diff --git a/.gitignore b/.gitignore index 35a8cbc..a588c01 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ SOURCES/RHEV-Application-Provisioning-Tool.exe_4.12 -SOURCES/libguestfs-1.36.3.tar.gz +SOURCES/libguestfs-1.36.10.tar.gz SOURCES/libguestfs.keyring SOURCES/rhsrvany.exe diff --git a/.libguestfs.metadata b/.libguestfs.metadata index c246969..e7d2b1b 100644 --- a/.libguestfs.metadata +++ b/.libguestfs.metadata @@ -1,4 +1,4 @@ 8fec32284530ce6d485629fcbd1f7f3e005ae8a0 SOURCES/RHEV-Application-Provisioning-Tool.exe_4.12 -269b49a6e6fcbc7beb287b27829cacbc35d4882b SOURCES/libguestfs-1.36.3.tar.gz +93c94f8c614af17078b345ea3f5f5a187194cace SOURCES/libguestfs-1.36.10.tar.gz 1bbc40f501a7fef9eef2a39b701a71aee2fea7c4 SOURCES/libguestfs.keyring 2bd96e478fc004cd323b5bd754c856641877dac6 SOURCES/rhsrvany.exe diff --git a/SOURCES/0001-RHEL-7-Remove-libguestfs-live-RHBZ-798980.patch b/SOURCES/0001-RHEL-7-Remove-libguestfs-live-RHBZ-798980.patch index 24af4ae..36203e1 100644 --- a/SOURCES/0001-RHEL-7-Remove-libguestfs-live-RHBZ-798980.patch +++ b/SOURCES/0001-RHEL-7-Remove-libguestfs-live-RHBZ-798980.patch @@ -1,4 +1,4 @@ -From c1b189f662e4dccce0c3ef72a458f5eba298e949 Mon Sep 17 00:00:00 2001 +From a237b1b342e1fa7d6b0229fd9b58dad21fd07877 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 21 Dec 2012 15:50:11 +0000 Subject: [PATCH] RHEL 7: Remove libguestfs live (RHBZ#798980). @@ -34,5 +34,5 @@ index 8ce4ca5b4..9be2b9c5f 100644 static int -- -2.13.4 +2.14.3 diff --git a/SOURCES/0002-RHEL-7-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch b/SOURCES/0002-RHEL-7-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch index 6e565ff..23a11a9 100644 --- a/SOURCES/0002-RHEL-7-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch +++ b/SOURCES/0002-RHEL-7-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch @@ -1,4 +1,4 @@ -From ee68d9b7941ced89bc91878f09eb528773e624db Mon Sep 17 00:00:00 2001 +From 5cb76a0fdc42cecd218b905acfd4d3ce07faf748 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 18 Jul 2013 18:31:53 +0100 Subject: [PATCH] RHEL 7: Remove 9p APIs from RHEL (RHBZ#921710). @@ -16,7 +16,7 @@ Subject: [PATCH] RHEL 7: Remove 9p APIs from RHEL (RHBZ#921710). delete mode 100644 daemon/9p.c diff --git a/Makefile.am b/Makefile.am -index 12486deee..14b277a35 100644 +index 494892206..ffe002837 100644 --- a/Makefile.am +++ b/Makefile.am @@ -73,7 +73,7 @@ SUBDIRS += tests/xfs @@ -30,7 +30,7 @@ index 12486deee..14b277a35 100644 SUBDIRS += tests/disk-labels diff --git a/daemon/9p.c b/daemon/9p.c deleted file mode 100644 -index bd564a5be..000000000 +index fc5b01736..000000000 --- a/daemon/9p.c +++ /dev/null @@ -1,225 +0,0 @@ @@ -216,7 +216,7 @@ index bd564a5be..000000000 - struct stat statbuf; - int r; - -- ABS_PATH (mountpoint, , return -1); +- ABS_PATH (mountpoint, 0, return -1); - - mp = sysroot_path (mountpoint); - if (!mp) { @@ -260,10 +260,10 @@ index bd564a5be..000000000 - return 0; -} diff --git a/daemon/Makefile.am b/daemon/Makefile.am -index 9381742c8..0670cda90 100644 +index 31414653f..7aeaf7b8d 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am -@@ -48,7 +48,6 @@ endif +@@ -49,7 +49,6 @@ endif guestfsd_SOURCES = \ ../common/errnostring/errnostring.h \ ../common/protocol/guestfs_protocol.h \ @@ -272,7 +272,7 @@ index 9381742c8..0670cda90 100644 actions.h \ available.c \ diff --git a/docs/C_SOURCE_FILES b/docs/C_SOURCE_FILES -index 26abcc9bb..608eaea76 100644 +index f54015de0..d7fa51cf6 100644 --- a/docs/C_SOURCE_FILES +++ b/docs/C_SOURCE_FILES @@ -49,7 +49,6 @@ common/windows/windows.h @@ -284,13 +284,14 @@ index 26abcc9bb..608eaea76 100644 daemon/actions.h daemon/augeas.c diff --git a/generator/actions_core.ml b/generator/actions_core.ml -index ed89f74aa..2567981d7 100644 +index 5e487df02..dc54d616a 100644 --- a/generator/actions_core.ml +++ b/generator/actions_core.ml -@@ -6372,27 +6372,6 @@ This returns true iff the device exists and contains all zero bytes. +@@ -6371,27 +6371,6 @@ This returns true iff the device exists and contains all zero bytes. + Note that for large devices this can take a long time to run." }; - { defaults with +- { defaults with - name = "list_9p"; added = (1, 11, 12); - style = RStringList "mounttags", [], []; - shortdesc = "list 9p filesystems"; @@ -311,10 +312,9 @@ index ed89f74aa..2567981d7 100644 -Any other options required can be passed in the optional C -parameter." }; - -- { defaults with + { defaults with name = "list_dm_devices"; added = (1, 11, 15); style = RStringList "devices", [], []; - shortdesc = "list device mapper devices"; diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml index b3be31996..7f92e0427 100644 --- a/generator/proc_nr.ml @@ -349,7 +349,7 @@ index 8fa8599d3..7a5272684 100644 src/optargs-ntfsclone_out.c \ src/optargs-ntfsfix.c \ diff --git a/po/POTFILES b/po/POTFILES -index 904e751de..143d1cd9d 100644 +index 447b2a1e3..2856b36a3 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -39,7 +39,6 @@ customize/crypt-c.c @@ -369,5 +369,5 @@ index 904e751de..143d1cd9d 100644 gobject/src/optargs-ntfsclone_out.c gobject/src/optargs-ntfsfix.c -- -2.13.4 +2.14.3 diff --git a/SOURCES/0003-RHEL-7-Disable-unsupported-remote-drive-protocols-RH.patch b/SOURCES/0003-RHEL-7-Disable-unsupported-remote-drive-protocols-RH.patch index 26bb7ee..43b43a8 100644 --- a/SOURCES/0003-RHEL-7-Disable-unsupported-remote-drive-protocols-RH.patch +++ b/SOURCES/0003-RHEL-7-Disable-unsupported-remote-drive-protocols-RH.patch @@ -1,4 +1,4 @@ -From a000794c30a6c6603f000d39b6674bfb3be26037 Mon Sep 17 00:00:00 2001 +From 0b0b38041f963b36be1d2e38a7cd7743cece0722 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Mon, 29 Jul 2013 14:47:56 +0100 Subject: [PATCH] RHEL 7: Disable unsupported remote drive protocols @@ -23,14 +23,14 @@ We hope to gradually add some of these back over the lifetime of RHEL 7. In RHEL 7.2: rbd (Ceph) support was enabled. --- docs/guestfs-testing.pod | 20 ------- - fish/guestfish.pod | 64 ++------------------- + fish/guestfish.pod | 66 ++-------------------- fish/test-add-uri.sh | 32 ----------- generator/actions_core.ml | 50 +---------------- lib/drives.c | 8 +++ lib/guestfs.pod | 100 --------------------------------- tests/disks/test-qemu-drive-libvirt.sh | 28 --------- tests/disks/test-qemu-drive.sh | 60 -------------------- - 8 files changed, 15 insertions(+), 347 deletions(-) + 8 files changed, 16 insertions(+), 348 deletions(-) diff --git a/docs/guestfs-testing.pod b/docs/guestfs-testing.pod index 1e88ed4df..ce64755db 100644 @@ -64,7 +64,7 @@ index 1e88ed4df..ce64755db 100644 Run L on guests or disk images: diff --git a/fish/guestfish.pod b/fish/guestfish.pod -index 3b71c3a21..cbaaca516 100644 +index feaae7f8c..a9fc8d2df 100644 --- a/fish/guestfish.pod +++ b/fish/guestfish.pod @@ -131,9 +131,9 @@ To list what is available do: @@ -135,7 +135,7 @@ index 3b71c3a21..cbaaca516 100644 =head2 B<-a nbd://example.com[:port]> =head2 B<-a nbd://example.com[:port]/exportname> -@@ -1203,28 +1169,6 @@ The equivalent API command would be: +@@ -1203,35 +1169,13 @@ The equivalent API command would be: > add pool/disk protocol:rbd server:tcp:example.com:port @@ -161,9 +161,17 @@ index 3b71c3a21..cbaaca516 100644 - - > add /disk protocol:ssh server:tcp:example.com [username:user] - - =head1 PROGRESS BARS + Note that the URIs follow the syntax of + L: in particular, there + are restrictions on the allowed characters for the various components + of the URI. Characters such as C<:>, C<@>, and C B be + percent-encoded: + +- $ guestfish -a ssh://user:pass%40word@example.com/disk.img ++ $ guestfish -a rbd://user:pass%40word@example.com[:port]/pool/disk + + In this case, the password is C. - Some (not all) long-running commands send progress notification diff --git a/fish/test-add-uri.sh b/fish/test-add-uri.sh index 756df997b..8f84fd31b 100755 --- a/fish/test-add-uri.sh @@ -214,7 +222,7 @@ index 756df997b..8f84fd31b 100755 rm test-add-uri.out rm test-add-uri.img diff --git a/generator/actions_core.ml b/generator/actions_core.ml -index 2567981d7..e4b2b8c4c 100644 +index dc54d616a..ee2539c09 100644 --- a/generator/actions_core.ml +++ b/generator/actions_core.ml @@ -522,29 +522,6 @@ F is interpreted as a local file or device. @@ -299,7 +307,7 @@ index 2567981d7..e4b2b8c4c 100644 example if using the libvirt backend and if the libvirt backend is configured to start the qemu appliance as a special user such as C. If in doubt, diff --git a/lib/drives.c b/lib/drives.c -index 4cf41cd9b..2d86ca88a 100644 +index 509522430..d3887c148 100644 --- a/lib/drives.c +++ b/lib/drives.c @@ -165,6 +165,7 @@ create_drive_non_file (guestfs_h *g, @@ -485,39 +493,39 @@ index e02cda6f8..41aa7ad83 100644 Libguestfs has APIs for inspecting an unknown disk image to find out diff --git a/tests/disks/test-qemu-drive-libvirt.sh b/tests/disks/test-qemu-drive-libvirt.sh -index a1a7b8906..aefd7cb4a 100755 +index 3520e8a83..7671afb4a 100755 --- a/tests/disks/test-qemu-drive-libvirt.sh +++ b/tests/disks/test-qemu-drive-libvirt.sh @@ -64,34 +64,6 @@ check_output - grep -sq -- '-drive file=rbd:abc-def/ghi-jkl:auth_supported=none,' "$DEBUG_QEMU_FILE" || fail + grep -sq -- '-drive file=rbd:abc-def/ghi-jkl:auth_supported=none,' "$DEBUG_QEMU_FILE" || fail ceph2 rm "$DEBUG_QEMU_FILE" -# Gluster. - -$guestfish -d gluster run ||: -check_output --grep -sq -- '-drive file=gluster://1.2.3.4:1234/volname/image,' "$DEBUG_QEMU_FILE" || fail +-grep -sq -- '-drive file=gluster://1.2.3.4:1234/volname/image,' "$DEBUG_QEMU_FILE" || fail gluster -rm "$DEBUG_QEMU_FILE" - -# iSCSI. - -$guestfish -d iscsi run ||: -check_output --grep -sq -- '-drive file=iscsi://1.2.3.4:1234/iqn.2003-01.org.linux-iscsi.fedora,' "$DEBUG_QEMU_FILE" || fail +-grep -sq -- '-drive file=iscsi://1.2.3.4:1234/iqn.2003-01.org.linux-iscsi.fedora' "$DEBUG_QEMU_FILE" || fail iscsi -rm "$DEBUG_QEMU_FILE" - -# NBD. - -$guestfish -d nbd run ||: -check_output --grep -sq -- '-drive file=nbd:1.2.3.4:1234,' "$DEBUG_QEMU_FILE" || fail +-grep -sq -- '-drive file=nbd:1.2.3.4:1234,' "$DEBUG_QEMU_FILE" || fail nbd -rm "$DEBUG_QEMU_FILE" - -# Sheepdog. - -$guestfish -d sheepdog run ||: -check_output --grep -sq -- '-drive file=sheepdog:volume,' "$DEBUG_QEMU_FILE" || fail +-grep -sq -- '-drive file=sheepdog:volume,' "$DEBUG_QEMU_FILE" || fail sheepdog -rm "$DEBUG_QEMU_FILE" - # Local, stored in a pool. @@ -599,5 +607,5 @@ index 19dd60a2f..583e031bd 100755 -grep -sq -- '-drive file=ssh://rich@example.com/disk.img,' "$DEBUG_QEMU_FILE" || fail -rm "$DEBUG_QEMU_FILE" -- -2.13.4 +2.14.3 diff --git a/SOURCES/0004-RHEL-7-Remove-User-Mode-Linux-RHBZ-1144197.patch b/SOURCES/0004-RHEL-7-Remove-User-Mode-Linux-RHBZ-1144197.patch index 4560d5a..f16ac1b 100644 --- a/SOURCES/0004-RHEL-7-Remove-User-Mode-Linux-RHBZ-1144197.patch +++ b/SOURCES/0004-RHEL-7-Remove-User-Mode-Linux-RHBZ-1144197.patch @@ -1,4 +1,4 @@ -From 07dfad456fb78bbb5c3c1342f45c48dff4db2c36 Mon Sep 17 00:00:00 2001 +From 30f46900825b5a48024220d651d12166e2d8fe92 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 19 Sep 2014 13:38:20 +0100 Subject: [PATCH] RHEL 7: Remove User-Mode Linux (RHBZ#1144197). @@ -9,7 +9,7 @@ This isn't supported in RHEL 7. 1 file changed, 13 insertions(+) diff --git a/lib/launch-uml.c b/lib/launch-uml.c -index c391af309..3033daa88 100644 +index 65745ff47..3b67f2598 100644 --- a/lib/launch-uml.c +++ b/lib/launch-uml.c @@ -44,7 +44,9 @@ struct backend_uml_data { @@ -22,7 +22,7 @@ index c391af309..3033daa88 100644 /* Run uml_mkcow to create a COW overlay. */ static char * -@@ -82,6 +84,7 @@ create_cow_overlay_uml (guestfs_h *g, void *datav, struct drive *drv) +@@ -81,6 +83,7 @@ create_cow_overlay_uml (guestfs_h *g, void *datav, struct drive *drv) return make_cow_overlay (g, drv->src.u.path); } @@ -30,7 +30,7 @@ index c391af309..3033daa88 100644 /* Test for features which are not supported by the UML backend. * Possibly some of these should just be warnings, not errors. */ -@@ -129,10 +132,17 @@ uml_supported (guestfs_h *g) +@@ -128,10 +131,17 @@ uml_supported (guestfs_h *g) return true; } @@ -48,7 +48,7 @@ index c391af309..3033daa88 100644 struct backend_uml_data *data = datav; CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (cmdline); int console_sock = -1, daemon_sock = -1; -@@ -486,8 +496,10 @@ launch_uml (guestfs_h *g, void *datav, const char *arg) +@@ -491,8 +501,10 @@ launch_uml (guestfs_h *g, void *datav, const char *arg) } g->state = CONFIG; return -1; @@ -59,7 +59,7 @@ index c391af309..3033daa88 100644 /* This is called from the forked subprocess just before vmlinux runs, * so it can just print the message straight to stderr, where it will * be picked up and funnelled through the usual appliance event API. -@@ -517,6 +529,7 @@ print_vmlinux_command_line (guestfs_h *g, char **argv) +@@ -522,6 +534,7 @@ print_vmlinux_command_line (guestfs_h *g, char **argv) fputc ('\n', stderr); } @@ -68,5 +68,5 @@ index c391af309..3033daa88 100644 static int shutdown_uml (guestfs_h *g, void *datav, int check_for_errors) -- -2.13.4 +2.14.3 diff --git a/SOURCES/0005-RHEL-7-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch b/SOURCES/0005-RHEL-7-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch index f339a3e..a40ac53 100644 --- a/SOURCES/0005-RHEL-7-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch +++ b/SOURCES/0005-RHEL-7-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch @@ -1,4 +1,4 @@ -From 9185b9edc455e72ae44abc98b98aaef79b0a7a69 Mon Sep 17 00:00:00 2001 +From a16c5c28835dab579f7ff0c782bff4706f5efc28 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Sun, 28 Sep 2014 19:14:43 +0100 Subject: [PATCH] RHEL 7: v2v: Select correct qemu binary for -o qemu mode @@ -29,5 +29,5 @@ index ccdda8ad4..19757e007 100644 let flag t k = assert (String.is_prefix k "-"); -- -2.13.4 +2.14.3 diff --git a/SOURCES/0006-RHEL-7-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch b/SOURCES/0006-RHEL-7-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch index d569485..749237d 100644 --- a/SOURCES/0006-RHEL-7-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch +++ b/SOURCES/0006-RHEL-7-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch @@ -1,4 +1,4 @@ -From d4f2cb392ed4b88b14f3c3f8e08b02b5f52a9430 Mon Sep 17 00:00:00 2001 +From ba16c33451e806c58601eceec54e4c7048f398bc Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 30 Sep 2014 10:50:27 +0100 Subject: [PATCH] RHEL 7: v2v: Disable the --qemu-boot option (RHBZ#1147313). @@ -14,7 +14,7 @@ qemu script. 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml -index c294e5778..9f02098c0 100644 +index c7c7437ec..5a1ea04f3 100644 --- a/v2v/cmdline.ml +++ b/v2v/cmdline.ml @@ -199,7 +199,6 @@ let parse_cmdline () = @@ -25,7 +25,7 @@ index c294e5778..9f02098c0 100644 [ L"root" ], Getopt.String ("ask|... ", set_root_choice), s_"How to choose root filesystem"; [ L"vdsm-compat" ], Getopt.Symbol ("0.10|1.1", ["0.10"; "1.1"], set_vdsm_compat), s_"Write qcow2 with compat=0.10|1.1"; [ L"vdsm-image-uuid" ], Getopt.String ("uuid", add_vdsm_image_uuid), s_"Output image UUID(s)"; -@@ -403,6 +402,8 @@ read the man page virt-v2v(1). +@@ -405,6 +404,8 @@ read the man page virt-v2v(1). | Some d when not (is_directory d) -> error (f_"-os %s: output directory does not exist or is not a directory") d | Some d -> d in @@ -35,7 +35,7 @@ index c294e5778..9f02098c0 100644 output_format, output_alloc diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index 838b5986f..79c742e3f 100644 +index 5d4ed9ae5..ff91e29b8 100644 --- a/v2v/virt-v2v.pod +++ b/v2v/virt-v2v.pod @@ -145,11 +145,6 @@ Since F contains the path(s) to the guest disk @@ -73,5 +73,5 @@ index 838b5986f..79c742e3f 100644 =item B<--quiet> -- -2.13.4 +2.14.3 diff --git a/SOURCES/0007-RHEL-7-Revert-tests-rsync-Skip-this-test-when-the-ba.patch b/SOURCES/0007-RHEL-7-Revert-tests-rsync-Skip-this-test-when-the-ba.patch index f43ed77..fb75f80 100644 --- a/SOURCES/0007-RHEL-7-Revert-tests-rsync-Skip-this-test-when-the-ba.patch +++ b/SOURCES/0007-RHEL-7-Revert-tests-rsync-Skip-this-test-when-the-ba.patch @@ -1,4 +1,4 @@ -From d40e0b93a58edc9c67184e0108731556bc44b46f Mon Sep 17 00:00:00 2001 +From 4706dff15716286461c0826da9f703dc1b49177d Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 2 Oct 2014 16:44:00 +0100 Subject: [PATCH] RHEL 7: Revert "tests: rsync: Skip this test when the backend @@ -70,5 +70,5 @@ index c6d98cfd1..246396276 100755 guestfish --network -N test-rsync.img=fs -m /dev/sda1 < Date: Thu, 2 Oct 2014 16:44:04 +0100 Subject: [PATCH] RHEL 7: Revert "appliance: Change example ping lines to ping @@ -10,10 +10,10 @@ This reverts commit 07c0926b588db5c86214917b609c2f477c817c0e. 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/appliance/init b/appliance/init -index 8a26e1a02..624e20fa6 100755 +index 59b5c4955..c6a269dd1 100755 --- a/appliance/init +++ b/appliance/init -@@ -154,7 +154,8 @@ if test "$guestfs_verbose" = 1 && test "$guestfs_boot_analysis" != 1; then +@@ -157,7 +157,8 @@ if test "$guestfs_verbose" = 1 && test "$guestfs_boot_analysis" != 1; then date echo -n "clocksource: " cat /sys/devices/system/clocksource/clocksource0/current_clocksource @@ -24,5 +24,5 @@ index 8a26e1a02..624e20fa6 100755 echo -n "uptime: "; cat /proc/uptime fi -- -2.13.4 +2.14.3 diff --git a/SOURCES/0009-RHEL-7-Revert-launch-libvirt-Use-qemu-bridge-helper-.patch b/SOURCES/0009-RHEL-7-Revert-launch-libvirt-Use-qemu-bridge-helper-.patch index ab14e8b..4ab9832 100644 --- a/SOURCES/0009-RHEL-7-Revert-launch-libvirt-Use-qemu-bridge-helper-.patch +++ b/SOURCES/0009-RHEL-7-Revert-launch-libvirt-Use-qemu-bridge-helper-.patch @@ -1,4 +1,4 @@ -From 706ec2c841cda0de58a52001b1567d2b72fdacdf Mon Sep 17 00:00:00 2001 +From 5a411a67cf166eb44b8f88858eabaa80d6a0d504 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 2 Oct 2014 16:44:07 +0100 Subject: [PATCH] RHEL 7: Revert "launch: libvirt: Use qemu-bridge-helper to @@ -32,7 +32,7 @@ index 41aa7ad83..6443e3bae 100644 I This is B and has a tendency to eat diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c -index 168bba6ac..bc5d4d215 100644 +index 4ddf9b87f..def9cfe07 100644 --- a/lib/launch-libvirt.c +++ b/lib/launch-libvirt.c @@ -115,7 +115,6 @@ struct backend_libvirt_data { @@ -43,7 +43,7 @@ index 168bba6ac..bc5d4d215 100644 char name[DOMAIN_NAME_LEN]; /* random name */ bool is_kvm; /* false = qemu, true = kvm (from capabilities)*/ struct version libvirt_version; /* libvirt version */ -@@ -436,12 +435,6 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri) +@@ -435,12 +434,6 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri) guestfs_get_backend_setting (g, "internal_libvirt_imagelabel"); data->selinux_norelabel_disks = guestfs_int_get_backend_setting_bool (g, "internal_libvirt_norelabel_disks"); @@ -56,7 +56,7 @@ index 168bba6ac..bc5d4d215 100644 guestfs_pop_error_handler (g); if (g->enable_network && check_bridge_exists (g, data->network_bridge) == -1) -@@ -1384,19 +1377,6 @@ construct_libvirt_xml_devices (guestfs_h *g, +@@ -1383,19 +1376,6 @@ construct_libvirt_xml_devices (guestfs_h *g, } end_element (); } end_element (); @@ -76,7 +76,7 @@ index 168bba6ac..bc5d4d215 100644 /* Libvirt adds some devices by default. Indicate to libvirt * that we don't want them. */ -@@ -1771,6 +1751,27 @@ construct_libvirt_xml_qemu_cmdline (guestfs_h *g, +@@ -1793,6 +1773,27 @@ construct_libvirt_xml_qemu_cmdline (guestfs_h *g, attribute ("value", tmpdir); } end_element (); @@ -104,7 +104,7 @@ index 168bba6ac..bc5d4d215 100644 /* The qemu command line arguments requested by the caller. */ for (hp = g->hv_params; hp; hp = hp->next) { start_element ("qemu:arg") { -@@ -2096,9 +2097,6 @@ shutdown_libvirt (guestfs_h *g, void *datav, int check_for_errors) +@@ -2118,9 +2119,6 @@ shutdown_libvirt (guestfs_h *g, void *datav, int check_for_errors) free (data->selinux_imagelabel); data->selinux_imagelabel = NULL; @@ -115,5 +115,5 @@ index 168bba6ac..bc5d4d215 100644 free (data->secrets[i].secret); free (data->secrets); -- -2.13.4 +2.14.3 diff --git a/SOURCES/0010-RHEL-7-Revert-launch-libvirt-Better-error-when-bridg.patch b/SOURCES/0010-RHEL-7-Revert-launch-libvirt-Better-error-when-bridg.patch index 66b876a..85929df 100644 --- a/SOURCES/0010-RHEL-7-Revert-launch-libvirt-Better-error-when-bridg.patch +++ b/SOURCES/0010-RHEL-7-Revert-launch-libvirt-Better-error-when-bridg.patch @@ -1,4 +1,4 @@ -From 39c453f02083fa1b17a826a3b44b3405b601d792 Mon Sep 17 00:00:00 2001 +From f725f168ec3019da2332e5cae91a518a7897f8ff Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Mon, 21 Sep 2015 12:38:50 -0400 Subject: [PATCH] RHEL 7: Revert "launch: libvirt: Better error when bridge / @@ -10,7 +10,7 @@ This reverts commit edcd02a965ae6675c0ee9ecd8d98a1a641c6ef60. 1 file changed, 47 deletions(-) diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c -index bc5d4d215..0c2879dbf 100644 +index def9cfe07..681281b9b 100644 --- a/lib/launch-libvirt.c +++ b/lib/launch-libvirt.c @@ -155,7 +155,6 @@ static int is_blk (const char *path); @@ -21,7 +21,7 @@ index bc5d4d215..0c2879dbf 100644 #if HAVE_LIBSELINUX static void selinux_warning (guestfs_h *g, const char *func, const char *selinux_op, const char *data); -@@ -437,9 +436,6 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri) +@@ -436,9 +435,6 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri) guestfs_int_get_backend_setting_bool (g, "internal_libvirt_norelabel_disks"); guestfs_pop_error_handler (g); @@ -31,7 +31,7 @@ index bc5d4d215..0c2879dbf 100644 /* Locate and/or build the appliance. */ TRACE0 (launch_build_libvirt_appliance_start); -@@ -2009,49 +2005,6 @@ is_blk (const char *path) +@@ -2031,49 +2027,6 @@ is_blk (const char *path) return S_ISBLK (statbuf.st_mode); } @@ -82,5 +82,5 @@ index bc5d4d215..0c2879dbf 100644 ignore_errors (void *ignore, virErrorPtr ignore2) { -- -2.13.4 +2.14.3 diff --git a/SOURCES/0011-RHEL-7-Revert-appliance-add-dhcp-client-on-Mageia.patch b/SOURCES/0011-RHEL-7-Revert-appliance-add-dhcp-client-on-Mageia.patch index c41dea0..105081b 100644 --- a/SOURCES/0011-RHEL-7-Revert-appliance-add-dhcp-client-on-Mageia.patch +++ b/SOURCES/0011-RHEL-7-Revert-appliance-add-dhcp-client-on-Mageia.patch @@ -1,4 +1,4 @@ -From 8d2911ce34aca7ba67c9921fb8cb9207e2215fa8 Mon Sep 17 00:00:00 2001 +From 88dc95888f15c353581d0e9779d654935d9e820b Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 10 Oct 2014 17:45:39 +0100 Subject: [PATCH] RHEL 7: Revert "appliance: add dhcp-client on Mageia" @@ -9,10 +9,10 @@ This reverts commit 8f3a2ca5358d5601be7a9247b6d08193c4e2da46. 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appliance/packagelist.in b/appliance/packagelist.in -index 8ed3afedc..0477bfc55 100644 +index a2f6107b8..8a71f6e98 100644 --- a/appliance/packagelist.in +++ b/appliance/packagelist.in -@@ -188,7 +188,7 @@ ifelse(MAGEIA,1, +@@ -189,7 +189,7 @@ ifelse(MAGEIA,1, chkconfig /* for /etc/init.d */ cdrkit-genisoimage cdrkit-isotools @@ -22,5 +22,5 @@ index 8ed3afedc..0477bfc55 100644 gfs2-utils grub -- -2.13.4 +2.14.3 diff --git a/SOURCES/0012-RHEL-7-Revert-appliance-add-dhcpcd-and-gptfdisk-on-A.patch b/SOURCES/0012-RHEL-7-Revert-appliance-add-dhcpcd-and-gptfdisk-on-A.patch index 9445d49..50f5a2c 100644 --- a/SOURCES/0012-RHEL-7-Revert-appliance-add-dhcpcd-and-gptfdisk-on-A.patch +++ b/SOURCES/0012-RHEL-7-Revert-appliance-add-dhcpcd-and-gptfdisk-on-A.patch @@ -1,4 +1,4 @@ -From b70a988f7ecc6c446d88c1172332fe7c3c74dec3 Mon Sep 17 00:00:00 2001 +From b7640b6a60366d615f2b7bd24ed923a3c6c2eddb Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 10 Oct 2014 17:45:48 +0100 Subject: [PATCH] RHEL 7: Revert "appliance: add dhcpcd and gptfdisk on @@ -10,7 +10,7 @@ This reverts commit 979e7a49147f4ef1387337db262bf7ea12f627e3. 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/appliance/packagelist.in b/appliance/packagelist.in -index 0477bfc55..961a2a3b1 100644 +index 8a71f6e98..e088ace30 100644 --- a/appliance/packagelist.in +++ b/appliance/packagelist.in @@ -105,8 +105,7 @@ ifelse(ARCHLINUX,1, @@ -24,5 +24,5 @@ index 0477bfc55..961a2a3b1 100644 hivex iproute2 -- -2.13.4 +2.14.3 diff --git a/SOURCES/0013-RHEL-7-Revert-appliance-Use-dhclient-or-dhcpcd-inste.patch b/SOURCES/0013-RHEL-7-Revert-appliance-Use-dhclient-or-dhcpcd-inste.patch index e378ecd..5e69636 100644 --- a/SOURCES/0013-RHEL-7-Revert-appliance-Use-dhclient-or-dhcpcd-inste.patch +++ b/SOURCES/0013-RHEL-7-Revert-appliance-Use-dhclient-or-dhcpcd-inste.patch @@ -1,4 +1,4 @@ -From 1b565df653cff8421e7af40728e27c79d563d474 Mon Sep 17 00:00:00 2001 +From 169f16907f701d7d6eaf157eff0141bdf3632760 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 10 Oct 2014 17:46:02 +0100 Subject: [PATCH] RHEL 7: Revert "appliance: Use dhclient or dhcpcd instead of @@ -11,10 +11,10 @@ This reverts commit 67e6f32a240c7c234e6af637c1cd324b36a82cd3. 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/appliance/init b/appliance/init -index 624e20fa6..2e18be4fe 100755 +index c6a269dd1..2c9aecd5f 100755 --- a/appliance/init +++ b/appliance/init -@@ -118,15 +118,12 @@ shopt -u nullglob +@@ -120,15 +120,12 @@ shopt -u nullglob ip addr add 127.0.0.1/8 brd + dev lo scope host ip link set dev lo up @@ -37,7 +37,7 @@ index 624e20fa6..2e18be4fe 100755 # Scan for MDs. mdadm -As --auto=yes --run diff --git a/appliance/packagelist.in b/appliance/packagelist.in -index 961a2a3b1..b437b02e0 100644 +index e088ace30..8019af158 100644 --- a/appliance/packagelist.in +++ b/appliance/packagelist.in @@ -26,7 +26,6 @@ ifelse(REDHAT,1, @@ -64,16 +64,16 @@ index 961a2a3b1..b437b02e0 100644 grub hivex iproute2 -@@ -133,8 +130,6 @@ ifelse(SUSE,1, - augeas-lenses +@@ -134,8 +131,6 @@ ifelse(SUSE,1, btrfsprogs + cdrkit-cdrtools-compat cryptsetup - dhcpcd - dhcp-client genisoimage glibc-locale gptfdisk -@@ -160,7 +155,6 @@ ifelse(FRUGALWARE,1, +@@ -161,7 +156,6 @@ ifelse(FRUGALWARE,1, augeas cryptsetup-luks cdrkit @@ -81,7 +81,7 @@ index 961a2a3b1..b437b02e0 100644 grub2 hfsplus iproute2 -@@ -187,7 +181,6 @@ ifelse(MAGEIA,1, +@@ -188,7 +182,6 @@ ifelse(MAGEIA,1, chkconfig /* for /etc/init.d */ cdrkit-genisoimage cdrkit-isotools @@ -90,5 +90,5 @@ index 961a2a3b1..b437b02e0 100644 gfs2-utils grub -- -2.13.4 +2.14.3 diff --git a/SOURCES/0014-RHEL-7-Disable-alternate-Augeas-lenses.patch b/SOURCES/0014-RHEL-7-Disable-alternate-Augeas-lenses.patch index f19674b..be866fb 100644 --- a/SOURCES/0014-RHEL-7-Disable-alternate-Augeas-lenses.patch +++ b/SOURCES/0014-RHEL-7-Disable-alternate-Augeas-lenses.patch @@ -1,4 +1,4 @@ -From 08a8b9cf677d1c21890e14fcb34f49bf0800e912 Mon Sep 17 00:00:00 2001 +From 060fa25dd5046c3b6cea8c0d2c55ac9607042e9c Mon Sep 17 00:00:00 2001 From: Pino Toscano Date: Fri, 24 Oct 2014 16:33:50 +0100 Subject: [PATCH] RHEL 7: Disable alternate Augeas lenses. @@ -9,20 +9,18 @@ not required in RHEL. See: https://www.redhat.com/archives/libguestfs/2014-October/msg00220.html --- - appliance/Makefile.am | 2 -- + appliance/Makefile.am | 1 - daemon/augeas.c | 5 ++++- - daemon/lvm-filter.c | 4 ++-- - 3 files changed, 6 insertions(+), 5 deletions(-) + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/appliance/Makefile.am b/appliance/Makefile.am -index 05b9d42e9..1e142cbd0 100644 +index 42896b9a7..6cc147a18 100644 --- a/appliance/Makefile.am +++ b/appliance/Makefile.am -@@ -92,8 +92,6 @@ supermin.d/daemon.tar.gz: ../daemon/guestfsd guestfs_lvm_conf.aug guestfs_shadow +@@ -91,7 +91,6 @@ supermin.d/daemon.tar.gz: ../daemon/guestfsd guestfs_shadow.aug rm -rf tmp-d mkdir -p tmp-d$(DAEMON_SUPERMIN_DIR) tmp-d/etc tmp-d/usr/share/guestfs ln ../daemon/guestfsd tmp-d$(DAEMON_SUPERMIN_DIR)/guestfsd -- ln $(srcdir)/guestfs_lvm_conf.aug tmp-d/usr/share/guestfs/guestfs_lvm_conf.aug - ln $(srcdir)/guestfs_shadow.aug tmp-d/usr/share/guestfs/guestfs_shadow.aug ( cd tmp-d && tar zcf - * ) > $@-t rm -r tmp-d @@ -57,28 +55,6 @@ index 5adc959a5..dc5266ee4 100644 return 0; } -diff --git a/daemon/lvm-filter.c b/daemon/lvm-filter.c -index 5c9ce1866..bd32626e6 100644 ---- a/daemon/lvm-filter.c -+++ b/daemon/lvm-filter.c -@@ -140,7 +140,7 @@ set_filter (char *const *filters) - * but do that only after having applied the transformation. - */ - const int flags = AUG_NO_ERR_CLOSE | AUG_NO_LOAD; -- aug = aug_init (lvm_system_dir, "/usr/share/guestfs/", flags); -+ aug = aug_init (lvm_system_dir, NULL, flags); - if (!aug) { - reply_with_error ("augeas initialization failed"); - return -1; -@@ -151,7 +151,7 @@ set_filter (char *const *filters) - return -1; - } - -- r = aug_transform (aug, "guestfs_lvm_conf", "/lvm/lvm.conf", -+ r = aug_transform (aug, "lvm", "/lvm/lvm.conf", - 0 /* = included */); - if (r == -1) { - AUGEAS_ERROR ("aug_transform"); -- -2.13.4 +2.14.3 diff --git a/SOURCES/0015-RHEL-7-Fix-list-of-supported-sound-cards-to-match-RH.patch b/SOURCES/0015-RHEL-7-Fix-list-of-supported-sound-cards-to-match-RH.patch index 9ef5daf..656fd9f 100644 --- a/SOURCES/0015-RHEL-7-Fix-list-of-supported-sound-cards-to-match-RH.patch +++ b/SOURCES/0015-RHEL-7-Fix-list-of-supported-sound-cards-to-match-RH.patch @@ -1,4 +1,4 @@ -From 53e3905783593eaa4a06ea3ee416e9dc1da3a60a Mon Sep 17 00:00:00 2001 +From fcc0b3562ac001eaa93d216dcdf567108d96b8b8 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 24 Apr 2015 09:45:41 -0400 Subject: [PATCH] RHEL 7: Fix list of supported sound cards to match RHEL qemu @@ -9,7 +9,7 @@ Subject: [PATCH] RHEL 7: Fix list of supported sound cards to match RHEL qemu 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/v2v/utils.ml b/v2v/utils.ml -index e53f9fe0a..8f1053ec9 100644 +index 56a35c7b9..d72dc3477 100644 --- a/v2v/utils.ml +++ b/v2v/utils.ml @@ -40,13 +40,14 @@ let kvm_arch = function @@ -30,5 +30,5 @@ index e53f9fe0a..8f1053ec9 100644 (* Find the UEFI firmware. *) let find_uefi_firmware guest_arch = -- -2.13.4 +2.14.3 diff --git a/SOURCES/0016-RHEL-7-v2v-efi-Remove-references-to-Fedora-kraxel-s-.patch b/SOURCES/0016-RHEL-7-v2v-efi-Remove-references-to-Fedora-kraxel-s-.patch index 930b2a5..cb3e179 100644 --- a/SOURCES/0016-RHEL-7-v2v-efi-Remove-references-to-Fedora-kraxel-s-.patch +++ b/SOURCES/0016-RHEL-7-v2v-efi-Remove-references-to-Fedora-kraxel-s-.patch @@ -1,4 +1,4 @@ -From 8fb7f81181a566fac5ee572ee630946294f735ff Mon Sep 17 00:00:00 2001 +From 6e6a8a32ab3c3ff33897a6883632a8887c7b508e Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 30 Apr 2015 17:20:26 -0400 Subject: [PATCH] RHEL 7: v2v: efi: Remove references to Fedora / kraxel's OVMF @@ -6,8 +6,8 @@ Subject: [PATCH] RHEL 7: v2v: efi: Remove references to Fedora / kraxel's OVMF --- generator/UEFI.ml | 6 ------ - v2v/utils.ml | 3 +-- - 2 files changed, 1 insertion(+), 8 deletions(-) + v2v/utils.ml | 1 - + 2 files changed, 7 deletions(-) diff --git a/generator/UEFI.ml b/generator/UEFI.ml index 95797aad9..881009cfb 100644 @@ -27,7 +27,7 @@ index 95797aad9..881009cfb 100644 "/usr/share/OVMF/OVMF_CODE.fd", None, diff --git a/v2v/utils.ml b/v2v/utils.ml -index 8f1053ec9..212c8a0a0 100644 +index d72dc3477..2061eea61 100644 --- a/v2v/utils.ml +++ b/v2v/utils.ml @@ -54,7 +54,6 @@ let find_uefi_firmware guest_arch = @@ -38,15 +38,6 @@ index 8f1053ec9..212c8a0a0 100644 | "x86_64" -> Uefi.uefi_x86_64_firmware | "aarch64" -> Uefi.uefi_aarch64_firmware | arch -> -@@ -62,7 +61,7 @@ let find_uefi_firmware guest_arch = - guest_arch in - let rec loop = function - | [] -> -- error (f_"cannot find firmware for UEFI guests.\n\nYou probably need to install OVMF, or Gerd's firmware repo (https://www.kraxel.org/repos/), or AAVMF (if using aarch64)") -+ error (f_"cannot find firmware for UEFI guests.\n\nYou probably need to install OVMF, or AAVMF (if using aarch64)") - | ({ Uefi.code = code; vars = vars_template } as ret) :: rest -> - if Sys.file_exists code && Sys.file_exists vars_template then ret - else loop rest -- -2.13.4 +2.14.3 diff --git a/SOURCES/0017-RHEL-7-Reject-use-of-libguestfs-winsupport-features-.patch b/SOURCES/0017-RHEL-7-Reject-use-of-libguestfs-winsupport-features-.patch index 399c924..92b2d72 100644 --- a/SOURCES/0017-RHEL-7-Reject-use-of-libguestfs-winsupport-features-.patch +++ b/SOURCES/0017-RHEL-7-Reject-use-of-libguestfs-winsupport-features-.patch @@ -1,4 +1,4 @@ -From 0c01f7c2c9acb1336d996df65acddb33c2dc0181 Mon Sep 17 00:00:00 2001 +From 7246417f3ba33616846d3c3f3ec097e1b9692de7 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 7 Jul 2015 09:28:03 -0400 Subject: [PATCH] RHEL 7: Reject use of libguestfs-winsupport features except @@ -43,5 +43,5 @@ index 606c89807..bba57c56f 100644 * as a progress bar hint. *) -- -2.13.4 +2.14.3 diff --git a/SOURCES/0018-RHEL-7-daemon-umount-all-Hack-to-avoid-umount-sysroo.patch b/SOURCES/0018-RHEL-7-daemon-umount-all-Hack-to-avoid-umount-sysroo.patch index 59dd738..c010fa4 100644 --- a/SOURCES/0018-RHEL-7-daemon-umount-all-Hack-to-avoid-umount-sysroo.patch +++ b/SOURCES/0018-RHEL-7-daemon-umount-all-Hack-to-avoid-umount-sysroo.patch @@ -1,4 +1,4 @@ -From 006717a7f2c939fd99154d0b7af6447c30ef7ec1 Mon Sep 17 00:00:00 2001 +From 5cd87d524afba59a3916f4c953a4e4b6bccf8c04 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 23 Jul 2015 18:15:36 -0400 Subject: [PATCH] RHEL 7: daemon: umount-all: Hack to avoid umount: /sysroot: @@ -13,7 +13,7 @@ https://bugzilla.redhat.com/show_bug.cgi?id=1246032 1 file changed, 5 insertions(+) diff --git a/daemon/mount.c b/daemon/mount.c -index f2aedfd11..14b24bff9 100644 +index 0ad9626a7..b44753441 100644 --- a/daemon/mount.c +++ b/daemon/mount.c @@ -28,6 +28,8 @@ @@ -36,5 +36,5 @@ index f2aedfd11..14b24bff9 100644 for (i = 0; i < mounts.size; ++i) { CLEANUP_FREE char *err = NULL; -- -2.13.4 +2.14.3 diff --git a/SOURCES/0019-RHEL-7-Fix-tests-for-libguestfs-winsupport-7.2.patch b/SOURCES/0019-RHEL-7-Fix-tests-for-libguestfs-winsupport-7.2.patch index 875a270..24c4f22 100644 --- a/SOURCES/0019-RHEL-7-Fix-tests-for-libguestfs-winsupport-7.2.patch +++ b/SOURCES/0019-RHEL-7-Fix-tests-for-libguestfs-winsupport-7.2.patch @@ -1,4 +1,4 @@ -From 93d34d8282b48c737fe2e1e749dfa916086b15c9 Mon Sep 17 00:00:00 2001 +From 00ff00aa5a5ce998bd3cfe0457ace9f783e2e3ae Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Sun, 30 Aug 2015 03:21:57 -0400 Subject: [PATCH] RHEL 7: Fix tests for libguestfs-winsupport 7.2. @@ -89,5 +89,5 @@ index f1da222a9..ff94fe39b 100755 # We also update the Registry several times, for firstboot, and (ONLY -- -2.13.4 +2.14.3 diff --git a/SOURCES/0020-RHEL-7-Revert-v2v-Add-a-support-matrix-to-the-manual.patch b/SOURCES/0020-RHEL-7-Revert-v2v-Add-a-support-matrix-to-the-manual.patch index 725e320..abba042 100644 --- a/SOURCES/0020-RHEL-7-Revert-v2v-Add-a-support-matrix-to-the-manual.patch +++ b/SOURCES/0020-RHEL-7-Revert-v2v-Add-a-support-matrix-to-the-manual.patch @@ -1,4 +1,4 @@ -From db662b2d47088d792bb158103719ac07dfc8e3e0 Mon Sep 17 00:00:00 2001 +From 6af2d1ad18bfd41491c3415be64712b0f842b920 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Mon, 21 Sep 2015 15:49:17 +0100 Subject: [PATCH] RHEL 7: Revert "v2v: Add a support matrix to the manual @@ -10,7 +10,7 @@ This reverts commit a03bffa15a5357d5d0244595caf99607be1ec3ab. 1 file changed, 97 deletions(-) diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index 79c742e3f..fca0a2a93 100644 +index ff91e29b8..5bef6ae8a 100644 --- a/v2v/virt-v2v.pod +++ b/v2v/virt-v2v.pod @@ -145,103 +145,6 @@ Since F contains the path(s) to the guest disk @@ -98,7 +98,7 @@ index 79c742e3f..fca0a2a93 100644 - -=item Ubuntu 10.04, 12.04, 14.04, 16.04, and up - --=item Windows XP to Windows 8.1 / Windows Server 2012 R2 +-=item Windows XP to Windows 10 / Windows Server 2016 - -We use Windows internal version numbers, see -L @@ -118,5 +118,5 @@ index 79c742e3f..fca0a2a93 100644 =over 4 -- -2.13.4 +2.14.3 diff --git a/SOURCES/0021-RHEL-7-All-qemu-kvm-in-RHEL-7-supports-discard-of-qc.patch b/SOURCES/0021-RHEL-7-All-qemu-kvm-in-RHEL-7-supports-discard-of-qc.patch index b01c0c2..eed5ec0 100644 --- a/SOURCES/0021-RHEL-7-All-qemu-kvm-in-RHEL-7-supports-discard-of-qc.patch +++ b/SOURCES/0021-RHEL-7-All-qemu-kvm-in-RHEL-7-supports-discard-of-qc.patch @@ -1,4 +1,4 @@ -From 1995428106fe0e14832e0b0d07e5b71740b193a4 Mon Sep 17 00:00:00 2001 +From ef6ad315f02830f04a467cd32be09e2b25ce3824 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Wed, 27 May 2015 10:03:00 -0400 Subject: [PATCH] RHEL 7: All qemu-kvm in RHEL 7 supports discard of qcow2 @@ -12,10 +12,10 @@ For rationale behind this, see: 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/qemu.c b/lib/qemu.c -index d60692f0d..6bb54b70d 100644 +index a5278129c..c9debe937 100644 --- a/lib/qemu.c +++ b/lib/qemu.c -@@ -610,10 +610,6 @@ guestfs_int_discard_possible (guestfs_h *g, struct drive *drv, +@@ -963,10 +963,6 @@ guestfs_int_discard_possible (guestfs_h *g, struct drive *drv, * discard option on -drive at all. */ bool qemu15 = guestfs_int_version_ge (qemu_version, 1, 5, 0); @@ -26,7 +26,7 @@ index d60692f0d..6bb54b70d 100644 if (!qemu15) NOT_SUPPORTED (g, false, -@@ -638,12 +634,8 @@ guestfs_int_discard_possible (guestfs_h *g, struct drive *drv, +@@ -991,12 +987,8 @@ guestfs_int_discard_possible (guestfs_h *g, struct drive *drv, } else if (STREQ (drv->src.format, "raw")) /* OK */ ; @@ -42,5 +42,5 @@ index d60692f0d..6bb54b70d 100644 /* It's possible in future other formats will support discard, but * currently (qemu 1.7) none of them do. -- -2.13.4 +2.14.3 diff --git a/SOURCES/0022-RHEL-7-tests-Disable-daemon-tests-that-require-the-u.patch b/SOURCES/0022-RHEL-7-tests-Disable-daemon-tests-that-require-the-u.patch index edf48ec..4bb5241 100644 --- a/SOURCES/0022-RHEL-7-tests-Disable-daemon-tests-that-require-the-u.patch +++ b/SOURCES/0022-RHEL-7-tests-Disable-daemon-tests-that-require-the-u.patch @@ -1,4 +1,4 @@ -From ec0693476e8459771fa74cb820b7f9f89a6ba915 Mon Sep 17 00:00:00 2001 +From 6af62afc2e3287b1c87908f300167aeffac6017a Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Mon, 21 Sep 2015 13:12:43 -0400 Subject: [PATCH] RHEL 7: tests: Disable daemon tests that require the 'unix' @@ -24,5 +24,5 @@ index 053cad3e1..0d723fee4 100644 TESTS_ENVIRONMENT = $(top_builddir)/run --test -- -2.13.4 +2.14.3 diff --git a/SOURCES/0023-RHEL-7-v2v-Disable-the-virt-v2v-in-place-option.patch b/SOURCES/0023-RHEL-7-v2v-Disable-the-virt-v2v-in-place-option.patch index 27e1379..89e3131 100644 --- a/SOURCES/0023-RHEL-7-v2v-Disable-the-virt-v2v-in-place-option.patch +++ b/SOURCES/0023-RHEL-7-v2v-Disable-the-virt-v2v-in-place-option.patch @@ -1,4 +1,4 @@ -From c299f3e835dd3480960df3ea941099a43f399b96 Mon Sep 17 00:00:00 2001 +From 56aa0b649b144e78e791e134ee33422c273a8f22 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 14 Jan 2016 11:53:42 -0500 Subject: [PATCH] RHEL 7: v2v: Disable the virt-v2v --in-place option. @@ -36,7 +36,7 @@ index 133a411bc..297406496 100644 test-v2v-networks-and-bridges-expected.xml \ test-v2v-networks-and-bridges.sh \ diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml -index 9f02098c0..9aecb5cd6 100644 +index 5a1ea04f3..3e3d5c312 100644 --- a/v2v/cmdline.ml +++ b/v2v/cmdline.ml @@ -179,7 +179,7 @@ let parse_cmdline () = @@ -48,7 +48,7 @@ index 9f02098c0..9aecb5cd6 100644 [ L"machine-readable" ], Getopt.Set machine_readable, s_"Make output machine readable"; [ S 'n'; L"network" ], Getopt.String ("in:out", add_network), s_"Map network 'in' to 'out'"; [ L"no-copy" ], Getopt.Clear do_copy, s_"Just write the metadata"; -@@ -333,6 +333,10 @@ read the man page virt-v2v(1). +@@ -335,6 +335,10 @@ read the man page virt-v2v(1). error (f_"expecting an OVA file name on the command line") in Input_ova.input_ova filename in @@ -184,7 +184,7 @@ index 6f7d78f39..000000000 -# Clean up. -rm -r $d diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index fca0a2a93..c45828b58 100644 +index 5bef6ae8a..1c866e773 100644 --- a/v2v/virt-v2v.pod +++ b/v2v/virt-v2v.pod @@ -15,8 +15,6 @@ virt-v2v - Convert a guest to use KVM @@ -227,7 +227,7 @@ index fca0a2a93..c45828b58 100644 =item B<--machine-readable> This option is used to make the output more machine friendly -@@ -1632,7 +1613,7 @@ Minimum free space: 10 MB +@@ -1657,7 +1638,7 @@ Minimum free space: 10 MB =head2 Minimum free space check in the host You must have sufficient free space in the host directory used to @@ -236,7 +236,7 @@ index fca0a2a93..c45828b58 100644 which directory this is, use: $ df -h "`guestfish get-cachedir`" -@@ -1750,31 +1731,6 @@ that instead. +@@ -1789,31 +1770,6 @@ that instead. @@ -269,5 +269,5 @@ index fca0a2a93..c45828b58 100644 The I<--machine-readable> option can be used to make the output more -- -2.13.4 +2.14.3 diff --git a/SOURCES/0024-RHEL-7-v2v-Remove-dcpath-option-RHBZ-1315237-RHBZ-14.patch b/SOURCES/0024-RHEL-7-v2v-Remove-dcpath-option-RHBZ-1315237-RHBZ-14.patch deleted file mode 100644 index 8d9744d..0000000 --- a/SOURCES/0024-RHEL-7-v2v-Remove-dcpath-option-RHBZ-1315237-RHBZ-14.patch +++ /dev/null @@ -1,63 +0,0 @@ -From c04a77d09ad5b0a5238681f6e2b9b485f44f1599 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 23 Jun 2016 10:38:47 -0400 -Subject: [PATCH] RHEL 7: v2v: Remove --dcpath option (RHBZ#1315237, - RHBZ#1429430) - -This is no longer required, since RHEL 7.3. ---- - v2v/cmdline.ml | 2 +- - v2v/test-v2v-docs.sh | 2 +- - v2v/virt-v2v.pod | 13 ------------- - 3 files changed, 2 insertions(+), 15 deletions(-) - -diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml -index 9aecb5cd6..a2f132b6c 100644 ---- a/v2v/cmdline.ml -+++ b/v2v/cmdline.ml -@@ -172,7 +172,7 @@ let parse_cmdline () = - [ S 'b'; L"bridge" ], Getopt.String ("in:out", add_bridge), s_"Map bridge 'in' to 'out'"; - [ L"compressed" ], Getopt.Set compressed, s_"Compress output file"; - [ L"dcpath"; L"dcPath" ], Getopt.String ("path", set_string_option_once "--dcpath" dcpath), -- s_"Override dcPath (for vCenter)"; -+ ""; - [ L"debug-overlay"; L"debug-overlays" ], Getopt.Set debug_overlays, s_"Save overlay files"; - [ S 'i' ], Getopt.String (i_options, set_input_mode), s_"Set input mode (default: libvirt)"; - [ M"ic" ], Getopt.String ("uri", set_string_option_once "-ic" input_conn), -diff --git a/v2v/test-v2v-docs.sh b/v2v/test-v2v-docs.sh -index c5d98de7f..02750faf3 100755 ---- a/v2v/test-v2v-docs.sh -+++ b/v2v/test-v2v-docs.sh -@@ -22,4 +22,4 @@ $TEST_FUNCTIONS - skip_if_skipped - - $top_srcdir/podcheck.pl virt-v2v.pod virt-v2v \ -- --ignore=--dcPath,--debug-overlay,--ic,--if,--in-place,--no-trim,--oa,--oc,--of,--on,--os,--vmtype -+ --ignore=--dcpath,--dcPath,--debug-overlay,--ic,--if,--in-place,--no-trim,--oa,--oc,--of,--on,--os,--vmtype -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index c45828b58..f4def737a 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -169,19 +169,6 @@ Write a compressed output file. This is only allowed if the output - format is qcow2 (see I<-of> below), and is equivalent to the I<-c> - option of L. - --=item B<--dcpath> Folder/Datacenter -- --B You don't need to use this parameter if you have --S 1.2.20>. -- --For VMware vCenter, override the C parameter used to --select the datacenter. Virt-v2v can usually calculate this from the --C URI, but if it gets it wrong, then you can override it using --this setting. Go to your vCenter web folder interface, eg. --C (I a trailing slash), --and examine the C parameter in the URLs that appear on this --page. -- - =item B<--debug-overlays> - - Save the overlay file(s) created during conversion. This option is --- -2.13.4 - diff --git a/SOURCES/0024-RHEL-7-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch b/SOURCES/0024-RHEL-7-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch new file mode 100644 index 0000000..3e457c0 --- /dev/null +++ b/SOURCES/0024-RHEL-7-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch @@ -0,0 +1,26 @@ +From f1905ec2781ed29bebbb2b6311d8c82261c09a88 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 2 Mar 2017 14:21:37 +0100 +Subject: [PATCH] RHEL 7: v2v: -i disk: force VNC as display (RHBZ#1372671) + +The SDL output mode is not supported in RHEL 7's qemu-kvm. +--- + v2v/input_disk.ml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/v2v/input_disk.ml b/v2v/input_disk.ml +index 27f855352..1f319a487 100644 +--- a/v2v/input_disk.ml ++++ b/v2v/input_disk.ml +@@ -83,7 +83,7 @@ class input_disk input_format disk = object + s_features = [ "acpi"; "apic"; "pae" ]; + s_firmware = UnknownFirmware; (* causes virt-v2v to autodetect *) + s_display = +- Some { s_display_type = Window; s_keymap = None; s_password = None; ++ Some { s_display_type = VNC; s_keymap = None; s_password = None; + s_listen = LNoListen; s_port = None }; + s_video = None; + s_sound = None; +-- +2.14.3 + diff --git a/SOURCES/0025-RHEL-7-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch b/SOURCES/0025-RHEL-7-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch new file mode 100644 index 0000000..57abe79 --- /dev/null +++ b/SOURCES/0025-RHEL-7-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch @@ -0,0 +1,27 @@ +From fa0f50b8a18a1265b3876de50fb720247e980ceb Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Wed, 8 Mar 2017 11:03:40 +0100 +Subject: [PATCH] RHEL 7: v2v: do not mention SUSE Xen hosts (RHBZ#1430203) + +They are not supported in RHEL 7. +--- + v2v/virt-v2v.pod | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index 1c866e773..709075fba 100644 +--- a/v2v/virt-v2v.pod ++++ b/v2v/virt-v2v.pod +@@ -1194,8 +1194,7 @@ Remove the F and F files. + + =head1 INPUT FROM XEN + +-Virt-v2v is able to import Xen guests from RHEL 5 Xen or SLES and +-openSUSE Xen hosts. ++Virt-v2v is able to import Xen guests from RHEL 5 Xen hosts. + + Virt-v2v uses libvirt for access to the remote Xen host, and therefore + the input mode should be I<-i libvirt>. As this is the default, you +-- +2.14.3 + diff --git a/SOURCES/0025-RHEL-7-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch b/SOURCES/0025-RHEL-7-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch deleted file mode 100644 index 1abb7fb..0000000 --- a/SOURCES/0025-RHEL-7-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch +++ /dev/null @@ -1,26 +0,0 @@ -From ba326a8e1e0258a4254d1304f3c7447e996e3dc4 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 2 Mar 2017 14:21:37 +0100 -Subject: [PATCH] RHEL 7: v2v: -i disk: force VNC as display (RHBZ#1372671) - -The SDL output mode is not supported in RHEL 7's qemu-kvm. ---- - v2v/input_disk.ml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/input_disk.ml b/v2v/input_disk.ml -index 27f855352..1f319a487 100644 ---- a/v2v/input_disk.ml -+++ b/v2v/input_disk.ml -@@ -83,7 +83,7 @@ class input_disk input_format disk = object - s_features = [ "acpi"; "apic"; "pae" ]; - s_firmware = UnknownFirmware; (* causes virt-v2v to autodetect *) - s_display = -- Some { s_display_type = Window; s_keymap = None; s_password = None; -+ Some { s_display_type = VNC; s_keymap = None; s_password = None; - s_listen = LNoListen; s_port = None }; - s_video = None; - s_sound = None; --- -2.13.4 - diff --git a/SOURCES/0026-RHEL-7-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch b/SOURCES/0026-RHEL-7-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch deleted file mode 100644 index 459fe6d..0000000 --- a/SOURCES/0026-RHEL-7-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 6a753511ad8624efd71529aae0644b84ca0336f6 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Wed, 8 Mar 2017 11:03:40 +0100 -Subject: [PATCH] RHEL 7: v2v: do not mention SUSE Xen hosts (RHBZ#1430203) - -They are not supported in RHEL 7. ---- - v2v/virt-v2v.pod | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index f4def737a..7ad674d43 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -1178,8 +1178,7 @@ Remove the F and F files. - - =head1 INPUT FROM XEN - --Virt-v2v is able to import Xen guests from RHEL 5 Xen or SLES and --openSUSE Xen hosts. -+Virt-v2v is able to import Xen guests from RHEL 5 Xen hosts. - - Virt-v2v uses libvirt for access to the remote Xen host, and therefore - the input mode should be I<-i libvirt>. As this is the default, you --- -2.13.4 - diff --git a/SOURCES/0026-sysprep-Remove-DHCP_HOSTNAME-from-ifcfg-files-RHBZ-1.patch b/SOURCES/0026-sysprep-Remove-DHCP_HOSTNAME-from-ifcfg-files-RHBZ-1.patch new file mode 100644 index 0000000..e92d14d --- /dev/null +++ b/SOURCES/0026-sysprep-Remove-DHCP_HOSTNAME-from-ifcfg-files-RHBZ-1.patch @@ -0,0 +1,42 @@ +From 563085e246220a3e7e88309f82d2edf71cd3db5a Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 28 Feb 2017 15:48:18 +0000 +Subject: [PATCH] sysprep: Remove DHCP_HOSTNAME= from ifcfg-* files + (RHBZ#1427529). + +(cherry picked from commit 0f99537cb69c88f7ceb6c69a9d9ae10baaaa3623) +--- + sysprep/sysprep_operation_net_hostname.ml | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/sysprep/sysprep_operation_net_hostname.ml b/sysprep/sysprep_operation_net_hostname.ml +index 3824d42ae..7284d630f 100644 +--- a/sysprep/sysprep_operation_net_hostname.ml ++++ b/sysprep/sysprep_operation_net_hostname.ml +@@ -30,10 +30,12 @@ let net_hostname_perform (g : Guestfs.guestfs) root side_effects = + let filenames = g#glob_expand "/etc/sysconfig/network-scripts/ifcfg-*" in + Array.iter ( + fun filename -> +- (* Replace HOSTNAME=... entry. *) ++ (* Remove HOSTNAME=... and DHCP_HOSTNAME=... entries. *) + let lines = Array.to_list (g#read_lines filename) in + let lines = List.filter ( +- fun line -> not (String.is_prefix line "HOSTNAME=") ++ fun line -> ++ not (String.is_prefix line "HOSTNAME=") && ++ not (String.is_prefix line "DHCP_HOSTNAME=") + ) lines in + let file = String.concat "\n" lines ^ "\n" in + g#write filename file; +@@ -46,7 +48,7 @@ let op = { + defaults with + name = "net-hostname"; + enabled_by_default = true; +- heading = s_"Remove HOSTNAME in network interface configuration"; ++ heading = s_"Remove HOSTNAME and DHCP_HOSTNAME in network interface configuration"; + pod_description = Some (s_"\ + For Fedora and Red Hat Enterprise Linux, + this is removed from C files."); +-- +2.14.3 + diff --git a/SOURCES/0027-p2v-Run-fewer-scp-commands.patch b/SOURCES/0027-p2v-Run-fewer-scp-commands.patch new file mode 100644 index 0000000..bcd0172 --- /dev/null +++ b/SOURCES/0027-p2v-Run-fewer-scp-commands.patch @@ -0,0 +1,134 @@ +From 847f9845085f76be8a00eba10fd995fe5e25ea21 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 30 Mar 2017 13:13:03 +0100 +Subject: [PATCH] p2v: Run fewer 'scp' commands. + +Each scp command takes a considerable amount of time -- several +seconds -- because it must set up, authenticate and tear down a new +connection. Avoid this by combining several copies into a single +command. + +We still have to use two scp commands because we want to check that +some files are copied and ignore failures in a second set of +informational files. + +(cherry picked from commit d178deeeb814471b9d70431626b6cd515a21d0c1) +--- + p2v/conversion.c | 31 +++++++++++-------------------- + p2v/p2v.h | 2 +- + p2v/ssh.c | 25 +++++++++++++++++++++---- + 3 files changed, 33 insertions(+), 25 deletions(-) + +diff --git a/p2v/conversion.c b/p2v/conversion.c +index 94a466640..27c6b2f2d 100644 +--- a/p2v/conversion.c ++++ b/p2v/conversion.c +@@ -366,28 +366,19 @@ start_conversion (struct config *config, + } + + /* Copy the static files to the remote dir. */ +- if (scp_file (config, name_file, remote_dir) == -1) { +- set_conversion_error ("scp: %s to %s: %s", +- name_file, remote_dir, get_ssh_error ()); ++ ++ /* These three files must not fail, so check for errors here. */ ++ if (scp_file (config, remote_dir, ++ name_file, libvirt_xml_file, wrapper_script, NULL) == -1) { ++ set_conversion_error ("scp: %s: %s", ++ remote_dir, get_ssh_error ()); + goto out; + } +- if (scp_file (config, libvirt_xml_file, remote_dir) == -1) { +- set_conversion_error ("scp: %s to %s: %s", +- libvirt_xml_file, remote_dir, get_ssh_error ()); +- goto out; +- } +- if (scp_file (config, wrapper_script, remote_dir) == -1) { +- set_conversion_error ("scp: %s to %s: %s", +- wrapper_script, remote_dir, get_ssh_error ()); +- goto out; +- } +- /* It's not essential that these files are copied. */ +- ignore_value (scp_file (config, dmesg_file, remote_dir)); +- ignore_value (scp_file (config, lscpu_file, remote_dir)); +- ignore_value (scp_file (config, lspci_file, remote_dir)); +- ignore_value (scp_file (config, lsscsi_file, remote_dir)); +- ignore_value (scp_file (config, lsusb_file, remote_dir)); +- ignore_value (scp_file (config, p2v_version_file, remote_dir)); ++ ++ /* It's not essential that these files are copied, so ignore errors. */ ++ ignore_value (scp_file (config, remote_dir, ++ dmesg_file, lscpu_file, lspci_file, lsscsi_file, ++ lsusb_file, p2v_version_file, NULL)); + + /* Do the conversion. This runs until virt-v2v exits. */ + if (notify_ui) +diff --git a/p2v/p2v.h b/p2v/p2v.h +index 5223aa216..b26648a01 100644 +--- a/p2v/p2v.h ++++ b/p2v/p2v.h +@@ -128,7 +128,7 @@ extern int test_connection (struct config *); + extern mexp_h *open_data_connection (struct config *, const char *local_ipaddr, int local_port, int *remote_port); + extern mexp_h *start_remote_connection (struct config *, const char *remote_dir); + extern const char *get_ssh_error (void); +-extern int scp_file (struct config *config, const char *localfile, const char *remotefile); ++extern int scp_file (struct config *config, const char *target, const char *local, ...) __attribute__((sentinel)); + + /* nbd.c */ + extern void set_nbd_option (const char *opt); +diff --git a/p2v/ssh.c b/p2v/ssh.c +index dfcab0e40..991888348 100644 +--- a/p2v/ssh.c ++++ b/p2v/ssh.c +@@ -572,14 +572,18 @@ start_ssh (unsigned spawn_flags, struct config *config, + #endif + + /** +- * Upload a file to remote using L. ++ * Upload file(s) to remote using L. ++ * ++ * Note that the target (directory or file) comes before the list of ++ * local files, because the list of local files is a varargs list. + * + * This is a simplified version of L above. + */ + int +-scp_file (struct config *config, const char *localfile, const char *remotefile) ++scp_file (struct config *config, const char *target, const char *local, ...) + { + size_t i = 0; ++ va_list args; + const size_t MAX_ARGS = 64; + const char *argv[MAX_ARGS]; + char port_str[64]; +@@ -618,12 +622,25 @@ scp_file (struct config *config, const char *localfile, const char *remotefile) + ADD_ARG (argv, i, "-i"); + ADD_ARG (argv, i, config->identity_file); + } +- ADD_ARG (argv, i, localfile); ++ ++ /* Source files or directories. ++ * Strictly speaking this could abort() if the list of files is ++ * too long, but that never happens in virt-p2v. XXX ++ */ ++ va_start (args, local); ++ do ADD_ARG (argv, i, local); ++ while ((local = va_arg (args, const char *)) != NULL); ++ va_end (args); ++ ++ /* The target file or directory. We need to rewrite this as ++ * "username@server:target". ++ */ + if (asprintf (&remote, "%s@%s:%s", + config->username ? config->username : "root", +- config->server, remotefile) == -1) ++ config->server, target) == -1) + error (EXIT_FAILURE, errno, "asprintf"); + ADD_ARG (argv, i, remote); ++ + ADD_ARG (argv, i, NULL); + + #if DEBUG_STDERR +-- +2.14.3 + diff --git a/SOURCES/0027-sysprep-Remove-DHCP_HOSTNAME-from-ifcfg-files-RHBZ-1.patch b/SOURCES/0027-sysprep-Remove-DHCP_HOSTNAME-from-ifcfg-files-RHBZ-1.patch deleted file mode 100644 index 8fc66d6..0000000 --- a/SOURCES/0027-sysprep-Remove-DHCP_HOSTNAME-from-ifcfg-files-RHBZ-1.patch +++ /dev/null @@ -1,42 +0,0 @@ -From db166d40204d854d852880c154ae55a18b6f8acf Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 28 Feb 2017 15:48:18 +0000 -Subject: [PATCH] sysprep: Remove DHCP_HOSTNAME= from ifcfg-* files - (RHBZ#1427529). - -(cherry picked from commit 0f99537cb69c88f7ceb6c69a9d9ae10baaaa3623) ---- - sysprep/sysprep_operation_net_hostname.ml | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/sysprep/sysprep_operation_net_hostname.ml b/sysprep/sysprep_operation_net_hostname.ml -index 3824d42ae..7284d630f 100644 ---- a/sysprep/sysprep_operation_net_hostname.ml -+++ b/sysprep/sysprep_operation_net_hostname.ml -@@ -30,10 +30,12 @@ let net_hostname_perform (g : Guestfs.guestfs) root side_effects = - let filenames = g#glob_expand "/etc/sysconfig/network-scripts/ifcfg-*" in - Array.iter ( - fun filename -> -- (* Replace HOSTNAME=... entry. *) -+ (* Remove HOSTNAME=... and DHCP_HOSTNAME=... entries. *) - let lines = Array.to_list (g#read_lines filename) in - let lines = List.filter ( -- fun line -> not (String.is_prefix line "HOSTNAME=") -+ fun line -> -+ not (String.is_prefix line "HOSTNAME=") && -+ not (String.is_prefix line "DHCP_HOSTNAME=") - ) lines in - let file = String.concat "\n" lines ^ "\n" in - g#write filename file; -@@ -46,7 +48,7 @@ let op = { - defaults with - name = "net-hostname"; - enabled_by_default = true; -- heading = s_"Remove HOSTNAME in network interface configuration"; -+ heading = s_"Remove HOSTNAME and DHCP_HOSTNAME in network interface configuration"; - pod_description = Some (s_"\ - For Fedora and Red Hat Enterprise Linux, - this is removed from C files."); --- -2.13.4 - diff --git a/SOURCES/0028-p2v-Fix-list-of-files-in-documentation.patch b/SOURCES/0028-p2v-Fix-list-of-files-in-documentation.patch new file mode 100644 index 0000000..a0b8b01 --- /dev/null +++ b/SOURCES/0028-p2v-Fix-list-of-files-in-documentation.patch @@ -0,0 +1,66 @@ +From 77faaa76368ecd4e758d0705a44c1afc25c95796 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 30 Mar 2017 14:45:47 +0100 +Subject: [PATCH] p2v: Fix list of files in documentation. + +(cherry picked from commit 38e7a1e038a91e34010ca0f89b0da077be821421) +--- + p2v/virt-p2v.pod | 28 +++++++++++++--------------- + 1 file changed, 13 insertions(+), 15 deletions(-) + +diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod +index ee870fdd9..7fd637152 100644 +--- a/p2v/virt-p2v.pod ++++ b/p2v/virt-p2v.pod +@@ -724,18 +724,6 @@ Into this directory are written various files which include: + + =item F + +-I<(before conversion)> +- +-The dmesg output from the physical machine. Useful for detecting +-problems such as missing device drivers or firmware on the virt-p2v +-ISO. +- +-=item F +- +-I<(before conversion)> +- +-The content of the environment where L will run. +- + =item F + + =item F +@@ -746,8 +734,18 @@ The content of the environment where L will run. + + I<(before conversion)> + +-The output of the corresponding commands (ie L etc) on the +-physical machine. Useful for debugging novel hardware configurations. ++The output of the corresponding commands (ie L, L ++etc) on the physical machine. ++ ++The dmesg output is useful for detecting problems such as missing ++device drivers or firmware on the virt-p2v ISO. The others are useful ++for debugging novel hardware configurations. ++ ++=item F ++ ++I<(before conversion)> ++ ++The content of the environment where L will run. + + =item F + +@@ -799,7 +797,7 @@ B log file in any bug reports or support tickets. + + =item F + +-I<(during/after conversion)> ++I<(before conversion)> + + This is the wrapper script which is used when running virt-v2v. For + interest only, do not attempt to run this script yourself. +-- +2.14.3 + diff --git a/SOURCES/0028-p2v-v2v-Ensure-the-full-version-is-always-available-.patch b/SOURCES/0028-p2v-v2v-Ensure-the-full-version-is-always-available-.patch deleted file mode 100644 index 251d7fb..0000000 --- a/SOURCES/0028-p2v-v2v-Ensure-the-full-version-is-always-available-.patch +++ /dev/null @@ -1,181 +0,0 @@ -From a1385efa3499d7668128c90e26790e08e61897de Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 28 Mar 2017 23:03:31 +0100 -Subject: [PATCH] p2v, v2v: Ensure the full version is always available in - several places. - -Ensure the full version of virt-v2v and virt-p2v is available in the -conversion log file, the only log file that we reliably get from users -and customers. "Full version" means the major, minor, release and -extra fields. The extra field is especially important as it contains -the downstream package release in Fedora, RHEL etc. - -This change saves the virt-p2v version as a comment in the -physical.xml file, which is included in full in the conversion log (by -virt-v2v). - -It also ensures that the initial virt-v2v debug message contains the -full version number including the 'extra' field. - - $ cat virt-v2v-conversion-log.txt - virt-v2v: libguestfs 1.37.7local,libvirt (x86_64) - ... - - -It also adds 'p2v-version' and 'v2v-version' files in the virt-p2v -debug directory. These are strictly superfluous but could be useful -for end users. - - $ cat p2v-version - virt-p2v 1.37.7local,libvirt - $ cat v2v-version - virt-v2v 1.37.7local,libvirt - -(cherry picked from commit 7cae10f0c11ebde643ec575f7f779aa1e7103d6b) ---- - p2v/conversion.c | 40 ++++++++++++++++++++++++++++++++++++---- - p2v/virt-p2v.pod | 8 ++++++++ - v2v/v2v.ml | 4 ++-- - 3 files changed, 46 insertions(+), 6 deletions(-) - -diff --git a/p2v/conversion.c b/p2v/conversion.c -index 0c17ef242..beda2b89b 100644 ---- a/p2v/conversion.c -+++ b/p2v/conversion.c -@@ -95,6 +95,7 @@ static void generate_libvirt_xml (struct config *, struct data_conn *, const cha - static void generate_wrapper_script (struct config *, const char *remote_dir, const char *filename); - static void generate_system_data (const char *dmesg_file, const char *lscpu_file, const char *lspci_file, const char *lsscsi_file, const char *lsusb_file); - static const char *map_interface_to_network (struct config *, const char *interface); -+static void generate_p2v_version_file (const char *p2v_version_file); - static void print_quoted (FILE *fp, const char *s); - - static char *conversion_error; -@@ -206,6 +207,7 @@ start_conversion (struct config *config, - char lspci_file[] = "/tmp/p2v.XXXXXX/lspci"; - char lsscsi_file[] = "/tmp/p2v.XXXXXX/lsscsi"; - char lsusb_file[] = "/tmp/p2v.XXXXXX/lsusb"; -+ char p2v_version_file[] = "/tmp/p2v.XXXXXX/p2v-version"; - int inhibit_fd = -1; - - #if DEBUG_STDERR -@@ -342,6 +344,7 @@ start_conversion (struct config *config, - memcpy (lspci_file, tmpdir, strlen (tmpdir)); - memcpy (lsscsi_file, tmpdir, strlen (tmpdir)); - memcpy (lsusb_file, tmpdir, strlen (tmpdir)); -+ memcpy (p2v_version_file, tmpdir, strlen (tmpdir)); - - /* Generate the static files. */ - generate_name (config, name_file); -@@ -349,6 +352,7 @@ start_conversion (struct config *config, - generate_wrapper_script (config, remote_dir, wrapper_script); - generate_system_data (dmesg_file, - lscpu_file, lspci_file, lsscsi_file, lsusb_file); -+ generate_p2v_version_file (p2v_version_file); - - /* Open the control connection. This also creates remote_dir. */ - if (notify_ui) -@@ -383,6 +387,7 @@ start_conversion (struct config *config, - ignore_value (scp_file (config, lspci_file, remote_dir)); - ignore_value (scp_file (config, lsscsi_file, remote_dir)); - ignore_value (scp_file (config, lsusb_file, remote_dir)); -+ ignore_value (scp_file (config, p2v_version_file, remote_dir)); - - /* Do the conversion. This runs until virt-v2v exits. */ - if (notify_ui) -@@ -546,10 +551,10 @@ cleanup_data_conns (struct data_conn *data_conns, size_t nr) - } while (0) - - /* An XML comment. */ --#define comment(str) \ -- do { \ -- if (xmlTextWriterWriteComment (xo, BAD_CAST (str)) == -1) \ -- error (EXIT_FAILURE, errno, "xmlTextWriterWriteComment"); \ -+#define comment(fs,...) \ -+ do { \ -+ if (xmlTextWriterWriteFormatComment (xo, fs, ##__VA_ARGS__) == -1) \ -+ error (EXIT_FAILURE, errno, "xmlTextWriterWriteFormatComment"); \ - } while (0) - - /** -@@ -579,6 +584,8 @@ generate_libvirt_xml (struct config *config, struct data_conn *data_conns, - - memkb = config->memory / 1024; - -+ comment (" %s %s ", getprogname (), PACKAGE_VERSION_FULL); -+ - comment - (" NOTE!\n" - "\n" -@@ -859,6 +866,13 @@ generate_wrapper_script (struct config *config, const char *remote_dir, - fprintf (fp, "\n"); - - fprintf (fp, -+ "# Log the version of virt-v2v (for information only).\n"); -+ if (config->sudo) -+ fprintf (fp, "sudo -n "); -+ fprintf (fp, "virt-v2v --version > v2v-version\n"); -+ fprintf (fp, "\n"); -+ -+ fprintf (fp, - "# Run virt-v2v. Send stdout back to virt-p2v. Send stdout\n" - "# and stderr (debugging info) to the log file.\n"); - fprintf (fp, "v2v 2>> $log | tee -a $log\n"); -@@ -939,3 +953,21 @@ generate_system_data (const char *dmesg_file, - - ignore_value (system (cmd)); - } -+ -+/** -+ * Generate a file containing the version of virt-p2v. -+ * -+ * The version of virt-v2v is contained in the conversion log. -+ */ -+static void -+generate_p2v_version_file (const char *p2v_version_file) -+{ -+ FILE *fp = fopen (p2v_version_file, "w"); -+ if (fp == NULL) { -+ perror (p2v_version_file); -+ return; /* non-fatal */ -+ } -+ fprintf (fp, "%s %s\n", -+ getprogname (), PACKAGE_VERSION_FULL); -+ fclose (fp); -+} -diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod -index 4a5f58724..ee870fdd9 100644 ---- a/p2v/virt-p2v.pod -+++ b/p2v/virt-p2v.pod -@@ -767,6 +767,14 @@ Note this is not "real" libvirt XML (and must B be loaded into - libvirt, which would reject it anyhow). Also it is not the same as - the libvirt XML which virt-v2v generates in certain output modes. - -+=item F -+ -+=item F -+ -+I<(before conversion)> -+ -+The versions of virt-p2v and virt-v2v respectively. -+ - =item F - - I<(after conversion)> -diff --git a/v2v/v2v.ml b/v2v/v2v.ml -index 551524dc5..cc7b88966 100644 ---- a/v2v/v2v.ml -+++ b/v2v/v2v.ml -@@ -42,8 +42,8 @@ let rec main () = - - (* Print the version, easier than asking users to tell us. *) - debug "%s: %s %s (%s)" -- prog Guestfs_config.package_name -- Guestfs_config.package_version Guestfs_config.host_cpu; -+ prog Guestfs_config.package_name Guestfs_config.package_version_full -+ Guestfs_config.host_cpu; - - (* Print the libvirt version if debugging. Note that if - * we're configured --without-libvirt, then this will throw --- -2.13.4 - diff --git a/SOURCES/0029-p2v-Run-fewer-scp-commands.patch b/SOURCES/0029-p2v-Run-fewer-scp-commands.patch deleted file mode 100644 index e714803..0000000 --- a/SOURCES/0029-p2v-Run-fewer-scp-commands.patch +++ /dev/null @@ -1,134 +0,0 @@ -From f047435a1087f438c645d729f68f6578e8cb861d Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 30 Mar 2017 13:13:03 +0100 -Subject: [PATCH] p2v: Run fewer 'scp' commands. - -Each scp command takes a considerable amount of time -- several -seconds -- because it must set up, authenticate and tear down a new -connection. Avoid this by combining several copies into a single -command. - -We still have to use two scp commands because we want to check that -some files are copied and ignore failures in a second set of -informational files. - -(cherry picked from commit d178deeeb814471b9d70431626b6cd515a21d0c1) ---- - p2v/conversion.c | 31 +++++++++++-------------------- - p2v/p2v.h | 2 +- - p2v/ssh.c | 25 +++++++++++++++++++++---- - 3 files changed, 33 insertions(+), 25 deletions(-) - -diff --git a/p2v/conversion.c b/p2v/conversion.c -index beda2b89b..0da9a62e0 100644 ---- a/p2v/conversion.c -+++ b/p2v/conversion.c -@@ -366,28 +366,19 @@ start_conversion (struct config *config, - } - - /* Copy the static files to the remote dir. */ -- if (scp_file (config, name_file, remote_dir) == -1) { -- set_conversion_error ("scp: %s to %s: %s", -- name_file, remote_dir, get_ssh_error ()); -+ -+ /* These three files must not fail, so check for errors here. */ -+ if (scp_file (config, remote_dir, -+ name_file, libvirt_xml_file, wrapper_script, NULL) == -1) { -+ set_conversion_error ("scp: %s: %s", -+ remote_dir, get_ssh_error ()); - goto out; - } -- if (scp_file (config, libvirt_xml_file, remote_dir) == -1) { -- set_conversion_error ("scp: %s to %s: %s", -- libvirt_xml_file, remote_dir, get_ssh_error ()); -- goto out; -- } -- if (scp_file (config, wrapper_script, remote_dir) == -1) { -- set_conversion_error ("scp: %s to %s: %s", -- wrapper_script, remote_dir, get_ssh_error ()); -- goto out; -- } -- /* It's not essential that these files are copied. */ -- ignore_value (scp_file (config, dmesg_file, remote_dir)); -- ignore_value (scp_file (config, lscpu_file, remote_dir)); -- ignore_value (scp_file (config, lspci_file, remote_dir)); -- ignore_value (scp_file (config, lsscsi_file, remote_dir)); -- ignore_value (scp_file (config, lsusb_file, remote_dir)); -- ignore_value (scp_file (config, p2v_version_file, remote_dir)); -+ -+ /* It's not essential that these files are copied, so ignore errors. */ -+ ignore_value (scp_file (config, remote_dir, -+ dmesg_file, lscpu_file, lspci_file, lsscsi_file, -+ lsusb_file, p2v_version_file, NULL)); - - /* Do the conversion. This runs until virt-v2v exits. */ - if (notify_ui) -diff --git a/p2v/p2v.h b/p2v/p2v.h -index 5223aa216..b26648a01 100644 ---- a/p2v/p2v.h -+++ b/p2v/p2v.h -@@ -128,7 +128,7 @@ extern int test_connection (struct config *); - extern mexp_h *open_data_connection (struct config *, const char *local_ipaddr, int local_port, int *remote_port); - extern mexp_h *start_remote_connection (struct config *, const char *remote_dir); - extern const char *get_ssh_error (void); --extern int scp_file (struct config *config, const char *localfile, const char *remotefile); -+extern int scp_file (struct config *config, const char *target, const char *local, ...) __attribute__((sentinel)); - - /* nbd.c */ - extern void set_nbd_option (const char *opt); -diff --git a/p2v/ssh.c b/p2v/ssh.c -index 8beaf74bb..bfeb80661 100644 ---- a/p2v/ssh.c -+++ b/p2v/ssh.c -@@ -572,14 +572,18 @@ start_ssh (unsigned spawn_flags, struct config *config, - #endif - - /** -- * Upload a file to remote using L. -+ * Upload file(s) to remote using L. -+ * -+ * Note that the target (directory or file) comes before the list of -+ * local files, because the list of local files is a varargs list. - * - * This is a simplified version of L above. - */ - int --scp_file (struct config *config, const char *localfile, const char *remotefile) -+scp_file (struct config *config, const char *target, const char *local, ...) - { - size_t i = 0; -+ va_list args; - const size_t MAX_ARGS = 64; - const char *argv[MAX_ARGS]; - char port_str[64]; -@@ -618,12 +622,25 @@ scp_file (struct config *config, const char *localfile, const char *remotefile) - ADD_ARG (argv, i, "-i"); - ADD_ARG (argv, i, config->identity_file); - } -- ADD_ARG (argv, i, localfile); -+ -+ /* Source files or directories. -+ * Strictly speaking this could abort() if the list of files is -+ * too long, but that never happens in virt-p2v. XXX -+ */ -+ va_start (args, local); -+ do ADD_ARG (argv, i, local); -+ while ((local = va_arg (args, const char *)) != NULL); -+ va_end (args); -+ -+ /* The target file or directory. We need to rewrite this as -+ * "username@server:target". -+ */ - if (asprintf (&remote, "%s@%s:%s", - config->username ? config->username : "root", -- config->server, remotefile) == -1) -+ config->server, target) == -1) - error (EXIT_FAILURE, errno, "asprintf"); - ADD_ARG (argv, i, remote); -+ - ADD_ARG (argv, i, NULL); - - #if DEBUG_STDERR --- -2.13.4 - diff --git a/SOURCES/0029-p2v-tests-Fix-fake-scp-command-so-it-can-handle-mult.patch b/SOURCES/0029-p2v-tests-Fix-fake-scp-command-so-it-can-handle-mult.patch new file mode 100644 index 0000000..17bd1cf --- /dev/null +++ b/SOURCES/0029-p2v-tests-Fix-fake-scp-command-so-it-can-handle-mult.patch @@ -0,0 +1,46 @@ +From f06fc3401bc88206502f6f876a553634c8acf220 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 30 Mar 2017 19:34:29 +0100 +Subject: [PATCH] p2v: tests: Fix fake scp command so it can handle multiple + local files. + +Fixes commit d178deeeb814471b9d70431626b6cd515a21d0c1. + +(cherry picked from commit b417c877f4ea848af8f8538957ab677c65637027) +--- + p2v/test-virt-p2v-scp.sh | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +diff --git a/p2v/test-virt-p2v-scp.sh b/p2v/test-virt-p2v-scp.sh +index c8a405db4..29900b663 100755 +--- a/p2v/test-virt-p2v-scp.sh ++++ b/p2v/test-virt-p2v-scp.sh +@@ -44,15 +44,19 @@ while true ; do + esac + done + +-# Hopefully there are two arguments left, the source (local) file +-# and a remote file of the form user@server:remote. +-if [ $# -ne 2 ]; then ++# Hopefully there are >= two arguments left, the source (local) ++# file(s) and a remote file of the form user@server:remote. ++if [ $# -lt 2 ]; then + echo "$0: incorrect number of arguments found:" "$@" + exit 1 + fi + +-local="$1" +-remote="$(echo $2 | awk -F: '{print $2}')" ++# https://stackoverflow.com/questions/1853946/getting-the-last-argument-passed-to-a-shell-script/1854031#1854031 ++remote="${@: -1}" ++# https://stackoverflow.com/questions/20398499/remove-last-argument-from-argument-list-of-shell-script-bash/26163980#26163980 ++set -- "${@:1:$(($#-1))}" ++ ++remote="$(echo $remote | awk -F: '{print $2}')" + + # Use the copy command. +-exec cp "$local" "$remote" ++exec cp "$@" "$remote" +-- +2.14.3 + diff --git a/SOURCES/0030-p2v-Fix-list-of-files-in-documentation.patch b/SOURCES/0030-p2v-Fix-list-of-files-in-documentation.patch deleted file mode 100644 index cf988af..0000000 --- a/SOURCES/0030-p2v-Fix-list-of-files-in-documentation.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 90ee2a3d8b55cf983d765c2c7666cad16e16250f Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 30 Mar 2017 14:45:47 +0100 -Subject: [PATCH] p2v: Fix list of files in documentation. - -(cherry picked from commit 38e7a1e038a91e34010ca0f89b0da077be821421) ---- - p2v/virt-p2v.pod | 28 +++++++++++++--------------- - 1 file changed, 13 insertions(+), 15 deletions(-) - -diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod -index ee870fdd9..7fd637152 100644 ---- a/p2v/virt-p2v.pod -+++ b/p2v/virt-p2v.pod -@@ -724,18 +724,6 @@ Into this directory are written various files which include: - - =item F - --I<(before conversion)> -- --The dmesg output from the physical machine. Useful for detecting --problems such as missing device drivers or firmware on the virt-p2v --ISO. -- --=item F -- --I<(before conversion)> -- --The content of the environment where L will run. -- - =item F - - =item F -@@ -746,8 +734,18 @@ The content of the environment where L will run. - - I<(before conversion)> - --The output of the corresponding commands (ie L etc) on the --physical machine. Useful for debugging novel hardware configurations. -+The output of the corresponding commands (ie L, L -+etc) on the physical machine. -+ -+The dmesg output is useful for detecting problems such as missing -+device drivers or firmware on the virt-p2v ISO. The others are useful -+for debugging novel hardware configurations. -+ -+=item F -+ -+I<(before conversion)> -+ -+The content of the environment where L will run. - - =item F - -@@ -799,7 +797,7 @@ B log file in any bug reports or support tickets. - - =item F - --I<(during/after conversion)> -+I<(before conversion)> - - This is the wrapper script which is used when running virt-v2v. For - interest only, do not attempt to run this script yourself. --- -2.13.4 - diff --git a/SOURCES/0030-v2v-Implement-i-vmx-to-read-VMware-vmx-files-directl.patch b/SOURCES/0030-v2v-Implement-i-vmx-to-read-VMware-vmx-files-directl.patch new file mode 100644 index 0000000..643a430 --- /dev/null +++ b/SOURCES/0030-v2v-Implement-i-vmx-to-read-VMware-vmx-files-directl.patch @@ -0,0 +1,1942 @@ +From e43fe85f28ba6fb184e6894db019668f0515c38d Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 10 Apr 2017 15:24:26 +0100 +Subject: [PATCH] v2v: Implement -i vmx to read VMware vmx files directly + (RHBZ#1441197). + +This is a mostly complete implementation of a VMX parser and input +class for virt-v2v. It parses the name, memory size, CPU topology, +firmware, video, sound, hard disks, removable disks and network +interfaces from the VMX file. It only omits support for floppies and +SCSI CD-ROMs. + +The input class is split into two major parts: a generic VMX file +parser (Parse_vmx), and the Input_vmx module which translates the VMX +tree into the source device model. + +This also contains tests. There are simple unit tests of the +Parse_vmx module, and also some more complete parsing tests taken from +real guests. + +(cherry picked from commit ca40078cdda9167d4658ddfe24c828c7ee76be37) +--- + v2v/Makefile.am | 15 ++ + v2v/cmdline.ml | 12 +- + v2v/input_vmx.ml | 349 ++++++++++++++++++++++++++++++++++++++ + v2v/input_vmx.mli | 22 +++ + v2v/name_from_disk.ml | 2 +- + v2v/parse_vmx.ml | 381 ++++++++++++++++++++++++++++++++++++++++++ + v2v/parse_vmx.mli | 89 ++++++++++ + v2v/test-v2v-i-vmx-1.expected | 39 +++++ + v2v/test-v2v-i-vmx-1.vmx | 172 +++++++++++++++++++ + v2v/test-v2v-i-vmx-2.expected | 19 +++ + v2v/test-v2v-i-vmx-2.vmx | 84 ++++++++++ + v2v/test-v2v-i-vmx-3.expected | 19 +++ + v2v/test-v2v-i-vmx-3.vmx | 91 ++++++++++ + v2v/test-v2v-i-vmx-4.expected | 19 +++ + v2v/test-v2v-i-vmx-4.vmx | 88 ++++++++++ + v2v/test-v2v-i-vmx.sh | 48 ++++++ + v2v/v2v_unit_tests.ml | 143 ++++++++++++++++ + v2v/virt-v2v.pod | 72 +++++++- + 18 files changed, 1655 insertions(+), 9 deletions(-) + create mode 100644 v2v/input_vmx.ml + create mode 100644 v2v/input_vmx.mli + create mode 100644 v2v/parse_vmx.ml + create mode 100644 v2v/parse_vmx.mli + create mode 100644 v2v/test-v2v-i-vmx-1.expected + create mode 100644 v2v/test-v2v-i-vmx-1.vmx + create mode 100644 v2v/test-v2v-i-vmx-2.expected + create mode 100644 v2v/test-v2v-i-vmx-2.vmx + create mode 100644 v2v/test-v2v-i-vmx-3.expected + create mode 100644 v2v/test-v2v-i-vmx-3.vmx + create mode 100644 v2v/test-v2v-i-vmx-4.expected + create mode 100644 v2v/test-v2v-i-vmx-4.vmx + create mode 100755 v2v/test-v2v-i-vmx.sh + +diff --git a/v2v/Makefile.am b/v2v/Makefile.am +index 297406496..0df759eca 100644 +--- a/v2v/Makefile.am ++++ b/v2v/Makefile.am +@@ -38,6 +38,7 @@ SOURCES_MLI = \ + input_libvirt_xen_ssh.mli \ + input_libvirtxml.mli \ + input_ova.mli \ ++ input_vmx.mli \ + inspect_source.mli \ + libvirt_utils.mli \ + linux.mli \ +@@ -55,6 +56,7 @@ SOURCES_MLI = \ + OVF.mli \ + parse_ovf_from_ova.mli \ + parse_libvirt_xml.mli \ ++ parse_vmx.mli \ + qemu_command.mli \ + target_bus_assignment.mli \ + types.mli \ +@@ -80,6 +82,7 @@ SOURCES_ML = \ + windows_virtio.ml \ + modules_list.ml \ + input_disk.ml \ ++ parse_vmx.ml \ + parse_libvirt_xml.ml \ + create_libvirt_xml.ml \ + qemu_command.ml \ +@@ -89,6 +92,7 @@ SOURCES_ML = \ + input_libvirt_xen_ssh.ml \ + input_libvirt.ml \ + input_ova.ml \ ++ input_vmx.ml \ + linux_bootloaders.ml \ + linux_kernels.ml \ + convert_linux.ml \ +@@ -268,6 +272,7 @@ TESTS = \ + test-v2v-i-ova-subfolders.sh \ + test-v2v-i-ova-tar.sh \ + test-v2v-i-ova-two-disks.sh \ ++ test-v2v-i-vmx.sh \ + test-v2v-bad-networks-and-bridges.sh + + if HAVE_LIBVIRT +@@ -411,6 +416,15 @@ EXTRA_DIST += \ + test-v2v-i-ova.ovf \ + test-v2v-i-ova.sh \ + test-v2v-i-ova.xml \ ++ test-v2v-i-vmx.sh \ ++ test-v2v-i-vmx-1.expected \ ++ test-v2v-i-vmx-2.expected \ ++ test-v2v-i-vmx-3.expected \ ++ test-v2v-i-vmx-4.expected \ ++ test-v2v-i-vmx-1.vmx \ ++ test-v2v-i-vmx-2.vmx \ ++ test-v2v-i-vmx-3.vmx \ ++ test-v2v-i-vmx-4.vmx \ + test-v2v-machine-readable.sh \ + test-v2v-networks-and-bridges-expected.xml \ + test-v2v-networks-and-bridges.sh \ +@@ -450,6 +464,7 @@ v2v_unit_tests_BOBJECTS = \ + windows.cmo \ + windows_virtio.cmo \ + linux.cmo \ ++ parse_vmx.cmo \ + v2v_unit_tests.cmo + v2v_unit_tests_XOBJECTS = $(v2v_unit_tests_BOBJECTS:.cmo=.cmx) + +diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml +index 3e3d5c312..db2346a38 100644 +--- a/v2v/cmdline.ml ++++ b/v2v/cmdline.ml +@@ -86,6 +86,7 @@ let parse_cmdline () = + | "libvirt" -> input_mode := `Libvirt + | "libvirtxml" -> input_mode := `LibvirtXML + | "ova" -> input_mode := `OVA ++ | "vmx" -> input_mode := `VMX + | s -> + error (f_"unknown -i option: %s") s + in +@@ -333,7 +334,16 @@ read the man page virt-v2v(1). + | [filename] -> filename + | _ -> + error (f_"expecting an OVA file name on the command line") in +- Input_ova.input_ova filename in ++ Input_ova.input_ova filename ++ ++ | `VMX -> ++ (* -i vmx: Expecting an vmx filename. *) ++ let filename = ++ match args with ++ | [filename] -> filename ++ | _ -> ++ error (f_"expecting a VMX file name on the command line") in ++ Input_vmx.input_vmx filename in + + (* Prevent use of --in-place option in RHEL. *) + if in_place then +diff --git a/v2v/input_vmx.ml b/v2v/input_vmx.ml +new file mode 100644 +index 000000000..bb09f0bf8 +--- /dev/null ++++ b/v2v/input_vmx.ml +@@ -0,0 +1,349 @@ ++(* virt-v2v ++ * Copyright (C) 2017 Red Hat Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ *) ++ ++open Printf ++open Scanf ++ ++open Common_gettext.Gettext ++open Common_utils ++ ++open Types ++open Utils ++open Name_from_disk ++ ++external identity : 'a -> 'a = "%identity" ++ ++let rec find_disks vmx vmx_filename = ++ find_scsi_disks vmx vmx_filename @ find_ide_disks vmx vmx_filename ++ ++(* Find all SCSI hard disks. ++ * ++ * In the VMX file: ++ * scsi0.virtualDev = "pvscsi" # or may be "lsilogic" etc. ++ * scsi0:0.deviceType = "scsi-hardDisk" ++ * scsi0:0.fileName = "guest.vmdk" ++ *) ++and find_scsi_disks vmx vmx_filename = ++ let get_scsi_controller_target ns = ++ sscanf ns "scsi%d:%d" (fun c t -> c, t) ++ in ++ let is_scsi_controller_target ns = ++ try ignore (get_scsi_controller_target ns); true ++ with Scanf.Scan_failure _ | End_of_file | Failure _ -> false ++ in ++ let scsi_device_types = [ "scsi-harddisk" ] in ++ let scsi_controller = Source_SCSI in ++ ++ find_hdds vmx vmx_filename ++ get_scsi_controller_target is_scsi_controller_target ++ scsi_device_types scsi_controller ++ ++(* Find all IDE hard disks. ++ * ++ * In the VMX file: ++ * ide0:0.deviceType = "ata-hardDisk" ++ * ide0:0.fileName = "guest.vmdk" ++ *) ++and find_ide_disks vmx vmx_filename = ++ let get_ide_controller_target ns = ++ sscanf ns "ide%d:%d" (fun c t -> c, t) ++ in ++ let is_ide_controller_target ns = ++ try ignore (get_ide_controller_target ns); true ++ with Scanf.Scan_failure _ | End_of_file | Failure _ -> false ++ in ++ let ide_device_types = [ "ata-harddisk" ] in ++ let ide_controller = Source_IDE in ++ ++ find_hdds vmx vmx_filename ++ get_ide_controller_target is_ide_controller_target ++ ide_device_types ide_controller ++ ++and find_hdds vmx vmx_filename ++ get_controller_target is_controller_target ++ device_types controller = ++ (* Find namespaces matching '(ide|scsi)X:Y' with suitable deviceType. *) ++ let hdds = ++ Parse_vmx.select_namespaces ( ++ function ++ | [ns] -> ++ (* Check the namespace is '(ide|scsi)X:Y' *) ++ if not (is_controller_target ns) then false ++ else ( ++ (* Check the deviceType is one we are looking for. *) ++ match Parse_vmx.get_string vmx [ns; "deviceType"] with ++ | Some str -> ++ let str = String.lowercase_ascii str in ++ List.mem str device_types ++ | None -> false ++ ) ++ | _ -> false ++ ) vmx in ++ ++ (* Map the subset to a list of disks. *) ++ let hdds = ++ Parse_vmx.map ( ++ fun path v -> ++ match path, v with ++ | [ns; "filename"], Some filename -> ++ let c, t = get_controller_target ns in ++ let s = { s_disk_id = (-1); ++ s_qemu_uri = qemu_uri_of_filename vmx_filename filename; ++ s_format = Some "vmdk"; ++ s_controller = Some controller } in ++ Some (c, t, s) ++ | _ -> None ++ ) hdds in ++ let hdds = filter_map identity hdds in ++ ++ (* We don't have a way to return the controllers and targets, so ++ * just make sure the disks are sorted into order, since Parse_vmx ++ * won't return them in any particular order. ++ *) ++ let hdds = List.sort compare hdds in ++ let hdds = List.map (fun (_, _, source) -> source) hdds in ++ ++ (* Set the s_disk_id field to an incrementing number. *) ++ let hdds = mapi (fun i source -> { source with s_disk_id = i }) hdds in ++ ++ hdds ++ ++(* The filename can be an absolute path, but is more often a ++ * path relative to the location of the vmx file. ++ * ++ * Note that we always end up with an absolute path, which is ++ * also useful because it means we won't have any paths that ++ * could be misinterpreted by qemu. ++ *) ++and qemu_uri_of_filename vmx_filename filename = ++ if not (Filename.is_relative filename) then ++ filename ++ else ( ++ let dir = Filename.dirname (absolute_path vmx_filename) in ++ dir // filename ++ ) ++ ++(* Find all removable disks. ++ * ++ * In the VMX file: ++ * ide1:0.deviceType = "cdrom-image" ++ * ide1:0.fileName = "boot.iso" ++ * ++ * XXX This only supports IDE CD-ROMs, but we could support SCSI ++ * CD-ROMs and floppies in future. ++ *) ++and find_removables vmx = ++ let get_ide_controller_target ns = ++ sscanf ns "ide%d:%d" (fun c t -> c, t) ++ in ++ let is_ide_controller_target ns = ++ try ignore (get_ide_controller_target ns); true ++ with Scanf.Scan_failure _ | End_of_file | Failure _ -> false ++ in ++ let device_types = [ "atapi-cdrom"; ++ "cdrom-image"; "cdrom-raw" ] in ++ ++ (* Find namespaces matching 'ideX:Y' with suitable deviceType. *) ++ let devs = ++ Parse_vmx.select_namespaces ( ++ function ++ | [ns] -> ++ (* Check the namespace is 'ideX:Y' *) ++ if not (is_ide_controller_target ns) then false ++ else ( ++ (* Check the deviceType is one we are looking for. *) ++ match Parse_vmx.get_string vmx [ns; "deviceType"] with ++ | Some str -> ++ let str = String.lowercase_ascii str in ++ List.mem str device_types ++ | None -> false ++ ) ++ | _ -> false ++ ) vmx in ++ ++ (* Map the subset to a list of CD-ROMs. *) ++ let devs = ++ Parse_vmx.map ( ++ fun path v -> ++ match path, v with ++ | [ns], None -> ++ let c, t = get_ide_controller_target ns in ++ let s = { s_removable_type = CDROM; ++ s_removable_controller = Some Source_IDE; ++ s_removable_slot = Some (ide_slot c t) } in ++ Some s ++ | _ -> None ++ ) devs in ++ let devs = filter_map identity devs in ++ ++ (* Sort by slot. *) ++ let devs = ++ List.sort ++ (fun { s_removable_slot = s1 } { s_removable_slot = s2 } -> ++ compare s1 s2) ++ devs in ++ ++ devs ++ ++and ide_slot c t = ++ (* Assuming the old master/slave arrangement. *) ++ c * 2 + t ++ ++(* Find all ethernet cards. ++ * ++ * In the VMX file: ++ * ethernet0.virtualDev = "vmxnet3" ++ * ethernet0.networkName = "VM Network" ++ * ethernet0.generatedAddress = "00:01:02:03:04:05" ++ * ethernet0.connectionType = "bridged" # also: "custom", "nat" or not present ++ *) ++and find_nics vmx = ++ let get_ethernet_port ns = ++ sscanf ns "ethernet%d" (fun p -> p) ++ in ++ let is_ethernet_port ns = ++ try ignore (get_ethernet_port ns); true ++ with Scanf.Scan_failure _ | End_of_file | Failure _ -> false ++ in ++ ++ (* Find namespaces matching 'ethernetX'. *) ++ let nics = ++ Parse_vmx.select_namespaces ( ++ function ++ | [ns] -> is_ethernet_port ns ++ | _ -> false ++ ) vmx in ++ ++ (* Map the subset to a list of NICs. *) ++ let nics = ++ Parse_vmx.map ( ++ fun path v -> ++ match path, v with ++ | [ns], None -> ++ let port = get_ethernet_port ns in ++ let mac = Parse_vmx.get_string vmx [ns; "generatedAddress"] in ++ let model = Parse_vmx.get_string vmx [ns; "virtualDev"] in ++ let model = ++ match model with ++ | Some m when String.lowercase_ascii m = "e1000" -> ++ Some Source_e1000 ++ | Some model -> ++ Some (Source_other_nic (String.lowercase_ascii model)) ++ | None -> None in ++ let vnet = Parse_vmx.get_string vmx [ns; "networkName"] in ++ let vnet = ++ match vnet with ++ | Some vnet -> vnet ++ | None -> ns (* "ethernetX" *) in ++ let vnet_type = ++ match Parse_vmx.get_string vmx [ns; "connectionType"] with ++ | Some b when String.lowercase_ascii b = "bridged" -> ++ Bridge ++ | Some _ | None -> Network in ++ Some (port, ++ { s_mac = mac; s_nic_model = model; ++ s_vnet = vnet; s_vnet_orig = vnet; ++ s_vnet_type = vnet_type }) ++ | _ -> None ++ ) nics in ++ let nics = filter_map identity nics in ++ ++ (* Sort by port. *) ++ let nics = List.sort compare nics in ++ ++ let nics = List.map (fun (_, source) -> source) nics in ++ nics ++ ++class input_vmx vmx_filename = object ++ inherit input ++ ++ method as_options = "-i vmx " ^ vmx_filename ++ ++ method source () = ++ (* Parse the VMX file. *) ++ let vmx = Parse_vmx.parse_file vmx_filename in ++ ++ let name = ++ match Parse_vmx.get_string vmx ["displayName"] with ++ | None -> ++ warning (f_"no displayName key found in VMX file"); ++ name_from_disk vmx_filename ++ | Some s -> s in ++ ++ let memory_mb = ++ match Parse_vmx.get_int64 vmx ["memSize"] with ++ | None -> 32_L (* default is really 32 MB! *) ++ | Some i -> i in ++ let memory = memory_mb *^ 1024L *^ 1024L in ++ ++ let vcpu = ++ match Parse_vmx.get_int vmx ["numvcpus"] with ++ | None -> 1 ++ | Some i -> i in ++ ++ let firmware = ++ match Parse_vmx.get_string vmx ["firmware"] with ++ | None -> BIOS ++ | Some "efi" -> UEFI ++ (* Other values are not documented for this field ... *) ++ | Some fw -> ++ warning (f_"unknown firmware value '%s', assuming BIOS") fw; ++ BIOS in ++ ++ let video = ++ if Parse_vmx.namespace_present vmx ["svga"] then ++ (* We could also parse svga.vramSize. *) ++ Some (Source_other_video "vmvga") ++ else ++ None in ++ ++ let sound = ++ match Parse_vmx.get_string vmx ["sound"; "virtualDev"] with ++ | Some ("sb16") -> Some { s_sound_model = SB16 } ++ | Some ("es1371") -> Some { s_sound_model = ES1370 (* hmmm ... *) } ++ | Some "hdaudio" -> Some { s_sound_model = ICH6 (* intel-hda *) } ++ | Some model -> ++ warning (f_"unknown sound device '%s' ignored") model; ++ None ++ | None -> None in ++ ++ let disks = find_disks vmx vmx_filename in ++ let removables = find_removables vmx in ++ let nics = find_nics vmx in ++ ++ let source = { ++ s_hypervisor = VMware; ++ s_name = name; ++ s_orig_name = name; ++ s_memory = memory; ++ s_vcpu = vcpu; ++ s_features = []; ++ s_firmware = firmware; ++ s_display = None; ++ s_video = video; ++ s_sound = sound; ++ s_disks = disks; ++ s_removables = removables; ++ s_nics = nics; ++ } in ++ ++ source ++end ++ ++let input_vmx = new input_vmx ++let () = Modules_list.register_input_module "vmx" +diff --git a/v2v/input_vmx.mli b/v2v/input_vmx.mli +new file mode 100644 +index 000000000..f236f8716 +--- /dev/null ++++ b/v2v/input_vmx.mli +@@ -0,0 +1,22 @@ ++(* virt-v2v ++ * Copyright (C) 2017 Red Hat Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ *) ++ ++(** [-i vmx] source. *) ++ ++val input_vmx : string -> Types.input ++(** [input_vmx filename] sets up an input from vmware vmx file. *) +diff --git a/v2v/name_from_disk.ml b/v2v/name_from_disk.ml +index 82f09250a..452d9462c 100644 +--- a/v2v/name_from_disk.ml ++++ b/v2v/name_from_disk.ml +@@ -24,7 +24,7 @@ let name_from_disk disk = + (* Remove the extension (or suffix), only if it's one usually + * used for disk images. *) + let suffixes = [ +- ".img"; ".ova"; ".qcow2"; ".raw"; ".vmdk"; ++ ".img"; ".ova"; ".qcow2"; ".raw"; ".vmdk"; ".vmx"; + "-sda"; + ] in + let rec loop = function +diff --git a/v2v/parse_vmx.ml b/v2v/parse_vmx.ml +new file mode 100644 +index 000000000..33ec17d3d +--- /dev/null ++++ b/v2v/parse_vmx.ml +@@ -0,0 +1,381 @@ ++(* virt-v2v ++ * Copyright (C) 2017 Red Hat Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ *) ++ ++open Printf ++ ++open Common_utils ++open Common_gettext.Gettext ++ ++(* As far as I can tell the VMX format is totally unspecified. ++ * However libvirt has a useful selection of .vmx files in the ++ * sources which explore some of the darker regions of this ++ * format. ++ * ++ * So here are some facts about VMX derived from libvirt and ++ * other places: ++ * ++ * - Keys are compared case insensitively. We assume here ++ * that keys are 7-bit ASCII. ++ * ++ * - Multiple keys with the same name are not allowed. ++ * ++ * - Escaping in the value string is possible using a very weird ++ * escape format: "|22" means the character '\x22'. To write ++ * a pipe character you must use "|7C". ++ * ++ * - Boolean values are written "TRUE", "FALSE", "True", "true", etc. ++ * Because of the quotes they cannot be distinguished from strings. ++ * ++ * - Comments (#...) and blank lines are ignored. Some files start ++ * with a hash-bang path, but we ignore those as comments. This ++ * parser also ignores any other line which it doesn't understand, ++ * but will print a warning. ++ * ++ * - Multi-line values are not permitted. ++ * ++ * - Keys are namespaced using dots, eg. scsi0:0.deviceType has ++ * the namespace "scsi0:0" and the key name "deviceType". ++ * ++ * - Using namespace.present = "FALSE" means that all other keys ++ * in and under the namespace are ignored. ++ * ++ * - You cannot have a namespace and a key with the same name, eg. ++ * this is not allowed: ++ * namespace = "some value" ++ * namespace.foo = "another value" ++ * ++ * - The Hashicorp packer VMX writer considers some special keys ++ * as not requiring any quotes around their values, but I'm ++ * ignoring that for now. ++ *) ++ ++(* This VMX file: ++ * ++ * foo.a = "abc" ++ * foo.b = "def" ++ * foo.bar.c = "abc" ++ * foo.bar.d = "def" ++ * ++ * would be represented by this structure: ++ * ++ * "foo" => Namespace ( # "foo" is a namespace ++ * "a" => Key "abc"; # "foo.a" is a key with value "abc" ++ * "b" => Key "def"; ++ * "bar" => Namespace ( # "foo.bar" is another namespace ++ * "c" => Key "abc"; ++ * "d" => Key "def"; ++ * ) ++ * ) ++ * ‘( => )’s represent the StringMap type. ++ *) ++type t = key StringMap.t ++ ++and key = ++ | Key of string ++ | Namespace of t ++ ++let empty = StringMap.empty ++ ++(* Compare two trees for equality. *) ++let rec equal vmx1 vmx2 = ++ let cmp k1 k2 = ++ match k1, k2 with ++ | Key v1, Key v2 -> v1 = v2 ++ | Key _, Namespace _ -> false ++ | Namespace _, Key _ -> false ++ | Namespace vmx1, Namespace vmx2 -> equal vmx1 vmx2 ++ in ++ StringMap.equal cmp vmx1 vmx2 ++ ++(* Higher-order functions. *) ++let rec select_namespaces pred vmx = ++ _select_namespaces [] pred vmx ++ ++and _select_namespaces path pred vmx = ++ StringMap.fold ( ++ fun k v new_vmx -> ++ let path = path @ [k] in ++ match v with ++ | Key _ -> new_vmx ++ | Namespace _ when pred path -> ++ StringMap.add k v new_vmx ++ | Namespace t -> ++ let t = _select_namespaces path pred t in ++ if not (equal t empty) then ++ StringMap.add k (Namespace t) new_vmx ++ else ++ new_vmx ++ ) vmx empty ++ ++let rec map f vmx = ++ _map [] f vmx ++ ++and _map path f vmx = ++ StringMap.fold ( ++ fun k v r -> ++ let path = path @ [k] in ++ match v with ++ | Key v -> r @ [ f path (Some v) ] ++ | Namespace t -> r @ [ f path None ] @ _map path f t ++ ) vmx [] ++ ++let rec namespace_present vmx = function ++ | [] -> false ++ | [ns] -> ++ let ns = String.lowercase_ascii ns in ++ (try ++ let v = StringMap.find ns vmx in ++ match v with ++ | Key _ -> false ++ | Namespace _ -> true ++ with ++ Not_found -> false ++ ) ++ | ns :: path -> ++ let ns = String.lowercase_ascii ns in ++ (try ++ let v = StringMap.find ns vmx in ++ match v with ++ | Key _ -> false ++ | Namespace vmx -> namespace_present vmx path ++ with ++ Not_found -> false ++ ) ++ ++(* Dump the vmx structure to [chan]. Used for debugging. *) ++let rec print chan indent vmx = ++ StringMap.iter (print_key chan indent) vmx ++ ++and print_key chan indent k = function ++ | Key v -> ++ output_spaces chan indent; ++ fprintf chan "%s = \"%s\"\n" k v ++ | Namespace vmx -> ++ output_spaces chan indent; ++ fprintf chan "namespace '%s':\n" k; ++ print chan (indent+4) vmx ++ ++(* As above, but creates a string instead. *) ++let rec to_string indent vmx = ++ StringMap.fold (fun k v str -> str ^ to_string_key indent k v) vmx "" ++ ++and to_string_key indent k = function ++ | Key v -> ++ String.spaces indent ^ sprintf "%s = \"%s\"\n" k v ++ | Namespace vmx -> ++ String.spaces indent ^ sprintf "namespace '%s':\n" k ^ ++ to_string (indent+4) vmx ++ ++(* Access keys in the tree. *) ++let rec get_string vmx = function ++ | [] -> None ++ | [k] -> ++ let k = String.lowercase_ascii k in ++ (try ++ let v = StringMap.find k vmx in ++ match v with ++ | Key v -> Some v ++ | Namespace _ -> None ++ with Not_found -> None ++ ) ++ | ns :: path -> ++ let ns = String.lowercase_ascii ns in ++ (try ++ let v = StringMap.find ns vmx in ++ match v with ++ | Key v -> None ++ | Namespace vmx -> get_string vmx path ++ with ++ Not_found -> None ++ ) ++ ++let get_int64 vmx path = ++ match get_string vmx path with ++ | None -> None ++ | Some i -> Some (Int64.of_string i) ++ ++let get_int vmx path = ++ match get_string vmx path with ++ | None -> None ++ | Some i -> Some (int_of_string i) ++ ++let rec get_bool vmx path = ++ match get_string vmx path with ++ | None -> None ++ | Some t -> Some (vmx_bool_of_string t) ++ ++and vmx_bool_of_string t = ++ if String.lowercase_ascii t = "true" then true ++ else if String.lowercase_ascii t = "false" then false ++ else failwith "bool_of_string" ++ ++(* Regular expression used to match key = "value" in VMX file. *) ++let rex = Str.regexp "^\\([^ \t=]+\\)[ \t]*=[ \t]*\"\\(.*\\)\"$" ++ ++(* Remove the weird escapes used in value strings. See description above. *) ++let remove_vmx_escapes str = ++ let len = String.length str in ++ let out = Bytes.make len '\000' in ++ let j = ref 0 in ++ ++ let rec loop i = ++ if i >= len then () ++ else ( ++ let c = String.unsafe_get str i in ++ if i <= len-3 && c = '|' then ( ++ let c1 = str.[i+1] and c2 = str.[i+2] in ++ if Char.isxdigit c1 && Char.isxdigit c2 then ( ++ let x = Char.hexdigit c1 * 0x10 + Char.hexdigit c2 in ++ Bytes.set out !j (Char.chr x); ++ incr j; ++ loop (i+3) ++ ) ++ else ( ++ Bytes.set out !j c; ++ incr j; ++ loop (i+1) ++ ) ++ ) ++ else ( ++ Bytes.set out !j c; ++ incr j; ++ loop (i+1) ++ ) ++ ) ++ in ++ loop 0; ++ ++ (* Truncate the output string to its real size and return it ++ * as an immutable string. ++ *) ++ Bytes.sub_string out 0 !j ++ ++(* Parsing. *) ++let rec parse_file vmx_filename = ++ (* Read the whole file as a list of lines. *) ++ let str = read_whole_file vmx_filename in ++ if verbose () then eprintf "VMX file:\n%s\n" str; ++ parse_string str ++ ++and parse_string str = ++ let lines = String.nsplit "\n" str in ++ ++ (* I've never seen any VMX file with CR-LF endings, and VMware ++ * itself is Linux-based, but to be on the safe side ... ++ *) ++ let lines = List.map (String.trimr ~test:((=) '\r')) lines in ++ ++ (* Ignore blank lines and comments. *) ++ let lines = List.filter ( ++ fun line -> ++ let line = String.triml line in ++ let len = String.length line in ++ len > 0 && line.[0] != '#' ++ ) lines in ++ ++ (* Parse the lines into key = "value". *) ++ let lines = filter_map ( ++ fun line -> ++ if Str.string_match rex line 0 then ( ++ let key = Str.matched_group 1 line in ++ let key = String.lowercase_ascii key in ++ let value = Str.matched_group 2 line in ++ let value = remove_vmx_escapes value in ++ Some (key, value) ++ ) ++ else ( ++ warning (f_"vmx parser: cannot parse this line, ignoring: %s") line; ++ None ++ ) ++ ) lines in ++ ++ (* Split the keys into namespace paths. *) ++ let lines = ++ List.map (fun (key, value) -> String.nsplit "." key, value) lines in ++ ++ (* Build a tree from the flat list and return it. This is horribly ++ * inefficient, at least O(n²), possibly even O(n².log n). Hope ++ * there are no large VMX files! (XXX) ++ *) ++ let vmx = ++ List.fold_left ( ++ fun vmx (path, value) -> insert vmx value path ++ ) empty lines in ++ ++ (* If we're verbose, dump the parsed VMX for debugging purposes. *) ++ if verbose () then ( ++ eprintf "parsed VMX tree:\n"; ++ print stderr 0 vmx ++ ); ++ ++ (* Drop all present = "FALSE" namespaces. *) ++ let vmx = drop_not_present vmx in ++ ++ vmx ++ ++and insert vmx value = function ++ | [] -> assert false ++ | [k] -> ++ if StringMap.mem k vmx then ( ++ warning (f_"vmx parser: duplicate key '%s' ignored") k; ++ vmx ++ ) else ++ StringMap.add k (Key value) vmx ++ | ns :: path -> ++ let v = ++ try ++ (match StringMap.find ns vmx with ++ | Namespace vmx -> Some vmx ++ | Key _ -> None ++ ) ++ with Not_found -> None in ++ let v = ++ match v with ++ | None -> ++ (* Completely new namespace. *) ++ insert empty value path ++ | Some v -> ++ (* Insert the subkey into the previously created namespace. *) ++ insert v value path in ++ StringMap.add ns (Namespace v) vmx ++ ++(* Find any "present" keys. If we find present = "FALSE", then ++ * drop the containing namespace and all subkeys and subnamespaces. ++ *) ++and drop_not_present vmx = ++ StringMap.fold ( ++ fun k v new_vmx -> ++ match v with ++ | Key _ -> ++ StringMap.add k v new_vmx ++ | Namespace vmx when contains_key_present_false vmx -> ++ (* drop this namespace and all sub-spaces *) ++ new_vmx ++ | Namespace v -> ++ (* recurse into sub-namespace and do the same check *) ++ let v = drop_not_present v in ++ StringMap.add k (Namespace v) new_vmx ++ ) vmx empty ++ ++and contains_key_present_false vmx = ++ try ++ match StringMap.find "present" vmx with ++ | Key v when vmx_bool_of_string v = false -> true ++ | Key _ | Namespace _ -> false ++ with ++ Failure _ | Not_found -> false +diff --git a/v2v/parse_vmx.mli b/v2v/parse_vmx.mli +new file mode 100644 +index 000000000..0e4f21f07 +--- /dev/null ++++ b/v2v/parse_vmx.mli +@@ -0,0 +1,89 @@ ++(* virt-v2v ++ * Copyright (C) 2017 Red Hat Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ *) ++ ++(** A simple parser for VMware [.vmx] files. *) ++ ++type t ++ ++val parse_file : string -> t ++(** [parse_file filename] parses a VMX file. *) ++ ++val parse_string : string -> t ++(** [parse_string s] parses VMX from a string. *) ++ ++val get_string : t -> string list -> string option ++(** Find a key and return it as a string. If not present, returns [None]. ++ ++ Note that if [namespace.present = "FALSE"] is found in the file ++ then all keys in [namespace] and below it are ignored. This ++ applies to all [get_*] functions. *) ++ ++val get_int64 : t -> string list -> int64 option ++(** Find a key and return it as an [int64]. ++ If not present, returns [None]. ++ ++ Raises [Failure _] if the key is present but was not parseable ++ as an integer. *) ++ ++val get_int : t -> string list -> int option ++(** Find a key and return it as an [int]. ++ If not present, returns [None]. ++ ++ Raises [Failure _] if the key is present but was not parseable ++ as an integer. *) ++ ++val get_bool : t -> string list -> bool option ++(** Find a key and return it as a boolean. ++ ++ You cannot return [namespace.present = "FALSE"] booleans this way. ++ They are processed by the parser and the namespace and anything ++ below it are removed from the tree. ++ ++ Raises [Failure _] if the key is present but was not parseable ++ as a boolean. *) ++ ++val namespace_present : t -> string list -> bool ++(** Returns true iff the namespace ({b note:} not key) is present. *) ++ ++val select_namespaces : (string list -> bool) -> t -> t ++(** Filter the VMX file, selecting exactly namespaces (and their ++ keys) matching the predicate. The predicate is a function which ++ is called on each {i namespace} path ({b note:} not on ++ namespace + key paths). If the predicate matches a ++ namespace, then all sub-namespaces under that namespace are ++ selected implicitly. *) ++ ++val map : (string list -> string option -> 'a) -> t -> 'a list ++(** Map all the entries in the VMX file into a list using the ++ map function. The map function takes two arguments. The ++ first is the path to the namespace or key, and the second ++ is the key value (or [None] if the path refers to a namespace). *) ++ ++val equal : t -> t -> bool ++(** Compare two VMX files for equality. This is mainly used for ++ testing the parser. *) ++ ++val empty : t ++(** An empty VMX file. *) ++ ++val print : out_channel -> int -> t -> unit ++(** [print chan indent] prints the VMX file to the output channel. ++ [indent] is the indentation applied to each line of output. *) ++ ++val to_string : int -> t -> string ++(** Same as {!print} but it creates a printable (multiline) string. *) +diff --git a/v2v/test-v2v-i-vmx-1.expected b/v2v/test-v2v-i-vmx-1.expected +new file mode 100644 +index 000000000..c7ef1f5d5 +--- /dev/null ++++ b/v2v/test-v2v-i-vmx-1.expected +@@ -0,0 +1,39 @@ ++[ 0.0] Opening the source -i vmx test-v2v-i-vmx-1.vmx ++Source guest information (--print-source option): ++ ++ source name: BZ1308535_21disks ++hypervisor type: vmware ++ memory: 2147483648 (bytes) ++ nr vCPUs: 1 ++ CPU features: ++ firmware: bios ++ display: ++ video: vmvga ++ sound: ++disks: ++ /BZ1308535_21disks.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_1.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_2.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_3.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_4.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_5.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_6.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_7.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_8.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_9.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_10.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_11.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_12.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_13.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_14.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_15.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_16.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_17.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_18.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_19.vmdk (vmdk) [scsi] ++ /BZ1308535_21disks_20.vmdk (vmdk) [scsi] ++removable media: ++ CD-ROM [ide] in slot 2 ++NICs: ++ Network "VM Network" mac: 00:0c:29:36:ef:31 [vmxnet3] ++ +diff --git a/v2v/test-v2v-i-vmx-1.vmx b/v2v/test-v2v-i-vmx-1.vmx +new file mode 100644 +index 000000000..3f2f060a5 +--- /dev/null ++++ b/v2v/test-v2v-i-vmx-1.vmx +@@ -0,0 +1,172 @@ ++.encoding = "UTF-8" ++config.version = "8" ++virtualHW.version = "8" ++nvram = "BZ1308535_21disks.nvram" ++pciBridge0.present = "TRUE" ++svga.present = "TRUE" ++pciBridge4.present = "TRUE" ++pciBridge4.virtualDev = "pcieRootPort" ++pciBridge4.functions = "8" ++pciBridge5.present = "TRUE" ++pciBridge5.virtualDev = "pcieRootPort" ++pciBridge5.functions = "8" ++pciBridge6.present = "TRUE" ++pciBridge6.virtualDev = "pcieRootPort" ++pciBridge6.functions = "8" ++pciBridge7.present = "TRUE" ++pciBridge7.virtualDev = "pcieRootPort" ++pciBridge7.functions = "8" ++vmci0.present = "TRUE" ++hpet0.present = "TRUE" ++displayName = "BZ1308535_21disks" ++extendedConfigFile = "BZ1308535_21disks.vmxf" ++virtualHW.productCompatibility = "hosted" ++memSize = "2048" ++sched.cpu.units = "mhz" ++powerType.powerOff = "soft" ++powerType.suspend = "hard" ++powerType.reset = "soft" ++scsi0.virtualDev = "pvscsi" ++scsi0.present = "TRUE" ++scsi1.virtualDev = "pvscsi" ++scsi1.present = "TRUE" ++ide1:0.deviceType = "cdrom-image" ++ide1:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/RHEL-7.1-20150219.1-Server-x86_64-boot.iso" ++ide1:0.present = "TRUE" ++floppy0.startConnected = "FALSE" ++floppy0.clientDevice = "TRUE" ++floppy0.fileName = "vmware-null-remote-floppy" ++ethernet0.virtualDev = "vmxnet3" ++ethernet0.networkName = "VM Network" ++ethernet0.addressType = "generated" ++ethernet0.present = "TRUE" ++scsi0:0.deviceType = "scsi-hardDisk" ++scsi0:0.fileName = "BZ1308535_21disks.vmdk" ++scsi0:0.present = "TRUE" ++scsi0:1.deviceType = "scsi-hardDisk" ++scsi0:1.fileName = "BZ1308535_21disks_1.vmdk" ++scsi0:1.present = "TRUE" ++scsi0:2.deviceType = "scsi-hardDisk" ++scsi0:2.fileName = "BZ1308535_21disks_2.vmdk" ++scsi0:2.present = "TRUE" ++scsi0:3.deviceType = "scsi-hardDisk" ++scsi0:3.fileName = "BZ1308535_21disks_3.vmdk" ++scsi0:3.present = "TRUE" ++scsi0:4.deviceType = "scsi-hardDisk" ++scsi0:4.fileName = "BZ1308535_21disks_4.vmdk" ++scsi0:4.present = "TRUE" ++scsi0:5.deviceType = "scsi-hardDisk" ++scsi0:5.fileName = "BZ1308535_21disks_5.vmdk" ++scsi0:5.present = "TRUE" ++scsi0:6.deviceType = "scsi-hardDisk" ++scsi0:6.fileName = "BZ1308535_21disks_6.vmdk" ++scsi0:6.present = "TRUE" ++scsi0:8.deviceType = "scsi-hardDisk" ++scsi0:8.fileName = "BZ1308535_21disks_7.vmdk" ++scsi0:8.present = "TRUE" ++scsi0:9.deviceType = "scsi-hardDisk" ++scsi0:9.fileName = "BZ1308535_21disks_8.vmdk" ++scsi0:9.present = "TRUE" ++scsi0:10.deviceType = "scsi-hardDisk" ++scsi0:10.fileName = "BZ1308535_21disks_9.vmdk" ++scsi0:10.present = "TRUE" ++scsi0:11.deviceType = "scsi-hardDisk" ++scsi0:11.fileName = "BZ1308535_21disks_10.vmdk" ++scsi0:11.present = "TRUE" ++scsi0:12.deviceType = "scsi-hardDisk" ++scsi0:12.fileName = "BZ1308535_21disks_11.vmdk" ++scsi0:12.present = "TRUE" ++scsi0:13.deviceType = "scsi-hardDisk" ++scsi0:13.fileName = "BZ1308535_21disks_12.vmdk" ++scsi0:13.present = "TRUE" ++scsi0:14.deviceType = "scsi-hardDisk" ++scsi0:14.fileName = "BZ1308535_21disks_13.vmdk" ++scsi0:14.present = "TRUE" ++scsi0:15.deviceType = "scsi-hardDisk" ++scsi0:15.fileName = "BZ1308535_21disks_14.vmdk" ++scsi0:15.present = "TRUE" ++scsi1:0.deviceType = "scsi-hardDisk" ++scsi1:0.fileName = "BZ1308535_21disks_15.vmdk" ++scsi1:0.present = "TRUE" ++scsi1:1.deviceType = "scsi-hardDisk" ++scsi1:1.fileName = "BZ1308535_21disks_16.vmdk" ++scsi1:1.present = "TRUE" ++scsi1:2.deviceType = "scsi-hardDisk" ++scsi1:2.fileName = "BZ1308535_21disks_17.vmdk" ++scsi1:2.present = "TRUE" ++scsi1:3.deviceType = "scsi-hardDisk" ++scsi1:3.fileName = "BZ1308535_21disks_18.vmdk" ++scsi1:3.present = "TRUE" ++scsi1:4.deviceType = "scsi-hardDisk" ++scsi1:4.fileName = "BZ1308535_21disks_19.vmdk" ++scsi1:4.present = "TRUE" ++scsi1:5.deviceType = "scsi-hardDisk" ++scsi1:5.fileName = "BZ1308535_21disks_20.vmdk" ++scsi1:5.present = "TRUE" ++guestOS = "rhel6-64" ++toolScripts.afterPowerOn = "TRUE" ++toolScripts.afterResume = "TRUE" ++toolScripts.beforeSuspend = "TRUE" ++toolScripts.beforePowerOff = "TRUE" ++uuid.bios = "56 4d 96 af e6 46 bd 86-5c 4d 65 4e 77 36 ef 31" ++uuid.location = "56 4d 96 af e6 46 bd 86-5c 4d 65 4e 77 36 ef 31" ++vc.uuid = "52 31 cb fc c1 3f 96 32-83 c0 bb 70 6c 90 5c fd" ++chipset.onlineStandby = "FALSE" ++sched.cpu.min = "0" ++sched.cpu.shares = "normal" ++sched.mem.min = "0" ++sched.mem.minSize = "0" ++sched.mem.shares = "normal" ++svga.vramSize = "8388608" ++sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/BZ1308535_21disks/BZ1308535_21disks-6a024f8a.vswp" ++replay.supported = "FALSE" ++replay.filename = "" ++scsi0:0.redo = "" ++scsi0:1.redo = "" ++scsi0:2.redo = "" ++scsi0:3.redo = "" ++scsi0:4.redo = "" ++scsi0:5.redo = "" ++scsi0:6.redo = "" ++scsi0:8.redo = "" ++scsi0:9.redo = "" ++scsi0:10.redo = "" ++scsi0:11.redo = "" ++scsi0:12.redo = "" ++scsi0:13.redo = "" ++scsi0:14.redo = "" ++scsi0:15.redo = "" ++scsi1:0.redo = "" ++scsi1:1.redo = "" ++scsi1:2.redo = "" ++scsi1:3.redo = "" ++scsi1:4.redo = "" ++scsi1:5.redo = "" ++pciBridge0.pciSlotNumber = "17" ++pciBridge4.pciSlotNumber = "21" ++pciBridge5.pciSlotNumber = "22" ++pciBridge6.pciSlotNumber = "23" ++pciBridge7.pciSlotNumber = "24" ++scsi0.pciSlotNumber = "160" ++scsi1.pciSlotNumber = "192" ++ethernet0.pciSlotNumber = "224" ++vmci0.pciSlotNumber = "32" ++scsi0.sasWWID = "50 05 05 6f e6 46 bd 80" ++scsi1.sasWWID = "50 05 05 6f e6 46 bc 80" ++ethernet0.generatedAddress = "00:0c:29:36:ef:31" ++ethernet0.generatedAddressOffset = "0" ++vmci0.id = "2000088881" ++hostCPUID.0 = "0000000d756e65476c65746e49656e69" ++hostCPUID.1 = "000206a700100800179ae3bfbfebfbff" ++hostCPUID.80000001 = "00000000000000000000000128100800" ++guestCPUID.0 = "0000000d756e65476c65746e49656e69" ++guestCPUID.1 = "000206a700010800969822030fabfbff" ++guestCPUID.80000001 = "00000000000000000000000128100800" ++userCPUID.0 = "0000000d756e65476c65746e49656e69" ++userCPUID.1 = "000206a700100800169822030fabfbff" ++userCPUID.80000001 = "00000000000000000000000128100800" ++evcCompatibilityMode = "FALSE" ++vmotion.checkpointFBSize = "8388608" ++cleanShutdown = "TRUE" ++softPowerOff = "TRUE" ++tools.remindInstall = "TRUE" +diff --git a/v2v/test-v2v-i-vmx-2.expected b/v2v/test-v2v-i-vmx-2.expected +new file mode 100644 +index 000000000..a04bd0f62 +--- /dev/null ++++ b/v2v/test-v2v-i-vmx-2.expected +@@ -0,0 +1,19 @@ ++[ 0.0] Opening the source -i vmx test-v2v-i-vmx-2.vmx ++Source guest information (--print-source option): ++ ++ source name: Fedora 20 ++hypervisor type: vmware ++ memory: 2147483648 (bytes) ++ nr vCPUs: 1 ++ CPU features: ++ firmware: bios ++ display: ++ video: vmvga ++ sound: ++disks: ++ /Fedora 20.vmdk (vmdk) [scsi] ++removable media: ++ ++NICs: ++ Network "VM Network" mac: 00:50:56:9b:5f:0d [vmxnet3] ++ +diff --git a/v2v/test-v2v-i-vmx-2.vmx b/v2v/test-v2v-i-vmx-2.vmx +new file mode 100644 +index 000000000..d9dcf3a5c +--- /dev/null ++++ b/v2v/test-v2v-i-vmx-2.vmx +@@ -0,0 +1,84 @@ ++.encoding = "UTF-8" ++config.version = "8" ++virtualHW.version = "10" ++nvram = "Fedora 20.nvram" ++pciBridge0.present = "TRUE" ++svga.present = "TRUE" ++pciBridge4.present = "TRUE" ++pciBridge4.virtualDev = "pcieRootPort" ++pciBridge4.functions = "8" ++pciBridge5.present = "TRUE" ++pciBridge5.virtualDev = "pcieRootPort" ++pciBridge5.functions = "8" ++pciBridge6.present = "TRUE" ++pciBridge6.virtualDev = "pcieRootPort" ++pciBridge6.functions = "8" ++pciBridge7.present = "TRUE" ++pciBridge7.virtualDev = "pcieRootPort" ++pciBridge7.functions = "8" ++vmci0.present = "TRUE" ++hpet0.present = "TRUE" ++displayName = "Fedora 20" ++extendedConfigFile = "Fedora 20.vmxf" ++virtualHW.productCompatibility = "hosted" ++svga.vramSize = "8388608" ++memSize = "2048" ++sched.cpu.units = "mhz" ++sched.cpu.affinity = "all" ++powerType.powerOff = "soft" ++powerType.suspend = "hard" ++powerType.reset = "soft" ++scsi0.virtualDev = "pvscsi" ++scsi0.present = "TRUE" ++sata0.present = "TRUE" ++scsi0:0.deviceType = "scsi-hardDisk" ++scsi0:0.fileName = "Fedora 20.vmdk" ++sched.scsi0:0.shares = "normal" ++sched.scsi0:0.throughputCap = "off" ++scsi0:0.present = "TRUE" ++ethernet0.virtualDev = "vmxnet3" ++ethernet0.networkName = "VM Network" ++ethernet0.addressType = "vpx" ++ethernet0.generatedAddress = "00:50:56:9b:5f:0d" ++ethernet0.present = "TRUE" ++sata0:0.startConnected = "FALSE" ++sata0:0.deviceType = "cdrom-image" ++sata0:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/Fedora-20-x86_64-netinst.iso" ++sata0:0.present = "TRUE" ++floppy0.startConnected = "FALSE" ++floppy0.clientDevice = "TRUE" ++floppy0.fileName = "vmware-null-remote-floppy" ++vmci.filter.enable = "TRUE" ++guestOS = "rhel7-64" ++toolScripts.afterPowerOn = "TRUE" ++toolScripts.afterResume = "TRUE" ++toolScripts.beforeSuspend = "TRUE" ++toolScripts.beforePowerOff = "TRUE" ++uuid.bios = "42 1b 4b 87 e6 b7 d8 81-07 a0 c9 d2 21 cd 3c 6b" ++vc.uuid = "50 1b 1f 1b 73 00 32 bf-93 a1 1c b2 b4 e6 17 d6" ++sched.cpu.min = "0" ++sched.cpu.shares = "normal" ++sched.mem.min = "0" ++sched.mem.minSize = "0" ++sched.mem.shares = "normal" ++sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/Fedora 20/Fedora 20-c71e4118.vswp" ++uuid.location = "56 4d 0f 53 00 63 d5 55-41 01 4c f7 55 ce 03 0e" ++replay.supported = "TRUE" ++replay.filename = "" ++scsi0:0.redo = "" ++pciBridge0.pciSlotNumber = "17" ++pciBridge4.pciSlotNumber = "21" ++pciBridge5.pciSlotNumber = "22" ++pciBridge6.pciSlotNumber = "23" ++pciBridge7.pciSlotNumber = "24" ++scsi0.pciSlotNumber = "160" ++ethernet0.pciSlotNumber = "192" ++vmci0.pciSlotNumber = "32" ++sata0.pciSlotNumber = "33" ++scsi0.sasWWID = "50 05 05 67 e6 b7 d8 80" ++vmci0.id = "567098475" ++vmotion.checkpointFBSize = "8388608" ++cleanShutdown = "TRUE" ++softPowerOff = "TRUE" ++sata0:0.allowGuestConnectionControl = "TRUE" ++tools.syncTime = "FALSE" +diff --git a/v2v/test-v2v-i-vmx-3.expected b/v2v/test-v2v-i-vmx-3.expected +new file mode 100644 +index 000000000..64808a77b +--- /dev/null ++++ b/v2v/test-v2v-i-vmx-3.expected +@@ -0,0 +1,19 @@ ++[ 0.0] Opening the source -i vmx test-v2v-i-vmx-3.vmx ++Source guest information (--print-source option): ++ ++ source name: RHEL 7.1 UEFI ++hypervisor type: vmware ++ memory: 2147483648 (bytes) ++ nr vCPUs: 1 ++ CPU features: ++ firmware: uefi ++ display: ++ video: vmvga ++ sound: ++disks: ++ /RHEL 7.1 UEFI.vmdk (vmdk) [scsi] ++removable media: ++ CD-ROM [ide] in slot 2 ++NICs: ++ Network "VM Network" mac: 00:0c:29:4b:2b:8c [vmxnet3] ++ +diff --git a/v2v/test-v2v-i-vmx-3.vmx b/v2v/test-v2v-i-vmx-3.vmx +new file mode 100644 +index 000000000..c39215555 +--- /dev/null ++++ b/v2v/test-v2v-i-vmx-3.vmx +@@ -0,0 +1,91 @@ ++.encoding = "UTF-8" ++config.version = "8" ++virtualHW.version = "8" ++nvram = "RHEL 7.1 UEFI.nvram" ++pciBridge0.present = "TRUE" ++svga.present = "TRUE" ++pciBridge4.present = "TRUE" ++pciBridge4.virtualDev = "pcieRootPort" ++pciBridge4.functions = "8" ++pciBridge5.present = "TRUE" ++pciBridge5.virtualDev = "pcieRootPort" ++pciBridge5.functions = "8" ++pciBridge6.present = "TRUE" ++pciBridge6.virtualDev = "pcieRootPort" ++pciBridge6.functions = "8" ++pciBridge7.present = "TRUE" ++pciBridge7.virtualDev = "pcieRootPort" ++pciBridge7.functions = "8" ++vmci0.present = "TRUE" ++hpet0.present = "TRUE" ++displayName = "RHEL 7.1 UEFI" ++extendedConfigFile = "RHEL 7.1 UEFI.vmxf" ++virtualHW.productCompatibility = "hosted" ++memSize = "2048" ++firmware = "efi" ++sched.cpu.units = "mhz" ++powerType.powerOff = "soft" ++powerType.suspend = "hard" ++powerType.reset = "soft" ++scsi0.virtualDev = "pvscsi" ++scsi0.present = "TRUE" ++ide1:0.startConnected = "FALSE" ++ide1:0.deviceType = "cdrom-image" ++ide1:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/RHEL-7.1-20150219.1-Server-x86_64-boot.iso" ++ide1:0.present = "TRUE" ++floppy0.startConnected = "FALSE" ++floppy0.clientDevice = "TRUE" ++floppy0.fileName = "vmware-null-remote-floppy" ++ethernet0.virtualDev = "vmxnet3" ++ethernet0.networkName = "VM Network" ++ethernet0.addressType = "generated" ++ethernet0.present = "TRUE" ++scsi0:0.deviceType = "scsi-hardDisk" ++scsi0:0.fileName = "RHEL 7.1 UEFI.vmdk" ++scsi0:0.present = "TRUE" ++guestOS = "rhel6-64" ++toolScripts.afterPowerOn = "TRUE" ++toolScripts.afterResume = "TRUE" ++toolScripts.beforeSuspend = "TRUE" ++toolScripts.beforePowerOff = "TRUE" ++uuid.bios = "56 4d 99 89 a7 21 91 0d-cc 28 e2 db d5 4b 2b 8c" ++uuid.location = "56 4d 99 89 a7 21 91 0d-cc 28 e2 db d5 4b 2b 8c" ++vc.uuid = "52 3f 29 10 d3 81 16 43-fa b0 e3 af 3b ba 36 e5" ++chipset.onlineStandby = "FALSE" ++sched.cpu.min = "0" ++sched.cpu.shares = "normal" ++sched.mem.min = "0" ++sched.mem.minSize = "0" ++sched.mem.shares = "normal" ++svga.vramSize = "8388608" ++sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/RHEL 7.1 UEFI/RHEL 7.1 UEFI-58ff6e6f.vswp" ++replay.supported = "FALSE" ++replay.filename = "" ++scsi0:0.redo = "" ++pciBridge0.pciSlotNumber = "17" ++pciBridge4.pciSlotNumber = "21" ++pciBridge5.pciSlotNumber = "22" ++pciBridge6.pciSlotNumber = "23" ++pciBridge7.pciSlotNumber = "24" ++scsi0.pciSlotNumber = "160" ++ethernet0.pciSlotNumber = "192" ++vmci0.pciSlotNumber = "32" ++scsi0.sasWWID = "50 05 05 69 a7 21 91 00" ++ethernet0.generatedAddress = "00:0c:29:4b:2b:8c" ++ethernet0.generatedAddressOffset = "0" ++vmci0.id = "-716493940" ++hostCPUID.0 = "0000000d756e65476c65746e49656e69" ++hostCPUID.1 = "000206a700100800179ae3bfbfebfbff" ++hostCPUID.80000001 = "00000000000000000000000128100800" ++guestCPUID.0 = "0000000d756e65476c65746e49656e69" ++guestCPUID.1 = "000206a700010800969822030fabfbff" ++guestCPUID.80000001 = "00000000000000000000000128100800" ++userCPUID.0 = "0000000d756e65476c65746e49656e69" ++userCPUID.1 = "000206a700100800169822030fabfbff" ++userCPUID.80000001 = "00000000000000000000000128100800" ++evcCompatibilityMode = "FALSE" ++vmotion.checkpointFBSize = "8388608" ++cleanShutdown = "TRUE" ++softPowerOff = "TRUE" ++ide1:0.allowGuestConnectionControl = "TRUE" ++tools.syncTime = "FALSE" +diff --git a/v2v/test-v2v-i-vmx-4.expected b/v2v/test-v2v-i-vmx-4.expected +new file mode 100644 +index 000000000..208920b29 +--- /dev/null ++++ b/v2v/test-v2v-i-vmx-4.expected +@@ -0,0 +1,19 @@ ++[ 0.0] Opening the source -i vmx test-v2v-i-vmx-4.vmx ++Source guest information (--print-source option): ++ ++ source name: Windows 7 x64 ++hypervisor type: vmware ++ memory: 2147483648 (bytes) ++ nr vCPUs: 1 ++ CPU features: ++ firmware: bios ++ display: ++ video: vmvga ++ sound: ++disks: ++ /Windows 7 x64.vmdk (vmdk) [scsi] ++removable media: ++ CD-ROM [ide] in slot 2 ++NICs: ++ Network "VM Network" mac: 00:0c:29:94:89:23 [e1000] ++ +diff --git a/v2v/test-v2v-i-vmx-4.vmx b/v2v/test-v2v-i-vmx-4.vmx +new file mode 100644 +index 000000000..7756cf248 +--- /dev/null ++++ b/v2v/test-v2v-i-vmx-4.vmx +@@ -0,0 +1,88 @@ ++.encoding = "UTF-8" ++config.version = "8" ++virtualHW.version = "8" ++nvram = "Windows 7 x64.nvram" ++pciBridge0.present = "TRUE" ++svga.present = "TRUE" ++pciBridge4.present = "TRUE" ++pciBridge4.virtualDev = "pcieRootPort" ++pciBridge4.functions = "8" ++pciBridge5.present = "TRUE" ++pciBridge5.virtualDev = "pcieRootPort" ++pciBridge5.functions = "8" ++pciBridge6.present = "TRUE" ++pciBridge6.virtualDev = "pcieRootPort" ++pciBridge6.functions = "8" ++pciBridge7.present = "TRUE" ++pciBridge7.virtualDev = "pcieRootPort" ++pciBridge7.functions = "8" ++vmci0.present = "TRUE" ++hpet0.present = "TRUE" ++displayName = "Windows 7 x64" ++extendedConfigFile = "Windows 7 x64.vmxf" ++virtualHW.productCompatibility = "hosted" ++memSize = "2048" ++sched.cpu.units = "mhz" ++powerType.powerOff = "soft" ++powerType.suspend = "hard" ++powerType.reset = "soft" ++scsi0.virtualDev = "lsisas1068" ++scsi0.present = "TRUE" ++ide1:0.deviceType = "cdrom-image" ++ide1:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/en_windows_7_ultimate_with_sp1_x64_dvd_u_677332.iso" ++ide1:0.present = "TRUE" ++floppy0.startConnected = "FALSE" ++floppy0.clientDevice = "TRUE" ++floppy0.fileName = "vmware-null-remote-floppy" ++ethernet0.virtualDev = "e1000" ++ethernet0.networkName = "VM Network" ++ethernet0.addressType = "generated" ++ethernet0.present = "TRUE" ++scsi0:0.deviceType = "scsi-hardDisk" ++scsi0:0.fileName = "Windows 7 x64.vmdk" ++scsi0:0.present = "TRUE" ++guestOS = "windows7-64" ++toolScripts.afterPowerOn = "TRUE" ++toolScripts.afterResume = "TRUE" ++toolScripts.beforeSuspend = "TRUE" ++toolScripts.beforePowerOff = "TRUE" ++uuid.bios = "56 4d 6f ca 63 a5 a8 3e-13 ec 73 89 1d 94 89 23" ++uuid.location = "56 4d 6f ca 63 a5 a8 3e-13 ec 73 89 1d 94 89 23" ++vc.uuid = "52 7a 63 e1 2c 2f 50 46-91 66 3a e8 fa f9 c4 65" ++chipset.onlineStandby = "FALSE" ++sched.cpu.min = "0" ++sched.cpu.shares = "normal" ++sched.mem.min = "0" ++sched.mem.minSize = "0" ++sched.mem.shares = "normal" ++svga.vramSize = "8388608" ++sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/Windows 7 x64/Windows 7 x64-8e3b0929.vswp" ++replay.supported = "FALSE" ++replay.filename = "" ++scsi0:0.redo = "" ++pciBridge0.pciSlotNumber = "17" ++pciBridge4.pciSlotNumber = "21" ++pciBridge5.pciSlotNumber = "22" ++pciBridge6.pciSlotNumber = "23" ++pciBridge7.pciSlotNumber = "24" ++scsi0.pciSlotNumber = "160" ++ethernet0.pciSlotNumber = "32" ++vmci0.pciSlotNumber = "33" ++scsi0.sasWWID = "50 05 05 6a 63 a5 a8 30" ++ethernet0.generatedAddress = "00:0c:29:94:89:23" ++ethernet0.generatedAddressOffset = "0" ++vmci0.id = "496273699" ++hostCPUID.0 = "0000000b756e65476c65746e49656e69" ++hostCPUID.1 = "000206c220200800029ee3ffbfebfbff" ++hostCPUID.80000001 = "0000000000000000000000012c100800" ++guestCPUID.0 = "0000000b756e65476c65746e49656e69" ++guestCPUID.1 = "000206c200010800829822030fabfbff" ++guestCPUID.80000001 = "00000000000000000000000128100800" ++userCPUID.0 = "0000000b756e65476c65746e49656e69" ++userCPUID.1 = "000206c220200800029822030fabfbff" ++userCPUID.80000001 = "00000000000000000000000128100800" ++evcCompatibilityMode = "FALSE" ++vmotion.checkpointFBSize = "8388608" ++cleanShutdown = "TRUE" ++softPowerOff = "TRUE" ++tools.remindInstall = "TRUE" +diff --git a/v2v/test-v2v-i-vmx.sh b/v2v/test-v2v-i-vmx.sh +new file mode 100755 +index 000000000..5353e7e2a +--- /dev/null ++++ b/v2v/test-v2v-i-vmx.sh +@@ -0,0 +1,48 @@ ++#!/bin/bash - ++# libguestfs virt-v2v test script ++# Copyright (C) 2017 Red Hat Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ ++# Test -i ova option. ++ ++set -e ++ ++$TEST_FUNCTIONS ++skip_if_skipped ++skip_if_backend uml ++ ++export VIRT_TOOLS_DATA_DIR="$top_srcdir/test-data/fake-virt-tools" ++export VIRTIO_WIN="$top_srcdir/test-data/fake-virtio-win" ++ ++rm -f test-v2v-i-vmx-*.actual ++ ++for i in 1 2 3 4; do ++ $VG virt-v2v --debug-gc \ ++ -i vmx test-v2v-i-vmx-$i.vmx \ ++ --print-source > test-v2v-i-vmx-$i.actual ++ ++ # Normalize the print-source output. ++ mv test-v2v-i-vmx-$i.actual test-v2v-i-vmx-$i.actual.old ++ sed \ ++ -e "s,$(pwd),," \ ++ < test-v2v-i-vmx-$i.actual.old > test-v2v-i-vmx-$i.actual ++ rm test-v2v-i-vmx-$i.actual.old ++ ++ # Check the output. ++ diff -u test-v2v-i-vmx-$i.expected test-v2v-i-vmx-$i.actual ++done ++ ++rm test-v2v-i-vmx-*.actual +diff --git a/v2v/v2v_unit_tests.ml b/v2v/v2v_unit_tests.ml +index 873610a7c..1b4332a9e 100644 +--- a/v2v/v2v_unit_tests.ml ++++ b/v2v/v2v_unit_tests.ml +@@ -787,6 +787,148 @@ let test_qemu_img_supports ctx = + *) + ignore (Utils.qemu_img_supports_offset_and_size ()) + ++(* Test the VMX file parser in the Parse_vmx module. *) ++let test_vmx_parse_string ctx = ++ let cmp = Parse_vmx.equal in ++ let printer = Parse_vmx.to_string 0 in ++ ++ (* This should be identical to the empty file. *) ++ let t = Parse_vmx.parse_string "\ ++test.foo = \"a\" ++test.bar = \"b\" ++test.present = \"FALSE\" ++" in ++ assert_equal ~cmp ~printer Parse_vmx.empty t; ++ ++ (* Test weird escapes. *) ++ let t1 = Parse_vmx.parse_string "\ ++foo = \"a|20|21b\" ++" in ++ let t2 = Parse_vmx.parse_string "\ ++foo = \"a !b\" ++" in ++ assert_equal ~cmp ~printer t1 t2; ++ ++ (* Test case insensitivity. *) ++ let t1 = Parse_vmx.parse_string "\ ++foo = \"abc\" ++" in ++ let t2 = Parse_vmx.parse_string "\ ++fOO = \"abc\" ++" in ++ assert_equal ~cmp ~printer t1 t2; ++ let t = Parse_vmx.parse_string "\ ++flag = \"true\" ++" in ++ assert_bool "parse_vmx: failed case insensitivity test for booleans #1" ++ (Parse_vmx.get_bool t ["FLAG"] = Some true); ++ let t = Parse_vmx.parse_string "\ ++flag = \"TRUE\" ++" in ++ assert_bool "parse_vmx: failed case insensitivity test for booleans #2" ++ (Parse_vmx.get_bool t ["Flag"] = Some true); ++ ++ (* Missing keys. *) ++ let t = Parse_vmx.parse_string "\ ++foo = \"a\" ++" in ++ assert_bool "parse_vmx: failed missing key test" ++ (Parse_vmx.get_string t ["bar"] = None); ++ ++ (* namespace_present function *) ++ let t = Parse_vmx.parse_string "\ ++foo.bar.present = \"TRUE\" ++foo.baz.present = \"FALSE\" ++foo.a.b = \"abc\" ++foo.a.c = \"abc\" ++foo.b = \"abc\" ++foo.c.a = \"abc\" ++foo.c.b = \"abc\" ++" in ++ assert_bool "parse_vmx: namespace_present #1" ++ (Parse_vmx.namespace_present t ["foo"] = true); ++ assert_bool "parse_vmx: namespace_present #2" ++ (Parse_vmx.namespace_present t ["foo"; "bar"] = true); ++ assert_bool "parse_vmx: namespace_present #3" ++ (* this whole namespace should have been culled *) ++ (Parse_vmx.namespace_present t ["foo"; "baz"] = false); ++ assert_bool "parse_vmx: namespace_present #4" ++ (Parse_vmx.namespace_present t ["foo"; "a"] = true); ++ assert_bool "parse_vmx: namespace_present #5" ++ (* this is a key, not a namespace *) ++ (Parse_vmx.namespace_present t ["foo"; "a"; "b"] = false); ++ assert_bool "parse_vmx: namespace_present #6" ++ (Parse_vmx.namespace_present t ["foo"; "b"] = false); ++ assert_bool "parse_vmx: namespace_present #7" ++ (Parse_vmx.namespace_present t ["foo"; "c"] = true); ++ assert_bool "parse_vmx: namespace_present #8" ++ (Parse_vmx.namespace_present t ["foo"; "d"] = false); ++ ++ (* map function *) ++ let t = Parse_vmx.parse_string "\ ++foo.bar.present = \"TRUE\" ++foo.baz.present = \"FALSE\" ++foo.a.b = \"abc\" ++foo.a.c = \"abc\" ++foo.b = \"abc\" ++foo.c.a = \"abc\" ++foo.c.b = \"abc\" ++" in ++ let xs = ++ Parse_vmx.map ( ++ fun path -> ++ let path = String.concat "." path in ++ function ++ | None -> sprintf "%s.present = \"true\"\n" path ++ | Some v -> sprintf "%s = \"%s\"\n" path v ++ ) t in ++ let xs = List.sort compare xs in ++ let s = String.concat "" xs in ++ assert_equal ~printer:identity "\ ++foo.a.b = \"abc\" ++foo.a.c = \"abc\" ++foo.a.present = \"true\" ++foo.b = \"abc\" ++foo.bar.present = \"TRUE\" ++foo.bar.present = \"true\" ++foo.c.a = \"abc\" ++foo.c.b = \"abc\" ++foo.c.present = \"true\" ++foo.present = \"true\" ++" s; ++ ++ (* select_namespaces function *) ++ let t1 = Parse_vmx.parse_string "\ ++foo.bar.present = \"TRUE\" ++foo.a.b = \"abc\" ++foo.a.c = \"abc\" ++foo.b = \"abc\" ++foo.c.a = \"abc\" ++foo.c.b = \"abc\" ++" in ++ let t2 = ++ Parse_vmx.select_namespaces ++ (function ["foo"] -> true | _ -> false) t1 in ++ assert_equal ~cmp ~printer t1 t2; ++ ++ let t1 = Parse_vmx.parse_string "\ ++foo.bar.present = \"TRUE\" ++foo.a.b = \"abc\" ++foo.a.c = \"abc\" ++foo.b = \"abc\" ++foo.c.a = \"abc\" ++foo.c.b = \"abc\" ++foo.c.c.d.e.f = \"abc\" ++" in ++ let t1 = ++ Parse_vmx.select_namespaces ++ (function ["foo"; "a"] -> true | _ -> false) t1 in ++ let t2 = Parse_vmx.parse_string "\ ++foo.a.b = \"abc\" ++foo.a.c = \"abc\" ++" in ++ assert_equal ~cmp ~printer t2 t1 ++ + (* Suites declaration. *) + let suite = + "virt-v2v" >::: +@@ -798,6 +940,7 @@ let suite = + test_virtio_iso_path_matches_guest_os; + "Utils.shell_unquote" >:: test_shell_unquote; + "Utils.qemu_img_supports" >:: test_qemu_img_supports; ++ "Parse_vmx.parse_string" >::test_vmx_parse_string; + ] + + let () = +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index 709075fba..7ed5c5d86 100644 +--- a/v2v/virt-v2v.pod ++++ b/v2v/virt-v2v.pod +@@ -41,7 +41,8 @@ libguestfs E 1.28. + ... ───▶│ (default) │ │ │ ──┐ └────────────┘ + └────────────┘ │ │ ─┐└──────▶ -o glance + -i libvirtxml ─────────▶ │ │ ┐└─────────▶ -o rhv +- └────────────┘ └──────────▶ -o vdsm ++ -i vmx ────────────────▶ │ │ └──────────▶ -o vdsm ++ └────────────┘ + + Virt-v2v has a number of possible input and output modes, selected + using the I<-i> and I<-o> options. Only one input and output mode can +@@ -60,6 +61,8 @@ method used by L behind the scenes. + + I<-i ova> is used for reading from a VMware ova source file. + ++I<-i vmx> is used for reading from a VMware vmx file. ++ + I<-o glance> is used for writing to OpenStack Glance. + + I<-o libvirt> is used for writing to any libvirt target. Libvirt can +@@ -228,6 +231,14 @@ ova manifest file and check the vmdk volumes for validity (checksums) + as well as analyzing the ovf file, and then convert the guest. See + L below + ++=item B<-i> B ++ ++Set the input method to I. ++ ++In this mode you can read a VMware vmx file directly. This is useful ++when VMware VMs are stored on an NFS server which you can mount ++directly. See L below ++ + =item B<-ic> libvirtURI + + Specify a libvirt connection URI to use when reading the guest. This +@@ -859,9 +870,10 @@ I<--bridge> option instead. For example: + + Virt-v2v is able to import guests from VMware vCenter Server. + +-vCenter E 5.0 is required. If you don't have vCenter, using OVA +-is recommended instead (see L below), or if +-that is not possible then see L. ++vCenter E 5.0 is required. If you don’t have vCenter, using OVA ++or VMX is recommended instead (see L and/or ++L below), or if that is not possible then see ++L. + + Virt-v2v uses libvirt for access to vCenter, and therefore the input + mode should be I<-i libvirt>. As this is the default, you don't need +@@ -1132,12 +1144,58 @@ directory containing the files: + + $ virt-v2v -i ova /path/to/files -o local -os /var/tmp + ++=head1 INPUT FROM VMWARE VMX ++ ++Virt-v2v is able to import guests from VMware’s vmx files. This is ++useful where VMware virtual machines are stored on a separate NFS ++server and you are able to mount the NFS storage directly. ++ ++If you find a folder of files called F.vmx>, ++F.vmxf>, F.nvram> and one or more F<.vmdk> disk ++images, then you can use this method. ++ ++=head2 VMX: REMOVE VMWARE TOOLS FROM WINDOWS GUESTS ++ ++For Windows guests, you should remove VMware tools before conversion. ++Although this is not strictly necessary, and the guest will still be ++able to run, if you don't do this then the converted guest will ++complain on every boot. The tools cannot be removed after conversion ++because the uninstaller checks if it is running on VMware and refuses ++to start (which is also the reason that virt-v2v cannot remove them). ++ ++This is not necessary for Linux guests, as virt-v2v is able to remove ++VMware tools. ++ ++=head2 VMX: GUEST MUST BE SHUT DOWN ++ ++B. If you don't ++shut it down, you will end up with a corrupted VM disk on the target. ++With other methods, virt-v2v tries to prevent concurrent access, but ++because the I<-i vmx> method works directly against the storage, ++checking for concurrent access is not possible. ++ ++=head2 VMX: MOUNT THE NFS STORAGE ON THE CONVERSION SERVER ++ ++Virt-v2v must be able to access the F<.vmx> file and any local ++F<.vmdk> disks. Normally this means you must mount the NFS storage ++containing these files. ++ ++=head2 VMX: IMPORTING A GUEST ++ ++To import a vmx file, do: ++ ++ $ virt-v2v -i vmx guest.vmx -o local -os /var/tmp ++ ++Virt-v2v processes the vmx file and uses it to find the location of ++any vmdk disks. ++ + =head1 INPUT FROM VMWARE ESXi HYPERVISOR + + Virt-v2v cannot access an ESXi hypervisor directly. You should use +-the OVA method above (see L) if possible, as +-it is much faster and requires much less disk space than the method +-described in this section. ++the OVA or VMX methods above (see L and/or ++L) if possible, as it is much faster and ++requires much less disk space than the method described in this ++section. + + You can use the L tool to copy the guest + off the hypervisor into a local file, and then convert it. +-- +2.14.3 + diff --git a/SOURCES/0031-p2v-tests-Fix-fake-scp-command-so-it-can-handle-mult.patch b/SOURCES/0031-p2v-tests-Fix-fake-scp-command-so-it-can-handle-mult.patch deleted file mode 100644 index 5227af2..0000000 --- a/SOURCES/0031-p2v-tests-Fix-fake-scp-command-so-it-can-handle-mult.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 2fd825ed1984d761697f0b8814c425e69ff31719 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 30 Mar 2017 19:34:29 +0100 -Subject: [PATCH] p2v: tests: Fix fake scp command so it can handle multiple - local files. - -Fixes commit d178deeeb814471b9d70431626b6cd515a21d0c1. - -(cherry picked from commit b417c877f4ea848af8f8538957ab677c65637027) ---- - p2v/test-virt-p2v-scp.sh | 16 ++++++++++------ - 1 file changed, 10 insertions(+), 6 deletions(-) - -diff --git a/p2v/test-virt-p2v-scp.sh b/p2v/test-virt-p2v-scp.sh -index c8a405db4..29900b663 100755 ---- a/p2v/test-virt-p2v-scp.sh -+++ b/p2v/test-virt-p2v-scp.sh -@@ -44,15 +44,19 @@ while true ; do - esac - done - --# Hopefully there are two arguments left, the source (local) file --# and a remote file of the form user@server:remote. --if [ $# -ne 2 ]; then -+# Hopefully there are >= two arguments left, the source (local) -+# file(s) and a remote file of the form user@server:remote. -+if [ $# -lt 2 ]; then - echo "$0: incorrect number of arguments found:" "$@" - exit 1 - fi - --local="$1" --remote="$(echo $2 | awk -F: '{print $2}')" -+# https://stackoverflow.com/questions/1853946/getting-the-last-argument-passed-to-a-shell-script/1854031#1854031 -+remote="${@: -1}" -+# https://stackoverflow.com/questions/20398499/remove-last-argument-from-argument-list-of-shell-script-bash/26163980#26163980 -+set -- "${@:1:$(($#-1))}" -+ -+remote="$(echo $remote | awk -F: '{print $2}')" - - # Use the copy command. --exec cp "$local" "$remote" -+exec cp "$@" "$remote" --- -2.13.4 - diff --git a/SOURCES/0031-v2v-tests-Fix-i-vmx-test-so-it-is-more-stable.patch b/SOURCES/0031-v2v-tests-Fix-i-vmx-test-so-it-is-more-stable.patch new file mode 100644 index 0000000..35078ba --- /dev/null +++ b/SOURCES/0031-v2v-tests-Fix-i-vmx-test-so-it-is-more-stable.patch @@ -0,0 +1,75 @@ +From f5ce5692f4701fc122af82759a790cfe01a18c35 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 12 Apr 2017 08:32:58 +0100 +Subject: [PATCH] v2v: tests: Fix -i vmx test so it is more stable. + +When running under valgrind, the process takes a fraction of a second +to start up, changing the "Opening the guest" timestamp, which broke +the test. + +Fixes commit ca40078cdda9167d4658ddfe24c828c7ee76be37. + +(cherry picked from commit ec61873d397f050fe28987f10ec919778d27818a) +--- + v2v/test-v2v-i-vmx-1.expected | 2 +- + v2v/test-v2v-i-vmx-2.expected | 2 +- + v2v/test-v2v-i-vmx-3.expected | 2 +- + v2v/test-v2v-i-vmx-4.expected | 2 +- + v2v/test-v2v-i-vmx.sh | 1 + + 5 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/v2v/test-v2v-i-vmx-1.expected b/v2v/test-v2v-i-vmx-1.expected +index c7ef1f5d5..128c34762 100644 +--- a/v2v/test-v2v-i-vmx-1.expected ++++ b/v2v/test-v2v-i-vmx-1.expected +@@ -1,4 +1,4 @@ +-[ 0.0] Opening the source -i vmx test-v2v-i-vmx-1.vmx ++ + Source guest information (--print-source option): + + source name: BZ1308535_21disks +diff --git a/v2v/test-v2v-i-vmx-2.expected b/v2v/test-v2v-i-vmx-2.expected +index a04bd0f62..7f3ee8154 100644 +--- a/v2v/test-v2v-i-vmx-2.expected ++++ b/v2v/test-v2v-i-vmx-2.expected +@@ -1,4 +1,4 @@ +-[ 0.0] Opening the source -i vmx test-v2v-i-vmx-2.vmx ++ + Source guest information (--print-source option): + + source name: Fedora 20 +diff --git a/v2v/test-v2v-i-vmx-3.expected b/v2v/test-v2v-i-vmx-3.expected +index 64808a77b..4664efdec 100644 +--- a/v2v/test-v2v-i-vmx-3.expected ++++ b/v2v/test-v2v-i-vmx-3.expected +@@ -1,4 +1,4 @@ +-[ 0.0] Opening the source -i vmx test-v2v-i-vmx-3.vmx ++ + Source guest information (--print-source option): + + source name: RHEL 7.1 UEFI +diff --git a/v2v/test-v2v-i-vmx-4.expected b/v2v/test-v2v-i-vmx-4.expected +index 208920b29..d6dcda5b6 100644 +--- a/v2v/test-v2v-i-vmx-4.expected ++++ b/v2v/test-v2v-i-vmx-4.expected +@@ -1,4 +1,4 @@ +-[ 0.0] Opening the source -i vmx test-v2v-i-vmx-4.vmx ++ + Source guest information (--print-source option): + + source name: Windows 7 x64 +diff --git a/v2v/test-v2v-i-vmx.sh b/v2v/test-v2v-i-vmx.sh +index 5353e7e2a..997103d41 100755 +--- a/v2v/test-v2v-i-vmx.sh ++++ b/v2v/test-v2v-i-vmx.sh +@@ -37,6 +37,7 @@ for i in 1 2 3 4; do + # Normalize the print-source output. + mv test-v2v-i-vmx-$i.actual test-v2v-i-vmx-$i.actual.old + sed \ ++ -e "s,.*Opening the source.*,," \ + -e "s,$(pwd),," \ + < test-v2v-i-vmx-$i.actual.old > test-v2v-i-vmx-$i.actual + rm test-v2v-i-vmx-$i.actual.old +-- +2.14.3 + diff --git a/SOURCES/0032-RHEL-7-v2v-disable-unconfig-of-manually-installed-VM.patch b/SOURCES/0032-RHEL-7-v2v-disable-unconfig-of-manually-installed-VM.patch new file mode 100644 index 0000000..251c462 --- /dev/null +++ b/SOURCES/0032-RHEL-7-v2v-disable-unconfig-of-manually-installed-VM.patch @@ -0,0 +1,36 @@ +From e70e7d95ed6130152186b88d9341c5c715cf29bf Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Mon, 14 Aug 2017 10:02:13 +0200 +Subject: [PATCH] RHEL 7: v2v: disable unconfig of manually installed VMware + tools (RHBZ#1477905) + +It looks like they may require connection to the VMware servers, which +is not always available during conversion. +--- + v2v/convert_linux.ml | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml +index 32e08fa30..cd8a20d31 100644 +--- a/v2v/convert_linux.ml ++++ b/v2v/convert_linux.ml +@@ -293,6 +293,7 @@ let rec convert (g : G.guestfs) inspect source output rcaps = + let remove = !remove in + Linux.remove g inspect remove; + ++(* + (* VMware Tools may have been installed from a tarball, so the + * above code won't remove it. Look for the uninstall tool and run + * if present. +@@ -314,6 +315,8 @@ let rec convert (g : G.guestfs) inspect source output rcaps = + warning (f_"VMware tools was detected, but uninstallation failed. The error message was: %s (ignored)") + msg + ) ++*) ++ () + + and unconfigure_citrix () = + let pkgs = +-- +2.14.3 + diff --git a/SOURCES/0032-v2v-windows-convert-fix-virtio-block-driver-installa.patch b/SOURCES/0032-v2v-windows-convert-fix-virtio-block-driver-installa.patch deleted file mode 100644 index 73059d6..0000000 --- a/SOURCES/0032-v2v-windows-convert-fix-virtio-block-driver-installa.patch +++ /dev/null @@ -1,39 +0,0 @@ -From e7359e9feac4fa2163a7259d093e381273365c8e Mon Sep 17 00:00:00 2001 -From: Pavel Butsykin -Date: Mon, 3 Apr 2017 19:44:45 +0300 -Subject: [PATCH] v2v: windows convert: fix virtio block driver installation - for w10/w2k16 - -This patch fixes the problem of the first boot after installation virtio block -drivers on Windows 10 / Server 2016. The problem is related to the change in -the behavior of Windows-Kernel-Pnp. To fix we need to add a field "Version" to -HKLM/SYSTEM/DriverDatabase/DriverPackages/drv_inf_label then Windows-Kernel-Pnp -will be able to correctly install the virtio block driver. - -Signed-off-by: Pavel Butsykin -(cherry picked from commit cc162b49e6c87bf3535168853dadf10f7610865f) ---- - v2v/windows_virtio.ml | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/v2v/windows_virtio.ml b/v2v/windows_virtio.ml -index 2f5349d25..965d6ac8b 100644 ---- a/v2v/windows_virtio.ml -+++ b/v2v/windows_virtio.ml -@@ -220,6 +220,13 @@ and ddb_regedits inspect drv_name drv_pciid = - [ "DriverDatabase"; "DeviceIds"; "PCI"; drv_pciid ], - [ drv_inf, REG_BINARY "\x01\xff\x00\x00" ]; - -+ [ "DriverDatabase"; "DriverPackages"; drv_inf_label ], -+ [ "Version", REG_BINARY ("\x00\xff\x09\x00\x00\x00\x00\x00" ^ -+ "\x7b\xe9\x36\x4d\x25\xe3\xce\x11" ^ -+ "\xbf\xc1\x08\x00\x2b\xe1\x03\x18" ^ -+ (String.make 24 '\x00')) ]; -+ (* Version is necessary for Windows-Kernel-Pnp in w10/w2k16 *) -+ - [ "DriverDatabase"; "DriverPackages"; drv_inf_label; - "Configurations"; drv_config ], - [ "ConfigFlags", REG_DWORD 0_l; --- -2.13.4 - diff --git a/SOURCES/0033-v2v-i-ova-Prefer-pigz-or-pxz-for-uncompressing-OVA-f.patch b/SOURCES/0033-v2v-i-ova-Prefer-pigz-or-pxz-for-uncompressing-OVA-f.patch new file mode 100644 index 0000000..f0ff572 --- /dev/null +++ b/SOURCES/0033-v2v-i-ova-Prefer-pigz-or-pxz-for-uncompressing-OVA-f.patch @@ -0,0 +1,42 @@ +From 3c4780cda6bfdd20d2a71857e326cc9cd2fd708c Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 8 May 2017 09:55:42 +0100 +Subject: [PATCH] v2v: -i ova: Prefer pigz or pxz for uncompressing OVA files + (RHBZ#1448739). + +If the parallel tools pigz or pxz are available, prefer them for +uncompressing gz- and xz-compressed OVA files respectively. If not +available then gzip or xz are used as normal. +--- + v2v/input_ova.ml | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml +index c91011873..69cdf576b 100644 +--- a/v2v/input_ova.ml ++++ b/v2v/input_ova.ml +@@ -40,9 +40,19 @@ let libvirt_supports_json_raw_driver () = + else + true + ++let pigz_available = ++ let test = lazy (shell_command "pigz --help >/dev/null 2>&1" = 0) in ++ fun () -> Lazy.force test ++ ++let pxz_available = ++ let test = lazy (shell_command "pxz --help >/dev/null 2>&1" = 0) in ++ fun () -> Lazy.force test ++ + let zcat_command_of_format = function +- | `GZip -> "gzip -c -d" +- | `XZ -> "xz -c -d" ++ | `GZip -> ++ if pigz_available () then "pigz -c -d" else "gzip -c -d" ++ | `XZ -> ++ if pxz_available () then "pxz -c -d" else "xz -c -d" + + (* Untar part or all files from tar archive. If [paths] is specified it is + * a list of paths in the tar archive. +-- +2.14.3 + diff --git a/SOURCES/0033-v2v-o-qemu-Fix-creation-of-ICH6-sound-device.patch b/SOURCES/0033-v2v-o-qemu-Fix-creation-of-ICH6-sound-device.patch deleted file mode 100644 index 1f9a86d..0000000 --- a/SOURCES/0033-v2v-o-qemu-Fix-creation-of-ICH6-sound-device.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 9b24787dab3d5dea740a1667f69bc75b763cf699 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 11 Apr 2017 12:16:51 +0100 -Subject: [PATCH] v2v: -o qemu: Fix creation of ICH6 sound device. - -Fixes commit f6ece2c01a9a1a43d6715103e7dbdda0f09ee862. - -(cherry picked from commit e562f52c95fe8eefdab778918d152335f56012c6) ---- - v2v/output_qemu.ml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/output_qemu.ml b/v2v/output_qemu.ml -index 84efd4529..abff29c2b 100644 ---- a/v2v/output_qemu.ml -+++ b/v2v/output_qemu.ml -@@ -183,7 +183,7 @@ object - match model with - | AC97 -> arg "-device" "AC97" - | ES1370 -> arg "-device" "ES1370" -- | ICH6 -> arg "-device" "intel-hda -device hda-duplex" -+ | ICH6 -> arg "-device" "intel-hda"; arg "-device" "hda-duplex" - | ICH9 -> arg "-device" "ich9-intel-hda" - | PCSpeaker -> arg "-soundhw" "pcspk" (* not qdev-ified *) - | SB16 -> arg "-device" "sb16" --- -2.13.4 - diff --git a/SOURCES/0034-ocaml-Add-Bytes.sub_string-function-to-Bytes-compat-.patch b/SOURCES/0034-ocaml-Add-Bytes.sub_string-function-to-Bytes-compat-.patch deleted file mode 100644 index 5a4730e..0000000 --- a/SOURCES/0034-ocaml-Add-Bytes.sub_string-function-to-Bytes-compat-.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 12d1057fba45b534d0cfbbcc900e5032e314b150 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 11 Apr 2017 08:29:47 +0100 -Subject: [PATCH] ocaml: Add Bytes.sub_string function to Bytes compat module. - -This is only used when OCaml < 4.02 (eg. RHEL 7). For more recent -versions the real Bytes.sub_string function is used instead. - -(cherry picked from commit bb846887de7a252204152c3e6df80d39a5ea33af) ---- - m4/guestfs_ocaml.m4 | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/m4/guestfs_ocaml.m4 b/m4/guestfs_ocaml.m4 -index 0479e70ab..d8bd89f00 100644 ---- a/m4/guestfs_ocaml.m4 -+++ b/m4/guestfs_ocaml.m4 -@@ -120,6 +120,7 @@ AS_IF([test "x$have_Bytes_module" = "xno"],[ - include String - let of_string = String.copy - let to_string = String.copy -+let sub_string = String.sub - EOF - ln -s ../generator/bytes.ml mllib/bytes.ml - OCAML_GENERATOR_BYTES_COMPAT_CMO='$(top_builddir)/generator/bytes.cmo' --- -2.13.4 - diff --git a/SOURCES/0034-v2v-add-crypto-support-RHBZ-1451665.patch b/SOURCES/0034-v2v-add-crypto-support-RHBZ-1451665.patch new file mode 100644 index 0000000..e741ccd --- /dev/null +++ b/SOURCES/0034-v2v-add-crypto-support-RHBZ-1451665.patch @@ -0,0 +1,87 @@ +From a8853952b43e15fd4aa287d235d8583782475531 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Mon, 22 May 2017 11:31:45 +0200 +Subject: [PATCH] v2v: add crypto support (RHBZ#1451665) + +Make use of the additional command line arguments, and API needed to +decrypt LUKS partitions. This extends to v2v the work done in other +OCaml tools with commit 6b26a0cce4f1d6264bee88902b8931e39288c901, +since it seems to be working fine after a basic testing. + +Related to: RHBZ#1362649 + +(cherry picked from commit 7e6c16f1e7698317991b875f2d7ab3ce9e94c8bb) +--- + v2v/cmdline.ml | 2 +- + v2v/v2v.ml | 3 +++ + v2v/virt-v2v.pod | 20 ++++++++++++++++++++ + 3 files changed, 24 insertions(+), 1 deletion(-) + +diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml +index db2346a38..6b105886c 100644 +--- a/v2v/cmdline.ml ++++ b/v2v/cmdline.ml +@@ -235,7 +235,7 @@ A short summary of the options is given below. For detailed help please + read the man page virt-v2v(1). + ") + prog in +- let opthandle = create_standard_options argspec ~anon_fun usage_msg in ++ let opthandle = create_standard_options argspec ~anon_fun ~key_opts:true usage_msg in + Getopt.parse opthandle; + + (* Dereference the arguments. *) +diff --git a/v2v/v2v.ml b/v2v/v2v.ml +index c1d412295..d03662c84 100644 +--- a/v2v/v2v.ml ++++ b/v2v/v2v.ml +@@ -90,6 +90,9 @@ let rec main () = + + g#launch (); + ++ (* Decrypt the disks. *) ++ inspect_decrypt g; ++ + (* Inspection - this also mounts up the filesystems. *) + (match conversion_mode with + | Copying _ -> message (f_"Inspecting the overlay") +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index 7ed5c5d86..77b6f514f 100644 +--- a/v2v/virt-v2v.pod ++++ b/v2v/virt-v2v.pod +@@ -191,6 +191,17 @@ Save the overlay file(s) created during conversion. This option is + only used for debugging virt-v2v and may be removed in a future + version. + ++=item B<--echo-keys> ++ ++When prompting for keys and passphrases, virt-v2v normally turns ++echoing off so you cannot see what you are typing. If you are not ++worried about Tempest attacks and there is no one else in the room you ++can specify this flag to see what you are typing. ++ ++Note this options only applies to keys and passphrases for encrypted ++devices and partitions, not for passwords used to connect to remote ++servers. ++ + =item B<-i> B + + Set the input method to I. +@@ -257,6 +268,15 @@ For I<-i disk> only, this specifies the format of the input disk + image. For other input methods you should specify the input + format in the metadata. + ++=item B<--keys-from-stdin> ++ ++Read key or passphrase parameters from stdin. The default is ++to try to read passphrases from the user by opening F. ++ ++Note this options only applies to keys and passphrases for encrypted ++devices and partitions, not for passwords used to connect to remote ++servers. ++ + =item B<--machine-readable> + + This option is used to make the output more machine friendly +-- +2.14.3 + diff --git a/SOURCES/0035-mllib-Add-Char.hexdigit-function.patch b/SOURCES/0035-mllib-Add-Char.hexdigit-function.patch deleted file mode 100644 index de1d233..0000000 --- a/SOURCES/0035-mllib-Add-Char.hexdigit-function.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0279339ee9a7b61ebcb3f64846d94f8171872737 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 11 Apr 2017 08:32:04 +0100 -Subject: [PATCH] mllib: Add Char.hexdigit function. - -Same as the function defined in fish/fish.c. - -(cherry picked from commit ef261d69ed199cc07474a36c890f63df461b35a7) ---- - mllib/common_utils.ml | 19 +++++++++++++++++++ - mllib/common_utils.mli | 4 ++++ - 2 files changed, 23 insertions(+) - -diff --git a/mllib/common_utils.ml b/mllib/common_utils.ml -index e1d63292e..4593614aa 100644 ---- a/mllib/common_utils.ml -+++ b/mllib/common_utils.ml -@@ -70,6 +70,25 @@ module Char = struct - | 'a'..'z' -> true - | 'A'..'Z' -> true - | _ -> false -+ -+ let hexdigit = function -+ | '0' -> 0 -+ | '1' -> 1 -+ | '2' -> 2 -+ | '3' -> 3 -+ | '4' -> 4 -+ | '5' -> 5 -+ | '6' -> 6 -+ | '7' -> 7 -+ | '8' -> 8 -+ | '9' -> 9 -+ | 'a' | 'A' -> 10 -+ | 'b' | 'B' -> 11 -+ | 'c' | 'C' -> 12 -+ | 'd' | 'D' -> 13 -+ | 'e' | 'E' -> 14 -+ | 'f' | 'F' -> 15 -+ | _ -> -1 - end - - module String = struct -diff --git a/mllib/common_utils.mli b/mllib/common_utils.mli -index 1cd38ba83..ec41a8ff8 100644 ---- a/mllib/common_utils.mli -+++ b/mllib/common_utils.mli -@@ -43,6 +43,10 @@ module Char : sig - (** Return true if the character is a US ASCII 7 bit alphabetic. *) - val isalnum : char -> bool - (** Return true if the character is a US ASCII 7 bit alphanumeric. *) -+ -+ val hexdigit : char -> int -+ (** Return the value of a hex digit. If the char is not in -+ the set [[0-9a-fA-F]] then this returns [-1]. *) - end - (** Override the Char module from stdlib. *) - --- -2.13.4 - diff --git a/SOURCES/0035-v2v-Implement-input-from-nbdkit-vddk-plugin-RHBZ-147.patch b/SOURCES/0035-v2v-Implement-input-from-nbdkit-vddk-plugin-RHBZ-147.patch new file mode 100644 index 0000000..0e2618a --- /dev/null +++ b/SOURCES/0035-v2v-Implement-input-from-nbdkit-vddk-plugin-RHBZ-147.patch @@ -0,0 +1,763 @@ +From 9542f12a306e05b73f5c4ecd4e4e61e03797098a Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 30 Aug 2017 17:14:03 +0100 +Subject: [PATCH] v2v: Implement input from nbdkit vddk plugin (RHBZ#1477912). + +(cherry picked from commit bbda5a6a68846acf971e0f4cbf83cacfa083d6e9) +--- + v2v/Makefile.am | 2 + + v2v/cmdline.ml | 53 +++++++- + v2v/input_libvirt.ml | 16 ++- + v2v/input_libvirt.mli | 8 +- + v2v/input_libvirt_vddk.ml | 314 +++++++++++++++++++++++++++++++++++++++++++++ + v2v/input_libvirt_vddk.mli | 24 ++++ + v2v/types.ml | 12 ++ + v2v/types.mli | 13 ++ + v2v/virt-v2v.pod | 155 ++++++++++++++++++++++ + 9 files changed, 588 insertions(+), 9 deletions(-) + create mode 100644 v2v/input_libvirt_vddk.ml + create mode 100644 v2v/input_libvirt_vddk.mli + +diff --git a/v2v/Makefile.am b/v2v/Makefile.am +index 0df759eca..87776a509 100644 +--- a/v2v/Makefile.am ++++ b/v2v/Makefile.am +@@ -35,6 +35,7 @@ SOURCES_MLI = \ + input_libvirt.mli \ + input_libvirt_other.mli \ + input_libvirt_vcenter_https.mli \ ++ input_libvirt_vddk.mli \ + input_libvirt_xen_ssh.mli \ + input_libvirtxml.mli \ + input_ova.mli \ +@@ -89,6 +90,7 @@ SOURCES_ML = \ + input_libvirtxml.ml \ + input_libvirt_other.ml \ + input_libvirt_vcenter_https.ml \ ++ input_libvirt_vddk.ml \ + input_libvirt_xen_ssh.ml \ + input_libvirt.ml \ + input_ova.ml \ +diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml +index 6b105886c..3050104d0 100644 +--- a/v2v/cmdline.ml ++++ b/v2v/cmdline.ml +@@ -63,6 +63,15 @@ let parse_cmdline () = + let output_name = ref None in + let output_storage = ref None in + let password_file = ref None in ++ let vddk = ref None in ++ let vddk_config = ref None in ++ let vddk_cookie = ref None in ++ let vddk_nfchostport = ref None in ++ let vddk_port = ref None in ++ let vddk_snapshot = ref None in ++ let vddk_thumbprint = ref None in ++ let vddk_transports = ref None in ++ let vddk_vimapiver = ref None in + let vdsm_vm_uuid = ref None in + let vdsm_ovf_output = ref None in (* default "." *) + +@@ -201,6 +210,24 @@ let parse_cmdline () = + s_"Use password from file"; + [ L"print-source" ], Getopt.Set print_source, s_"Print source and stop"; + [ L"root" ], Getopt.String ("ask|... ", set_root_choice), s_"How to choose root filesystem"; ++ [ L"vddk" ], Getopt.String ("libpath", set_string_option_once "--vddk" vddk), ++ s_"Use nbdkit VDDK plugin"; ++ [ L"vddk-config" ], Getopt.String ("filename", set_string_option_once "--vddk-config" vddk_config), ++ s_"Set VDDK config file"; ++ [ L"vddk-cookie" ], Getopt.String ("cookie", set_string_option_once "--vddk-cookie" vddk_cookie), ++ s_"Set VDDK cookie"; ++ [ L"vddk-nfchostport" ], Getopt.String ("nfchostport", set_string_option_once "--vddk-nfchostport" vddk_nfchostport), ++ s_"Set VDDK nfchostport"; ++ [ L"vddk-port" ], Getopt.String ("port", set_string_option_once "--vddk-port" vddk_port), ++ s_"Set VDDK port"; ++ [ L"vddk-snapshot" ], Getopt.String ("snapshot-moref", set_string_option_once "--vddk-snapshot" vddk_snapshot), ++ s_"Set VDDK snapshot"; ++ [ L"vddk-thumbprint" ], Getopt.String ("thumbprint", set_string_option_once "--vddk-thumbprint" vddk_thumbprint), ++ s_"Set VDDK thumbprint"; ++ [ L"vddk-transports" ], Getopt.String ("transports", set_string_option_once "--vddk-transports" vddk_transports), ++ s_"Set VDDK transports"; ++ [ L"vddk-vimapiver" ], Getopt.String ("apiver", set_string_option_once "--vddk-vimapiver" vddk_vimapiver), ++ s_"Set VDDK vimapiver"; + [ L"vdsm-compat" ], Getopt.Symbol ("0.10|1.1", ["0.10"; "1.1"], set_vdsm_compat), s_"Write qcow2 with compat=0.10|1.1"; + [ L"vdsm-image-uuid" ], Getopt.String ("uuid", add_vdsm_image_uuid), s_"Output image UUID(s)"; + [ L"vdsm-vol-uuid" ], Getopt.String ("uuid", add_vdsm_vol_uuid), s_"Output vol UUID(s)"; +@@ -263,6 +290,29 @@ read the man page virt-v2v(1). + let print_source = !print_source in + let qemu_boot = !qemu_boot in + let root_choice = !root_choice in ++ let vddk_options = ++ match !vddk with ++ | Some libdir -> ++ Some { vddk_libdir = libdir; ++ vddk_config = !vddk_config; ++ vddk_cookie = !vddk_cookie; ++ vddk_nfchostport = !vddk_nfchostport; ++ vddk_port = !vddk_port; ++ vddk_snapshot = !vddk_snapshot; ++ vddk_thumbprint = !vddk_thumbprint; ++ vddk_transports = !vddk_transports; ++ vddk_vimapiver = !vddk_vimapiver } ++ | None -> ++ if !vddk_config <> None || ++ !vddk_cookie <> None || ++ !vddk_nfchostport <> None || ++ !vddk_port <> None || ++ !vddk_snapshot <> None || ++ !vddk_thumbprint <> None || ++ !vddk_transports <> None || ++ !vddk_vimapiver <> None then ++ error (f_"‘--vddk-*’ options should only be used when conversion via the nbdkit VDDK plugin has been enabled, ie. using ‘--vddk’."); ++ None in + let vdsm_compat = !vdsm_compat in + let vdsm_image_uuids = List.rev !vdsm_image_uuids in + let vdsm_vol_uuids = List.rev !vdsm_vol_uuids in +@@ -278,6 +328,7 @@ read the man page virt-v2v(1). + printf "libguestfs-rewrite\n"; + printf "vcenter-https\n"; + printf "xen-ssh\n"; ++ printf "vddk\n"; + printf "colours-option\n"; + printf "vdsm-compat-option\n"; + List.iter (printf "input:%s\n") (Modules_list.input_modules ()); +@@ -316,7 +367,7 @@ read the man page virt-v2v(1). + | [guest] -> guest + | _ -> + error (f_"expecting a libvirt guest name on the command line") in +- Input_libvirt.input_libvirt dcpath password input_conn guest ++ Input_libvirt.input_libvirt dcpath vddk_options password input_conn guest + + | `LibvirtXML -> + (* -i libvirtxml: Expecting a filename (XML file). *) +diff --git a/v2v/input_libvirt.ml b/v2v/input_libvirt.ml +index 0bc386430..e8143b6ad 100644 +--- a/v2v/input_libvirt.ml ++++ b/v2v/input_libvirt.ml +@@ -27,7 +27,7 @@ open Types + open Utils + + (* Choose the right subclass based on the URI. *) +-let input_libvirt dcpath password libvirt_uri guest = ++let input_libvirt dcpath vddk_options password libvirt_uri guest = + match libvirt_uri with + | None -> + Input_libvirt_other.input_libvirt_other password libvirt_uri guest +@@ -47,10 +47,18 @@ let input_libvirt dcpath password libvirt_uri guest = + | Some _, Some "" -> + Input_libvirt_other.input_libvirt_other password libvirt_uri guest + +- (* vCenter over https *) ++ (* vCenter over https, or ++ * vCenter or ESXi using nbdkit vddk plugin ++ *) + | Some server, Some ("esx"|"gsx"|"vpx" as scheme) -> +- Input_libvirt_vcenter_https.input_libvirt_vcenter_https +- dcpath password libvirt_uri parsed_uri scheme server guest ++ (match vddk_options with ++ | None -> ++ Input_libvirt_vcenter_https.input_libvirt_vcenter_https ++ dcpath password libvirt_uri parsed_uri scheme server guest ++ | Some vddk_options -> ++ Input_libvirt_vddk.input_libvirt_vddk vddk_options password ++ libvirt_uri parsed_uri guest ++ ) + + (* Xen over SSH *) + | Some server, Some ("xen+ssh" as scheme) -> +diff --git a/v2v/input_libvirt.mli b/v2v/input_libvirt.mli +index f5e6314d9..0a6aa3c54 100644 +--- a/v2v/input_libvirt.mli ++++ b/v2v/input_libvirt.mli +@@ -18,7 +18,7 @@ + + (** [-i libvirt] source. *) + +-val input_libvirt : string option -> string option -> string option -> string -> Types.input +-(** [input_libvirt dcpath password libvirt_uri guest] creates and returns a +- new {!Types.input} object specialized for reading input from +- libvirt sources. *) ++val input_libvirt : string option -> Types.vddk_options option -> string option -> string option -> string -> Types.input ++(** [input_libvirt dcpath vddk_options password libvirt_uri guest] creates ++ and returns a new {!Types.input} object specialized for reading input ++ from libvirt sources. *) +diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml +new file mode 100644 +index 000000000..89d2552f6 +--- /dev/null ++++ b/v2v/input_libvirt_vddk.ml +@@ -0,0 +1,314 @@ ++(* virt-v2v ++ * Copyright (C) 2009-2017 Red Hat Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ *) ++ ++(** [-i libvirt] when the source is VMware via nbdkit vddk plugin *) ++ ++open Unix ++ ++open Common_gettext.Gettext ++open Common_utils ++open Unix_utils ++ ++open Types ++open Utils ++open Input_libvirt_other ++open Parse_libvirt_xml ++open Xpath_helpers ++ ++open Printf ++ ++(* Subclass specialized for handling VMware via nbdkit vddk plugin. *) ++class input_libvirt_vddk vddk_options password libvirt_uri parsed_uri guest = ++ ++ (* The VDDK path. *) ++ let libdir = vddk_options.vddk_libdir in ++ (* Compute the LD_LIBRARY_PATH that we must pass to nbdkit. *) ++ let library_path = libdir // sprintf "lib%d" Sys.word_size in ++ ++ (* Is SELinux enabled and enforcing on the host? *) ++ let have_selinux = ++ 0 = Sys.command "getenforce 2>/dev/null | grep -isq Enforcing" in ++ ++ (* Check that the VDDK path looks reasonable. *) ++ let error_unless_vddk_libdir () = ++ if not (is_directory libdir) then ++ error (f_"‘--vddk %s’ does not point to a directory. See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") libdir; ++ ++ if not (is_directory library_path) then ++ error (f_"VDDK library path %s not found or not a directory. See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") ++ library_path ++ in ++ ++ (* Check that nbdkit is available and new enough. *) ++ let error_unless_nbdkit_working () = ++ if 0 <> Sys.command "nbdkit --version >/dev/null" then ++ error (f_"nbdkit is not installed or not working. It is required to use ‘--vddk’. See \"INPUT FROM VDDK\" in the virt-v2v(1) manual."); ++ ++ (* Check it's a new enough version. The latest features we ++ * require are ‘--exit-with-parent’ and ‘--selinux-label’, both ++ * added in 1.1.14. ++ *) ++ let lines = external_command "nbdkit --help" in ++ let lines = String.concat " " lines in ++ if String.find lines "exit-with-parent" == -1 || ++ String.find lines "selinux-label" == -1 then ++ error (f_"nbdkit is not new enough, you need to upgrade to nbdkit ≥ 1.1.14") ++ in ++ ++ (* Check that the VDDK plugin is installed and working *) ++ let error_unless_nbdkit_vddk_working () = ++ let cmd = ++ sprintf "LD_LIBRARY_PATH=%s nbdkit vddk --dump-plugin >/dev/null" ++ (quote library_path) in ++ if Sys.command cmd <> 0 then ( ++ (* See if we can diagnose why ... *) ++ let cmd = ++ sprintf "LD_LIBRARY_PATH=%s LANG=C nbdkit vddk --dump-plugin 2>&1 | grep -sq libvixDiskLib.so" ++ (quote library_path) in ++ let needs_library = Sys.command cmd = 0 in ++ if not needs_library then ++ error (f_"nbdkit VDDK plugin is not installed or not working. It is required if you want to use VDDK. ++ ++The VDDK plugin is not enabled by default when you compile nbdkit. You have to read the instructions in the nbdkit sources under ‘plugins/vddk/README.VDDK’ to find out how to enable the VDDK plugin. ++ ++See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") ++ else ++ error (f_"nbdkit VDDK plugin is not installed or not working. It is required if you want to use VDDK. ++ ++It looks like you did not set the right path in the ‘--vddk’ option, or your copy of the VDDK directory is incomplete. There should be a library called ’%s/libvixDiskLib.so.?’. ++ ++See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") library_path ++ ) ++ in ++ ++ let error_unless_thumbprint () = ++ if vddk_options.vddk_thumbprint = None then ++ error (f_"You must pass the ‘--vddk-thumbprint’ option with the SSL thumbprint of the VMware server. To find the thumbprint, see the nbdkit-vddk-plugin(1) manual. See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") ++ in ++ ++object ++ inherit input_libvirt password libvirt_uri guest ++ ++ method source () = ++ error_unless_vddk_libdir (); ++ error_unless_nbdkit_working (); ++ error_unless_nbdkit_vddk_working (); ++ error_unless_thumbprint (); ++ ++ (* Get the libvirt XML. This also checks (as a side-effect) ++ * that the domain is not running. (RHBZ#1138586) ++ *) ++ let xml = Libvirt_utils.dumpxml ?password ?conn:libvirt_uri guest in ++ let source, disks = parse_libvirt_xml ?conn:libvirt_uri xml in ++ ++ (* Find the element from the XML. This was added ++ * in libvirt >= 3.7 and is required. ++ *) ++ let moref = ++ let doc = Xml.parse_memory xml in ++ let xpathctx = Xml.xpath_new_context doc in ++ Xml.xpath_register_ns xpathctx ++ "vmware" "http://libvirt.org/schemas/domain/vmware/1.0"; ++ let xpath_string = xpath_string xpathctx in ++ match xpath_string "/domain/vmware:moref" with ++ | Some moref -> moref ++ | None -> ++ error (f_" was not found in the output of ‘virsh dumpxml \"%s\"’. The most likely reason is that libvirt is too old, try upgrading libvirt to ≥ 3.7.") guest in ++ ++ (* Create a temporary directory where we place the sockets and ++ * password file. ++ *) ++ let tmpdir = ++ let base_dir = (open_guestfs ())#get_cachedir () in ++ let t = Mkdtemp.temp_dir ~base_dir "vddk." in ++ (* tmpdir must be readable (but not writable) by "other" so that ++ * qemu can open the sockets. If we place a password file in ++ * this directory then we'll chmod that to 0600 below. ++ *) ++ chmod t 0o755; ++ rmdir_on_exit t; ++ t in ++ ++ (* Start constructing the parts of the incredibly long nbdkit ++ * command line which don't change between disks. ++ *) ++ let args = ++ let add_arg, get_args = ++ let args = ref [] in ++ let add_arg a = push_front a args in ++ let get_args () = List.rev !args in ++ add_arg, get_args in ++ ++ (* It probably never happens that the server name can be missing ++ * from the libvirt URI, but we need a server name to pass to ++ * nbdkit, so ... ++ *) ++ let server = ++ match parsed_uri.Xml.uri_server with ++ | Some server -> server ++ | None -> ++ match libvirt_uri with ++ | Some libvirt_uri -> ++ error (f_"‘-ic %s’ URL does not contain a host name field") ++ libvirt_uri ++ | None -> ++ error (f_"you must use the ‘-ic’ parameter. See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") in ++ ++ (* Similar to above, we also need a username to pass. *) ++ let user = ++ match parsed_uri.Xml.uri_user with ++ | Some user -> user ++ | None -> "root" (* ? *) in ++ ++ add_arg "nbdkit"; ++ if verbose () then add_arg "--verbose"; ++ add_arg "--readonly"; (* important! readonly mode *) ++ add_arg "--foreground"; (* run in foreground *) ++ add_arg "--exit-with-parent"; (* exit when virt-v2v exits *) ++ add_arg "--newstyle"; (* use newstyle NBD protocol *) ++ add_arg "--exportname"; add_arg "/"; ++ if have_selinux then ( (* label the socket so qemu can open it *) ++ add_arg "--selinux-label"; add_arg "system_u:object_r:svirt_t:s0" ++ ); ++ ++ (* Name of the plugin. Everything following is a plugin parameter. *) ++ add_arg "vddk"; ++ ++ let password_param = ++ match password with ++ | None -> ++ (* nbdkit asks for the password interactively *) ++ "password=-" ++ | Some password -> ++ let password_file = tmpdir // "password" in ++ let chan = open_out password_file in ++ chmod password_file 0o600; ++ output_string chan password; ++ close_out chan; ++ (* nbdkit reads the password from the file *) ++ "password=+" ^ password_file in ++ add_arg (sprintf "server=%s" server); ++ add_arg (sprintf "user=%s" user); ++ add_arg password_param; ++ add_arg (sprintf "vm=moref=%s" moref); ++ add_arg (sprintf "libdir=%s" libdir); ++ ++ (* The passthrough parameters. *) ++ let pt name = may (fun field -> add_arg (sprintf "%s=%s" name field)) in ++ pt "config" vddk_options.vddk_config; ++ pt "cookie" vddk_options.vddk_cookie; ++ pt "nfchostport" vddk_options.vddk_nfchostport; ++ pt "port" vddk_options.vddk_port; ++ pt "snapshot" vddk_options.vddk_snapshot; ++ pt "thumbprint" vddk_options.vddk_thumbprint; ++ pt "transports" vddk_options.vddk_transports; ++ pt "vimapiver" vddk_options.vddk_vimapiver; ++ ++ get_args () in ++ ++ (* Create an nbdkit instance for each disk and rewrite the source ++ * paths to point to the NBD socket. ++ *) ++ let disks = List.map ( ++ function ++ | { p_source_disk = disk; p_source = P_dont_rewrite } -> ++ disk ++ ++ | { p_source = P_source_dev _ } -> (* Should never happen. *) ++ error (f_"source disk has attribute in XML") ++ ++ | { p_source_disk = disk; p_source = P_source_file path } -> ++ (* The attribute returned by the libvirt ++ * VMX driver looks like "[datastore] path". We can use it ++ * directly as the nbdkit file= parameter, and it is passed ++ * directly in this form to VDDK. ++ *) ++ ++ let sock = tmpdir // sprintf "nbdkit%d.sock" disk.s_disk_id in ++ let qemu_uri = sprintf "nbd:unix:%s:exportname=/" sock in ++ ++ let pidfile = tmpdir // sprintf "nbdkit%d.pid" disk.s_disk_id in ++ ++ (* Construct the final command line with the "static" args ++ * above plus the args which vary for each disk. ++ *) ++ let args = ++ args @ [ "--pidfile"; pidfile; ++ "--unix"; sock; ++ sprintf "file=%s" path ] in ++ let args = Array.of_list args in ++ ++ (* Start an nbdkit instance in the background. By using ++ * --exit-with-parent we don't have to worry about cleaning ++ * it up, hopefully. ++ *) ++ let pid = fork () in ++ if pid = 0 then ( ++ (* Child process (nbdkit). *) ++ putenv "LD_LIBRARY_PATH" library_path; ++ execvp "nbdkit" args ++ ); ++ ++ (* Wait for the pidfile to appear so we know that nbdkit ++ * is listening for requests. ++ *) ++ let rec loop i = ++ if i = 0 then false ++ else if Sys.file_exists pidfile then true ++ else ( ++ sleep 1; ++ loop (i-1) ++ ) ++ in ++ if not (loop 30) then ( ++ if verbose () then ++ error (f_"nbdkit did not start up. See previous debugging messages for problems.") ++ else ++ error (f_"nbdkit did not start up. There may be errors printed by nbdkit above. ++ ++If the messages above are not sufficient to diagnose the problem then add the ‘virt-v2v -v -x’ options and examine the debugging output carefully.") ++ ); ++ ++ if have_selinux then ( ++ (* Note that Unix domain sockets have both a file label and ++ * a socket/process label. Using --selinux-label above ++ * only set the socket label, but we must also set the file ++ * label. ++ *) ++ ignore ( ++ run_command ["chcon"; "system_u:object_r:svirt_image_t:s0"; ++ sock] ++ ); ++ ); ++ (* ... and the regular Unix permissions, in case qemu is ++ * running as another user. ++ *) ++ chmod sock 0o777; ++ ++ { disk with s_qemu_uri = qemu_uri } ++ ) disks in ++ ++ if verbose () then ( ++ eprintf "vddk: tmpdir %s:\n%!" tmpdir; ++ ignore (Sys.command (sprintf "ls -laZ %s" (quote tmpdir))) ++ ); ++ ++ { source with s_disks = disks } ++end ++ ++let input_libvirt_vddk = new input_libvirt_vddk +diff --git a/v2v/input_libvirt_vddk.mli b/v2v/input_libvirt_vddk.mli +new file mode 100644 +index 000000000..19a34c202 +--- /dev/null ++++ b/v2v/input_libvirt_vddk.mli +@@ -0,0 +1,24 @@ ++(* virt-v2v ++ * Copyright (C) 2017 Red Hat Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ *) ++ ++(** [-i libvirt] when the source is VMware via nbdkit vddk plugin *) ++ ++val input_libvirt_vddk : Types.vddk_options -> string option -> string option -> Xml.uri -> string -> Types.input ++(** [input_libvirt_vddk vddk_options password libvirt_uri parsed_uri guest] ++ creates and returns a {!Types.input} object specialized for reading ++ the guest disks using the nbdkit vddk plugin. *) +diff --git a/v2v/types.ml b/v2v/types.ml +index 3efb9ff46..4f9205aa0 100644 +--- a/v2v/types.ml ++++ b/v2v/types.ml +@@ -472,6 +472,18 @@ type root_choice = AskRoot | SingleRoot | FirstRoot | RootDev of string + + type output_allocation = Sparse | Preallocated + ++type vddk_options = { ++ vddk_libdir : string; ++ vddk_config : string option; ++ vddk_cookie : string option; ++ vddk_nfchostport : string option; ++ vddk_port : string option; ++ vddk_snapshot : string option; ++ vddk_thumbprint : string option; ++ vddk_transports : string option; ++ vddk_vimapiver : string option; ++} ++ + class virtual input = object + method precheck () = () + method virtual as_options : string +diff --git a/v2v/types.mli b/v2v/types.mli +index 2880546ae..087a03702 100644 +--- a/v2v/types.mli ++++ b/v2v/types.mli +@@ -328,6 +328,19 @@ type root_choice = AskRoot | SingleRoot | FirstRoot | RootDev of string + type output_allocation = Sparse | Preallocated + (** Type of [-oa] (output allocation) option. *) + ++type vddk_options = { ++ vddk_libdir : string; ++ vddk_config : string option; ++ vddk_cookie : string option; ++ vddk_nfchostport : string option; ++ vddk_port : string option; ++ vddk_snapshot : string option; ++ vddk_thumbprint : string option; ++ vddk_transports : string option; ++ vddk_vimapiver : string option; ++} ++(** Various options passed through to the nbdkit vddk plugin unmodified. *) ++ + (** {2 Input object} + + There is one of these used for the [-i] option. *) +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index 77b6f514f..d713d0b1f 100644 +--- a/v2v/virt-v2v.pod ++++ b/v2v/virt-v2v.pod +@@ -514,6 +514,35 @@ boot an operating system from the first VirtIO disk. Specifically, + F must be on the first VirtIO disk, and it cannot chainload an + OS which is not in the first VirtIO disk. + ++=item B<--vddk> LIBDIR ++ ++Enable VDDK input from VMware vCenter or ESXi. C is the top ++directory of the VDDK library. This directory should I ++subdirectories called F, F etc., but do not include ++F actually in the parameter. ++ ++See L below for details. ++ ++=item B<--vddk-config> FILENAME ++ ++=item B<--vddk-cookie> COOKIE ++ ++=item B<--vddk-nfchostport> PORT ++ ++=item B<--vddk-port> PORT ++ ++=item B<--vddk-snapshot> SNAPSHOT-MOREF ++ ++=item B<--vddk-thumbprint> xx:xx:xx:... ++ ++=item B<--vddk-transports> MODE:MODE:... ++ ++=item B<--vddk-vimapiver> APIVER ++ ++When using VDDK mode, these options are passed unmodified to the ++L VDDK plugin. Please refer to L. ++Only I<--vddk-thumbprint> is required, the others are optional. ++ + =item B<--vdsm-compat=0.10> + + =item B<--vdsm-compat=1.1> +@@ -1270,6 +1299,130 @@ Perform the conversion of the guest using virt-v2v: + + Remove the F and F files. + ++=head1 INPUT FROM VDDK ++ ++Virt-v2v is able to import guests using VMware’s proprietary VDDK ++library (a.k.a. VixDiskLib). ++ ++=head2 VDDK: PREREQUISITES ++ ++=over 4 ++ ++=item 1. ++ ++As the VDDK library is not open source, and the license of this ++library does not permit redistribution or commercial use, you must ++obtain VDDK yourself and satisfy yourself that your usage of the ++library is permitted by the license. ++ ++=item 2. ++ ++You must also compile nbdkit, enabling the VDDK plugin. At least ++nbdkit E 1.1.14 is required, but it is usually best to compile ++from the git tree. ++ ++=over 4 ++ ++=item * ++ ++L ++ ++=item * ++ ++L ++ ++=back ++ ++=item 3. ++ ++You can run nbdkit from its source directory without needing to ++install it. Set C<$PATH> to include the nbdkit top build directory ++(the directory containing a shell script called F): ++ ++ export PATH=/path/to/nbdkit:$PATH ++ ++=item 4. ++ ++You must find the SSL "thumbprint" of your VMware server. How to do ++this is explained in L, also available at the ++link given in item 2 above. ++ ++=item 5. ++ ++VDDK imports require a feature added in libvirt E 3.7. ++ ++=back ++ ++=head2 VDDK: URI ++ ++Construct the correct C (for vCenter) or C (for ESXi) ++URL. It will look something like these: ++ ++ vpx://root@vcenter.example.com/Datacenter/esxi ++ ++ esx://root@esxi.example.com ++ ++To verify that you have the correct URL, use the L command ++to list the guests on the server: ++ ++ $ virsh -c 'vpx://root@vcenter.example.com/Datacenter/esxi' list --all ++ Enter root's password for vcenter.example.com: *** ++ ++ Id Name State ++ ---------------------------------------------------- ++ - Fedora 20 shut off ++ - Windows 2003 shut off ++ ++If you get an error "Peer certificate cannot be authenticated with ++given CA certificates" or similar, then you can either import the ++vCenter host’s certificate, or bypass signature verification by adding ++the C flag: ++ ++ $ virsh -c 'vpx://root@vcenter.example.com/Datacenter/esxi?no_verify=1' list --all ++ ++You should also try dumping the metadata from any guest on your ++server, like this: ++ ++ $ virsh -c 'vpx://root@vcenter.example.com/Datacenter/esxi' dumpxml "Windows 2003" ++ ++ Windows 2003 ++ [...] ++ vm-123 ++ ++ ++If Cvmware:morefE> does not appear in the metadata, then you ++need to upgrade libvirt. ++ ++B. Fix your URI and/or your VMware server before ++continuing. ++ ++=head2 VDDK: IMPORTING A GUEST ++ ++To import a particular guest from vCenter server or ESXi hypervisor, ++use a command like the following, substituting the URI, guest name and ++SSL thumbprint: ++ ++ $ export PATH=/path/to/nbdkit:$PATH ++ $ virt-v2v \ ++ -ic 'vpx://root@vcenter.example.com/Datacenter/esxi?no_verify=1' \ ++ --vddk /path/to/vmware-vix-disklib-distrib \ ++ --vddk-thumbprint xx:xx:xx:... \ ++ "Windows 2003" \ ++ -o local -os /var/tmp ++ ++Other options that you might need to add in rare circumstances include ++I<--vddk-config>, I<--vddk-cookie>, I<--vddk-nfchostport>, ++I<--vddk-port>, I<--vddk-snapshot>, I<--vddk-transports> and ++I<--vddk-vimapiver>, which are all explained in the ++L documentation. ++ ++=head2 VDDK: DEBUGGING VDDK FAILURES ++ ++The VDDK library can be operated in a verbose mode where it gives ++(very) verbose messages. Use ‘virt-v2v -v -x’ as usual to enable ++verbose messages. ++ + =head1 INPUT FROM XEN + + Virt-v2v is able to import Xen guests from RHEL 5 Xen hosts. +@@ -2032,6 +2185,8 @@ L, + L, + L, + L, ++L, ++L, + L. + + =head1 AUTHORS +-- +2.14.3 + diff --git a/SOURCES/0036-s390x-launch-libvirt-Use-console-device-sclp-for-app.patch b/SOURCES/0036-s390x-launch-libvirt-Use-console-device-sclp-for-app.patch new file mode 100644 index 0000000..e149135 --- /dev/null +++ b/SOURCES/0036-s390x-launch-libvirt-Use-console-device-sclp-for-app.patch @@ -0,0 +1,50 @@ +From c73e6d1e2dcbcf2c7b17096953e48bc5a84ee7d2 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 16 May 2017 20:12:54 +0200 +Subject: [PATCH] s390x: launch: libvirt: Use device sclp for + appliance debug messages (RHBZ#1376547). + +Thanks: Cole Robinson, Dan Horak, Thomas Huth. +(cherry picked from commit 6328f332361675abb0233db890d2bfe0d9a5092a) +--- + lib/launch-libvirt.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c +index 681281b9b..49bd40583 100644 +--- a/lib/launch-libvirt.c ++++ b/lib/launch-libvirt.c +@@ -1347,6 +1347,7 @@ construct_libvirt_xml_devices (guestfs_h *g, + return -1; + } + ++#ifndef __s390x__ + /* Console. */ + start_element ("serial") { + attribute ("type", "unix"); +@@ -1358,6 +1359,22 @@ construct_libvirt_xml_devices (guestfs_h *g, + attribute ("port", "0"); + } end_element (); + } end_element (); ++#else ++ /* https://bugzilla.redhat.com/show_bug.cgi?id=1376547#c14 ++ * and https://libvirt.org/formatdomain.html#elementCharConsole ++ */ ++ start_element ("console") { ++ attribute ("type", "unix"); ++ start_element ("source") { ++ attribute ("mode", "connect"); ++ attribute ("path", params->data->console_path); ++ } end_element (); ++ start_element ("target") { ++ attribute ("type", "sclp"); ++ attribute ("port", "0"); ++ } end_element (); ++ } end_element (); ++#endif + + /* Virtio-serial for guestfsd communication. */ + start_element ("channel") { +-- +2.14.3 + diff --git a/SOURCES/0036-v2v-Implement-i-vmx-to-read-VMware-vmx-files-directl.patch b/SOURCES/0036-v2v-Implement-i-vmx-to-read-VMware-vmx-files-directl.patch deleted file mode 100644 index ec063d5..0000000 --- a/SOURCES/0036-v2v-Implement-i-vmx-to-read-VMware-vmx-files-directl.patch +++ /dev/null @@ -1,1954 +0,0 @@ -From 79c0796259820d1ee49bf442392bc3cc5d82322d Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 10 Apr 2017 15:24:26 +0100 -Subject: [PATCH] v2v: Implement -i vmx to read VMware vmx files directly - (RHBZ#1441197). - -This is a mostly complete implementation of a VMX parser and input -class for virt-v2v. It parses the name, memory size, CPU topology, -firmware, video, sound, hard disks, removable disks and network -interfaces from the VMX file. It only omits support for floppies and -SCSI CD-ROMs. - -The input class is split into two major parts: a generic VMX file -parser (Parse_vmx), and the Input_vmx module which translates the VMX -tree into the source device model. - -This also contains tests. There are simple unit tests of the -Parse_vmx module, and also some more complete parsing tests taken from -real guests. - -(cherry picked from commit ca40078cdda9167d4658ddfe24c828c7ee76be37) ---- - v2v/Makefile.am | 15 ++ - v2v/cmdline.ml | 12 +- - v2v/input_vmx.ml | 349 ++++++++++++++++++++++++++++++++++++++ - v2v/input_vmx.mli | 22 +++ - v2v/name_from_disk.ml | 2 +- - v2v/parse_vmx.ml | 381 ++++++++++++++++++++++++++++++++++++++++++ - v2v/parse_vmx.mli | 89 ++++++++++ - v2v/test-v2v-i-vmx-1.expected | 42 +++++ - v2v/test-v2v-i-vmx-1.vmx | 172 +++++++++++++++++++ - v2v/test-v2v-i-vmx-2.expected | 22 +++ - v2v/test-v2v-i-vmx-2.vmx | 84 ++++++++++ - v2v/test-v2v-i-vmx-3.expected | 22 +++ - v2v/test-v2v-i-vmx-3.vmx | 91 ++++++++++ - v2v/test-v2v-i-vmx-4.expected | 22 +++ - v2v/test-v2v-i-vmx-4.vmx | 88 ++++++++++ - v2v/test-v2v-i-vmx.sh | 48 ++++++ - v2v/v2v_unit_tests.ml | 143 ++++++++++++++++ - v2v/virt-v2v.pod | 72 +++++++- - 18 files changed, 1667 insertions(+), 9 deletions(-) - create mode 100644 v2v/input_vmx.ml - create mode 100644 v2v/input_vmx.mli - create mode 100644 v2v/parse_vmx.ml - create mode 100644 v2v/parse_vmx.mli - create mode 100644 v2v/test-v2v-i-vmx-1.expected - create mode 100644 v2v/test-v2v-i-vmx-1.vmx - create mode 100644 v2v/test-v2v-i-vmx-2.expected - create mode 100644 v2v/test-v2v-i-vmx-2.vmx - create mode 100644 v2v/test-v2v-i-vmx-3.expected - create mode 100644 v2v/test-v2v-i-vmx-3.vmx - create mode 100644 v2v/test-v2v-i-vmx-4.expected - create mode 100644 v2v/test-v2v-i-vmx-4.vmx - create mode 100755 v2v/test-v2v-i-vmx.sh - -diff --git a/v2v/Makefile.am b/v2v/Makefile.am -index 297406496..0df759eca 100644 ---- a/v2v/Makefile.am -+++ b/v2v/Makefile.am -@@ -38,6 +38,7 @@ SOURCES_MLI = \ - input_libvirt_xen_ssh.mli \ - input_libvirtxml.mli \ - input_ova.mli \ -+ input_vmx.mli \ - inspect_source.mli \ - libvirt_utils.mli \ - linux.mli \ -@@ -55,6 +56,7 @@ SOURCES_MLI = \ - OVF.mli \ - parse_ovf_from_ova.mli \ - parse_libvirt_xml.mli \ -+ parse_vmx.mli \ - qemu_command.mli \ - target_bus_assignment.mli \ - types.mli \ -@@ -80,6 +82,7 @@ SOURCES_ML = \ - windows_virtio.ml \ - modules_list.ml \ - input_disk.ml \ -+ parse_vmx.ml \ - parse_libvirt_xml.ml \ - create_libvirt_xml.ml \ - qemu_command.ml \ -@@ -89,6 +92,7 @@ SOURCES_ML = \ - input_libvirt_xen_ssh.ml \ - input_libvirt.ml \ - input_ova.ml \ -+ input_vmx.ml \ - linux_bootloaders.ml \ - linux_kernels.ml \ - convert_linux.ml \ -@@ -268,6 +272,7 @@ TESTS = \ - test-v2v-i-ova-subfolders.sh \ - test-v2v-i-ova-tar.sh \ - test-v2v-i-ova-two-disks.sh \ -+ test-v2v-i-vmx.sh \ - test-v2v-bad-networks-and-bridges.sh - - if HAVE_LIBVIRT -@@ -411,6 +416,15 @@ EXTRA_DIST += \ - test-v2v-i-ova.ovf \ - test-v2v-i-ova.sh \ - test-v2v-i-ova.xml \ -+ test-v2v-i-vmx.sh \ -+ test-v2v-i-vmx-1.expected \ -+ test-v2v-i-vmx-2.expected \ -+ test-v2v-i-vmx-3.expected \ -+ test-v2v-i-vmx-4.expected \ -+ test-v2v-i-vmx-1.vmx \ -+ test-v2v-i-vmx-2.vmx \ -+ test-v2v-i-vmx-3.vmx \ -+ test-v2v-i-vmx-4.vmx \ - test-v2v-machine-readable.sh \ - test-v2v-networks-and-bridges-expected.xml \ - test-v2v-networks-and-bridges.sh \ -@@ -450,6 +464,7 @@ v2v_unit_tests_BOBJECTS = \ - windows.cmo \ - windows_virtio.cmo \ - linux.cmo \ -+ parse_vmx.cmo \ - v2v_unit_tests.cmo - v2v_unit_tests_XOBJECTS = $(v2v_unit_tests_BOBJECTS:.cmo=.cmx) - -diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml -index a2f132b6c..0850f9136 100644 ---- a/v2v/cmdline.ml -+++ b/v2v/cmdline.ml -@@ -86,6 +86,7 @@ let parse_cmdline () = - | "libvirt" -> input_mode := `Libvirt - | "libvirtxml" -> input_mode := `LibvirtXML - | "ova" -> input_mode := `OVA -+ | "vmx" -> input_mode := `VMX - | s -> - error (f_"unknown -i option: %s") s - in -@@ -331,7 +332,16 @@ read the man page virt-v2v(1). - | [filename] -> filename - | _ -> - error (f_"expecting an OVA file name on the command line") in -- Input_ova.input_ova filename in -+ Input_ova.input_ova filename -+ -+ | `VMX -> -+ (* -i vmx: Expecting an vmx filename. *) -+ let filename = -+ match args with -+ | [filename] -> filename -+ | _ -> -+ error (f_"expecting a VMX file name on the command line") in -+ Input_vmx.input_vmx filename in - - (* Prevent use of --in-place option in RHEL. *) - if in_place then -diff --git a/v2v/input_vmx.ml b/v2v/input_vmx.ml -new file mode 100644 -index 000000000..bb09f0bf8 ---- /dev/null -+++ b/v2v/input_vmx.ml -@@ -0,0 +1,349 @@ -+(* virt-v2v -+ * Copyright (C) 2017 Red Hat Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ *) -+ -+open Printf -+open Scanf -+ -+open Common_gettext.Gettext -+open Common_utils -+ -+open Types -+open Utils -+open Name_from_disk -+ -+external identity : 'a -> 'a = "%identity" -+ -+let rec find_disks vmx vmx_filename = -+ find_scsi_disks vmx vmx_filename @ find_ide_disks vmx vmx_filename -+ -+(* Find all SCSI hard disks. -+ * -+ * In the VMX file: -+ * scsi0.virtualDev = "pvscsi" # or may be "lsilogic" etc. -+ * scsi0:0.deviceType = "scsi-hardDisk" -+ * scsi0:0.fileName = "guest.vmdk" -+ *) -+and find_scsi_disks vmx vmx_filename = -+ let get_scsi_controller_target ns = -+ sscanf ns "scsi%d:%d" (fun c t -> c, t) -+ in -+ let is_scsi_controller_target ns = -+ try ignore (get_scsi_controller_target ns); true -+ with Scanf.Scan_failure _ | End_of_file | Failure _ -> false -+ in -+ let scsi_device_types = [ "scsi-harddisk" ] in -+ let scsi_controller = Source_SCSI in -+ -+ find_hdds vmx vmx_filename -+ get_scsi_controller_target is_scsi_controller_target -+ scsi_device_types scsi_controller -+ -+(* Find all IDE hard disks. -+ * -+ * In the VMX file: -+ * ide0:0.deviceType = "ata-hardDisk" -+ * ide0:0.fileName = "guest.vmdk" -+ *) -+and find_ide_disks vmx vmx_filename = -+ let get_ide_controller_target ns = -+ sscanf ns "ide%d:%d" (fun c t -> c, t) -+ in -+ let is_ide_controller_target ns = -+ try ignore (get_ide_controller_target ns); true -+ with Scanf.Scan_failure _ | End_of_file | Failure _ -> false -+ in -+ let ide_device_types = [ "ata-harddisk" ] in -+ let ide_controller = Source_IDE in -+ -+ find_hdds vmx vmx_filename -+ get_ide_controller_target is_ide_controller_target -+ ide_device_types ide_controller -+ -+and find_hdds vmx vmx_filename -+ get_controller_target is_controller_target -+ device_types controller = -+ (* Find namespaces matching '(ide|scsi)X:Y' with suitable deviceType. *) -+ let hdds = -+ Parse_vmx.select_namespaces ( -+ function -+ | [ns] -> -+ (* Check the namespace is '(ide|scsi)X:Y' *) -+ if not (is_controller_target ns) then false -+ else ( -+ (* Check the deviceType is one we are looking for. *) -+ match Parse_vmx.get_string vmx [ns; "deviceType"] with -+ | Some str -> -+ let str = String.lowercase_ascii str in -+ List.mem str device_types -+ | None -> false -+ ) -+ | _ -> false -+ ) vmx in -+ -+ (* Map the subset to a list of disks. *) -+ let hdds = -+ Parse_vmx.map ( -+ fun path v -> -+ match path, v with -+ | [ns; "filename"], Some filename -> -+ let c, t = get_controller_target ns in -+ let s = { s_disk_id = (-1); -+ s_qemu_uri = qemu_uri_of_filename vmx_filename filename; -+ s_format = Some "vmdk"; -+ s_controller = Some controller } in -+ Some (c, t, s) -+ | _ -> None -+ ) hdds in -+ let hdds = filter_map identity hdds in -+ -+ (* We don't have a way to return the controllers and targets, so -+ * just make sure the disks are sorted into order, since Parse_vmx -+ * won't return them in any particular order. -+ *) -+ let hdds = List.sort compare hdds in -+ let hdds = List.map (fun (_, _, source) -> source) hdds in -+ -+ (* Set the s_disk_id field to an incrementing number. *) -+ let hdds = mapi (fun i source -> { source with s_disk_id = i }) hdds in -+ -+ hdds -+ -+(* The filename can be an absolute path, but is more often a -+ * path relative to the location of the vmx file. -+ * -+ * Note that we always end up with an absolute path, which is -+ * also useful because it means we won't have any paths that -+ * could be misinterpreted by qemu. -+ *) -+and qemu_uri_of_filename vmx_filename filename = -+ if not (Filename.is_relative filename) then -+ filename -+ else ( -+ let dir = Filename.dirname (absolute_path vmx_filename) in -+ dir // filename -+ ) -+ -+(* Find all removable disks. -+ * -+ * In the VMX file: -+ * ide1:0.deviceType = "cdrom-image" -+ * ide1:0.fileName = "boot.iso" -+ * -+ * XXX This only supports IDE CD-ROMs, but we could support SCSI -+ * CD-ROMs and floppies in future. -+ *) -+and find_removables vmx = -+ let get_ide_controller_target ns = -+ sscanf ns "ide%d:%d" (fun c t -> c, t) -+ in -+ let is_ide_controller_target ns = -+ try ignore (get_ide_controller_target ns); true -+ with Scanf.Scan_failure _ | End_of_file | Failure _ -> false -+ in -+ let device_types = [ "atapi-cdrom"; -+ "cdrom-image"; "cdrom-raw" ] in -+ -+ (* Find namespaces matching 'ideX:Y' with suitable deviceType. *) -+ let devs = -+ Parse_vmx.select_namespaces ( -+ function -+ | [ns] -> -+ (* Check the namespace is 'ideX:Y' *) -+ if not (is_ide_controller_target ns) then false -+ else ( -+ (* Check the deviceType is one we are looking for. *) -+ match Parse_vmx.get_string vmx [ns; "deviceType"] with -+ | Some str -> -+ let str = String.lowercase_ascii str in -+ List.mem str device_types -+ | None -> false -+ ) -+ | _ -> false -+ ) vmx in -+ -+ (* Map the subset to a list of CD-ROMs. *) -+ let devs = -+ Parse_vmx.map ( -+ fun path v -> -+ match path, v with -+ | [ns], None -> -+ let c, t = get_ide_controller_target ns in -+ let s = { s_removable_type = CDROM; -+ s_removable_controller = Some Source_IDE; -+ s_removable_slot = Some (ide_slot c t) } in -+ Some s -+ | _ -> None -+ ) devs in -+ let devs = filter_map identity devs in -+ -+ (* Sort by slot. *) -+ let devs = -+ List.sort -+ (fun { s_removable_slot = s1 } { s_removable_slot = s2 } -> -+ compare s1 s2) -+ devs in -+ -+ devs -+ -+and ide_slot c t = -+ (* Assuming the old master/slave arrangement. *) -+ c * 2 + t -+ -+(* Find all ethernet cards. -+ * -+ * In the VMX file: -+ * ethernet0.virtualDev = "vmxnet3" -+ * ethernet0.networkName = "VM Network" -+ * ethernet0.generatedAddress = "00:01:02:03:04:05" -+ * ethernet0.connectionType = "bridged" # also: "custom", "nat" or not present -+ *) -+and find_nics vmx = -+ let get_ethernet_port ns = -+ sscanf ns "ethernet%d" (fun p -> p) -+ in -+ let is_ethernet_port ns = -+ try ignore (get_ethernet_port ns); true -+ with Scanf.Scan_failure _ | End_of_file | Failure _ -> false -+ in -+ -+ (* Find namespaces matching 'ethernetX'. *) -+ let nics = -+ Parse_vmx.select_namespaces ( -+ function -+ | [ns] -> is_ethernet_port ns -+ | _ -> false -+ ) vmx in -+ -+ (* Map the subset to a list of NICs. *) -+ let nics = -+ Parse_vmx.map ( -+ fun path v -> -+ match path, v with -+ | [ns], None -> -+ let port = get_ethernet_port ns in -+ let mac = Parse_vmx.get_string vmx [ns; "generatedAddress"] in -+ let model = Parse_vmx.get_string vmx [ns; "virtualDev"] in -+ let model = -+ match model with -+ | Some m when String.lowercase_ascii m = "e1000" -> -+ Some Source_e1000 -+ | Some model -> -+ Some (Source_other_nic (String.lowercase_ascii model)) -+ | None -> None in -+ let vnet = Parse_vmx.get_string vmx [ns; "networkName"] in -+ let vnet = -+ match vnet with -+ | Some vnet -> vnet -+ | None -> ns (* "ethernetX" *) in -+ let vnet_type = -+ match Parse_vmx.get_string vmx [ns; "connectionType"] with -+ | Some b when String.lowercase_ascii b = "bridged" -> -+ Bridge -+ | Some _ | None -> Network in -+ Some (port, -+ { s_mac = mac; s_nic_model = model; -+ s_vnet = vnet; s_vnet_orig = vnet; -+ s_vnet_type = vnet_type }) -+ | _ -> None -+ ) nics in -+ let nics = filter_map identity nics in -+ -+ (* Sort by port. *) -+ let nics = List.sort compare nics in -+ -+ let nics = List.map (fun (_, source) -> source) nics in -+ nics -+ -+class input_vmx vmx_filename = object -+ inherit input -+ -+ method as_options = "-i vmx " ^ vmx_filename -+ -+ method source () = -+ (* Parse the VMX file. *) -+ let vmx = Parse_vmx.parse_file vmx_filename in -+ -+ let name = -+ match Parse_vmx.get_string vmx ["displayName"] with -+ | None -> -+ warning (f_"no displayName key found in VMX file"); -+ name_from_disk vmx_filename -+ | Some s -> s in -+ -+ let memory_mb = -+ match Parse_vmx.get_int64 vmx ["memSize"] with -+ | None -> 32_L (* default is really 32 MB! *) -+ | Some i -> i in -+ let memory = memory_mb *^ 1024L *^ 1024L in -+ -+ let vcpu = -+ match Parse_vmx.get_int vmx ["numvcpus"] with -+ | None -> 1 -+ | Some i -> i in -+ -+ let firmware = -+ match Parse_vmx.get_string vmx ["firmware"] with -+ | None -> BIOS -+ | Some "efi" -> UEFI -+ (* Other values are not documented for this field ... *) -+ | Some fw -> -+ warning (f_"unknown firmware value '%s', assuming BIOS") fw; -+ BIOS in -+ -+ let video = -+ if Parse_vmx.namespace_present vmx ["svga"] then -+ (* We could also parse svga.vramSize. *) -+ Some (Source_other_video "vmvga") -+ else -+ None in -+ -+ let sound = -+ match Parse_vmx.get_string vmx ["sound"; "virtualDev"] with -+ | Some ("sb16") -> Some { s_sound_model = SB16 } -+ | Some ("es1371") -> Some { s_sound_model = ES1370 (* hmmm ... *) } -+ | Some "hdaudio" -> Some { s_sound_model = ICH6 (* intel-hda *) } -+ | Some model -> -+ warning (f_"unknown sound device '%s' ignored") model; -+ None -+ | None -> None in -+ -+ let disks = find_disks vmx vmx_filename in -+ let removables = find_removables vmx in -+ let nics = find_nics vmx in -+ -+ let source = { -+ s_hypervisor = VMware; -+ s_name = name; -+ s_orig_name = name; -+ s_memory = memory; -+ s_vcpu = vcpu; -+ s_features = []; -+ s_firmware = firmware; -+ s_display = None; -+ s_video = video; -+ s_sound = sound; -+ s_disks = disks; -+ s_removables = removables; -+ s_nics = nics; -+ } in -+ -+ source -+end -+ -+let input_vmx = new input_vmx -+let () = Modules_list.register_input_module "vmx" -diff --git a/v2v/input_vmx.mli b/v2v/input_vmx.mli -new file mode 100644 -index 000000000..f236f8716 ---- /dev/null -+++ b/v2v/input_vmx.mli -@@ -0,0 +1,22 @@ -+(* virt-v2v -+ * Copyright (C) 2017 Red Hat Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ *) -+ -+(** [-i vmx] source. *) -+ -+val input_vmx : string -> Types.input -+(** [input_vmx filename] sets up an input from vmware vmx file. *) -diff --git a/v2v/name_from_disk.ml b/v2v/name_from_disk.ml -index 82f09250a..452d9462c 100644 ---- a/v2v/name_from_disk.ml -+++ b/v2v/name_from_disk.ml -@@ -24,7 +24,7 @@ let name_from_disk disk = - (* Remove the extension (or suffix), only if it's one usually - * used for disk images. *) - let suffixes = [ -- ".img"; ".ova"; ".qcow2"; ".raw"; ".vmdk"; -+ ".img"; ".ova"; ".qcow2"; ".raw"; ".vmdk"; ".vmx"; - "-sda"; - ] in - let rec loop = function -diff --git a/v2v/parse_vmx.ml b/v2v/parse_vmx.ml -new file mode 100644 -index 000000000..33ec17d3d ---- /dev/null -+++ b/v2v/parse_vmx.ml -@@ -0,0 +1,381 @@ -+(* virt-v2v -+ * Copyright (C) 2017 Red Hat Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ *) -+ -+open Printf -+ -+open Common_utils -+open Common_gettext.Gettext -+ -+(* As far as I can tell the VMX format is totally unspecified. -+ * However libvirt has a useful selection of .vmx files in the -+ * sources which explore some of the darker regions of this -+ * format. -+ * -+ * So here are some facts about VMX derived from libvirt and -+ * other places: -+ * -+ * - Keys are compared case insensitively. We assume here -+ * that keys are 7-bit ASCII. -+ * -+ * - Multiple keys with the same name are not allowed. -+ * -+ * - Escaping in the value string is possible using a very weird -+ * escape format: "|22" means the character '\x22'. To write -+ * a pipe character you must use "|7C". -+ * -+ * - Boolean values are written "TRUE", "FALSE", "True", "true", etc. -+ * Because of the quotes they cannot be distinguished from strings. -+ * -+ * - Comments (#...) and blank lines are ignored. Some files start -+ * with a hash-bang path, but we ignore those as comments. This -+ * parser also ignores any other line which it doesn't understand, -+ * but will print a warning. -+ * -+ * - Multi-line values are not permitted. -+ * -+ * - Keys are namespaced using dots, eg. scsi0:0.deviceType has -+ * the namespace "scsi0:0" and the key name "deviceType". -+ * -+ * - Using namespace.present = "FALSE" means that all other keys -+ * in and under the namespace are ignored. -+ * -+ * - You cannot have a namespace and a key with the same name, eg. -+ * this is not allowed: -+ * namespace = "some value" -+ * namespace.foo = "another value" -+ * -+ * - The Hashicorp packer VMX writer considers some special keys -+ * as not requiring any quotes around their values, but I'm -+ * ignoring that for now. -+ *) -+ -+(* This VMX file: -+ * -+ * foo.a = "abc" -+ * foo.b = "def" -+ * foo.bar.c = "abc" -+ * foo.bar.d = "def" -+ * -+ * would be represented by this structure: -+ * -+ * "foo" => Namespace ( # "foo" is a namespace -+ * "a" => Key "abc"; # "foo.a" is a key with value "abc" -+ * "b" => Key "def"; -+ * "bar" => Namespace ( # "foo.bar" is another namespace -+ * "c" => Key "abc"; -+ * "d" => Key "def"; -+ * ) -+ * ) -+ * ‘( => )’s represent the StringMap type. -+ *) -+type t = key StringMap.t -+ -+and key = -+ | Key of string -+ | Namespace of t -+ -+let empty = StringMap.empty -+ -+(* Compare two trees for equality. *) -+let rec equal vmx1 vmx2 = -+ let cmp k1 k2 = -+ match k1, k2 with -+ | Key v1, Key v2 -> v1 = v2 -+ | Key _, Namespace _ -> false -+ | Namespace _, Key _ -> false -+ | Namespace vmx1, Namespace vmx2 -> equal vmx1 vmx2 -+ in -+ StringMap.equal cmp vmx1 vmx2 -+ -+(* Higher-order functions. *) -+let rec select_namespaces pred vmx = -+ _select_namespaces [] pred vmx -+ -+and _select_namespaces path pred vmx = -+ StringMap.fold ( -+ fun k v new_vmx -> -+ let path = path @ [k] in -+ match v with -+ | Key _ -> new_vmx -+ | Namespace _ when pred path -> -+ StringMap.add k v new_vmx -+ | Namespace t -> -+ let t = _select_namespaces path pred t in -+ if not (equal t empty) then -+ StringMap.add k (Namespace t) new_vmx -+ else -+ new_vmx -+ ) vmx empty -+ -+let rec map f vmx = -+ _map [] f vmx -+ -+and _map path f vmx = -+ StringMap.fold ( -+ fun k v r -> -+ let path = path @ [k] in -+ match v with -+ | Key v -> r @ [ f path (Some v) ] -+ | Namespace t -> r @ [ f path None ] @ _map path f t -+ ) vmx [] -+ -+let rec namespace_present vmx = function -+ | [] -> false -+ | [ns] -> -+ let ns = String.lowercase_ascii ns in -+ (try -+ let v = StringMap.find ns vmx in -+ match v with -+ | Key _ -> false -+ | Namespace _ -> true -+ with -+ Not_found -> false -+ ) -+ | ns :: path -> -+ let ns = String.lowercase_ascii ns in -+ (try -+ let v = StringMap.find ns vmx in -+ match v with -+ | Key _ -> false -+ | Namespace vmx -> namespace_present vmx path -+ with -+ Not_found -> false -+ ) -+ -+(* Dump the vmx structure to [chan]. Used for debugging. *) -+let rec print chan indent vmx = -+ StringMap.iter (print_key chan indent) vmx -+ -+and print_key chan indent k = function -+ | Key v -> -+ output_spaces chan indent; -+ fprintf chan "%s = \"%s\"\n" k v -+ | Namespace vmx -> -+ output_spaces chan indent; -+ fprintf chan "namespace '%s':\n" k; -+ print chan (indent+4) vmx -+ -+(* As above, but creates a string instead. *) -+let rec to_string indent vmx = -+ StringMap.fold (fun k v str -> str ^ to_string_key indent k v) vmx "" -+ -+and to_string_key indent k = function -+ | Key v -> -+ String.spaces indent ^ sprintf "%s = \"%s\"\n" k v -+ | Namespace vmx -> -+ String.spaces indent ^ sprintf "namespace '%s':\n" k ^ -+ to_string (indent+4) vmx -+ -+(* Access keys in the tree. *) -+let rec get_string vmx = function -+ | [] -> None -+ | [k] -> -+ let k = String.lowercase_ascii k in -+ (try -+ let v = StringMap.find k vmx in -+ match v with -+ | Key v -> Some v -+ | Namespace _ -> None -+ with Not_found -> None -+ ) -+ | ns :: path -> -+ let ns = String.lowercase_ascii ns in -+ (try -+ let v = StringMap.find ns vmx in -+ match v with -+ | Key v -> None -+ | Namespace vmx -> get_string vmx path -+ with -+ Not_found -> None -+ ) -+ -+let get_int64 vmx path = -+ match get_string vmx path with -+ | None -> None -+ | Some i -> Some (Int64.of_string i) -+ -+let get_int vmx path = -+ match get_string vmx path with -+ | None -> None -+ | Some i -> Some (int_of_string i) -+ -+let rec get_bool vmx path = -+ match get_string vmx path with -+ | None -> None -+ | Some t -> Some (vmx_bool_of_string t) -+ -+and vmx_bool_of_string t = -+ if String.lowercase_ascii t = "true" then true -+ else if String.lowercase_ascii t = "false" then false -+ else failwith "bool_of_string" -+ -+(* Regular expression used to match key = "value" in VMX file. *) -+let rex = Str.regexp "^\\([^ \t=]+\\)[ \t]*=[ \t]*\"\\(.*\\)\"$" -+ -+(* Remove the weird escapes used in value strings. See description above. *) -+let remove_vmx_escapes str = -+ let len = String.length str in -+ let out = Bytes.make len '\000' in -+ let j = ref 0 in -+ -+ let rec loop i = -+ if i >= len then () -+ else ( -+ let c = String.unsafe_get str i in -+ if i <= len-3 && c = '|' then ( -+ let c1 = str.[i+1] and c2 = str.[i+2] in -+ if Char.isxdigit c1 && Char.isxdigit c2 then ( -+ let x = Char.hexdigit c1 * 0x10 + Char.hexdigit c2 in -+ Bytes.set out !j (Char.chr x); -+ incr j; -+ loop (i+3) -+ ) -+ else ( -+ Bytes.set out !j c; -+ incr j; -+ loop (i+1) -+ ) -+ ) -+ else ( -+ Bytes.set out !j c; -+ incr j; -+ loop (i+1) -+ ) -+ ) -+ in -+ loop 0; -+ -+ (* Truncate the output string to its real size and return it -+ * as an immutable string. -+ *) -+ Bytes.sub_string out 0 !j -+ -+(* Parsing. *) -+let rec parse_file vmx_filename = -+ (* Read the whole file as a list of lines. *) -+ let str = read_whole_file vmx_filename in -+ if verbose () then eprintf "VMX file:\n%s\n" str; -+ parse_string str -+ -+and parse_string str = -+ let lines = String.nsplit "\n" str in -+ -+ (* I've never seen any VMX file with CR-LF endings, and VMware -+ * itself is Linux-based, but to be on the safe side ... -+ *) -+ let lines = List.map (String.trimr ~test:((=) '\r')) lines in -+ -+ (* Ignore blank lines and comments. *) -+ let lines = List.filter ( -+ fun line -> -+ let line = String.triml line in -+ let len = String.length line in -+ len > 0 && line.[0] != '#' -+ ) lines in -+ -+ (* Parse the lines into key = "value". *) -+ let lines = filter_map ( -+ fun line -> -+ if Str.string_match rex line 0 then ( -+ let key = Str.matched_group 1 line in -+ let key = String.lowercase_ascii key in -+ let value = Str.matched_group 2 line in -+ let value = remove_vmx_escapes value in -+ Some (key, value) -+ ) -+ else ( -+ warning (f_"vmx parser: cannot parse this line, ignoring: %s") line; -+ None -+ ) -+ ) lines in -+ -+ (* Split the keys into namespace paths. *) -+ let lines = -+ List.map (fun (key, value) -> String.nsplit "." key, value) lines in -+ -+ (* Build a tree from the flat list and return it. This is horribly -+ * inefficient, at least O(n²), possibly even O(n².log n). Hope -+ * there are no large VMX files! (XXX) -+ *) -+ let vmx = -+ List.fold_left ( -+ fun vmx (path, value) -> insert vmx value path -+ ) empty lines in -+ -+ (* If we're verbose, dump the parsed VMX for debugging purposes. *) -+ if verbose () then ( -+ eprintf "parsed VMX tree:\n"; -+ print stderr 0 vmx -+ ); -+ -+ (* Drop all present = "FALSE" namespaces. *) -+ let vmx = drop_not_present vmx in -+ -+ vmx -+ -+and insert vmx value = function -+ | [] -> assert false -+ | [k] -> -+ if StringMap.mem k vmx then ( -+ warning (f_"vmx parser: duplicate key '%s' ignored") k; -+ vmx -+ ) else -+ StringMap.add k (Key value) vmx -+ | ns :: path -> -+ let v = -+ try -+ (match StringMap.find ns vmx with -+ | Namespace vmx -> Some vmx -+ | Key _ -> None -+ ) -+ with Not_found -> None in -+ let v = -+ match v with -+ | None -> -+ (* Completely new namespace. *) -+ insert empty value path -+ | Some v -> -+ (* Insert the subkey into the previously created namespace. *) -+ insert v value path in -+ StringMap.add ns (Namespace v) vmx -+ -+(* Find any "present" keys. If we find present = "FALSE", then -+ * drop the containing namespace and all subkeys and subnamespaces. -+ *) -+and drop_not_present vmx = -+ StringMap.fold ( -+ fun k v new_vmx -> -+ match v with -+ | Key _ -> -+ StringMap.add k v new_vmx -+ | Namespace vmx when contains_key_present_false vmx -> -+ (* drop this namespace and all sub-spaces *) -+ new_vmx -+ | Namespace v -> -+ (* recurse into sub-namespace and do the same check *) -+ let v = drop_not_present v in -+ StringMap.add k (Namespace v) new_vmx -+ ) vmx empty -+ -+and contains_key_present_false vmx = -+ try -+ match StringMap.find "present" vmx with -+ | Key v when vmx_bool_of_string v = false -> true -+ | Key _ | Namespace _ -> false -+ with -+ Failure _ | Not_found -> false -diff --git a/v2v/parse_vmx.mli b/v2v/parse_vmx.mli -new file mode 100644 -index 000000000..0e4f21f07 ---- /dev/null -+++ b/v2v/parse_vmx.mli -@@ -0,0 +1,89 @@ -+(* virt-v2v -+ * Copyright (C) 2017 Red Hat Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ *) -+ -+(** A simple parser for VMware [.vmx] files. *) -+ -+type t -+ -+val parse_file : string -> t -+(** [parse_file filename] parses a VMX file. *) -+ -+val parse_string : string -> t -+(** [parse_string s] parses VMX from a string. *) -+ -+val get_string : t -> string list -> string option -+(** Find a key and return it as a string. If not present, returns [None]. -+ -+ Note that if [namespace.present = "FALSE"] is found in the file -+ then all keys in [namespace] and below it are ignored. This -+ applies to all [get_*] functions. *) -+ -+val get_int64 : t -> string list -> int64 option -+(** Find a key and return it as an [int64]. -+ If not present, returns [None]. -+ -+ Raises [Failure _] if the key is present but was not parseable -+ as an integer. *) -+ -+val get_int : t -> string list -> int option -+(** Find a key and return it as an [int]. -+ If not present, returns [None]. -+ -+ Raises [Failure _] if the key is present but was not parseable -+ as an integer. *) -+ -+val get_bool : t -> string list -> bool option -+(** Find a key and return it as a boolean. -+ -+ You cannot return [namespace.present = "FALSE"] booleans this way. -+ They are processed by the parser and the namespace and anything -+ below it are removed from the tree. -+ -+ Raises [Failure _] if the key is present but was not parseable -+ as a boolean. *) -+ -+val namespace_present : t -> string list -> bool -+(** Returns true iff the namespace ({b note:} not key) is present. *) -+ -+val select_namespaces : (string list -> bool) -> t -> t -+(** Filter the VMX file, selecting exactly namespaces (and their -+ keys) matching the predicate. The predicate is a function which -+ is called on each {i namespace} path ({b note:} not on -+ namespace + key paths). If the predicate matches a -+ namespace, then all sub-namespaces under that namespace are -+ selected implicitly. *) -+ -+val map : (string list -> string option -> 'a) -> t -> 'a list -+(** Map all the entries in the VMX file into a list using the -+ map function. The map function takes two arguments. The -+ first is the path to the namespace or key, and the second -+ is the key value (or [None] if the path refers to a namespace). *) -+ -+val equal : t -> t -> bool -+(** Compare two VMX files for equality. This is mainly used for -+ testing the parser. *) -+ -+val empty : t -+(** An empty VMX file. *) -+ -+val print : out_channel -> int -> t -> unit -+(** [print chan indent] prints the VMX file to the output channel. -+ [indent] is the indentation applied to each line of output. *) -+ -+val to_string : int -> t -> string -+(** Same as {!print} but it creates a printable (multiline) string. *) -diff --git a/v2v/test-v2v-i-vmx-1.expected b/v2v/test-v2v-i-vmx-1.expected -new file mode 100644 -index 000000000..d32a29987 ---- /dev/null -+++ b/v2v/test-v2v-i-vmx-1.expected -@@ -0,0 +1,42 @@ -+[ 0.0] Opening the source -i vmx test-v2v-i-vmx-1.vmx -+Source guest information (--print-source option): -+ -+ source name: BZ1308535_21disks -+hypervisor type: vmware -+ memory: 2147483648 (bytes) -+ nr vCPUs: 1 -+ CPU vendor: -+ CPU model: -+ CPU topology: sockets: - cores/socket: - threads/core: - -+ CPU features: -+ firmware: bios -+ display: -+ video: vmvga -+ sound: -+disks: -+ /BZ1308535_21disks.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_1.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_2.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_3.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_4.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_5.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_6.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_7.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_8.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_9.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_10.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_11.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_12.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_13.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_14.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_15.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_16.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_17.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_18.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_19.vmdk (vmdk) [scsi] -+ /BZ1308535_21disks_20.vmdk (vmdk) [scsi] -+removable media: -+ CD-ROM [ide] in slot 2 -+NICs: -+ Network "VM Network" mac: 00:0c:29:36:ef:31 [vmxnet3] -+ -diff --git a/v2v/test-v2v-i-vmx-1.vmx b/v2v/test-v2v-i-vmx-1.vmx -new file mode 100644 -index 000000000..3f2f060a5 ---- /dev/null -+++ b/v2v/test-v2v-i-vmx-1.vmx -@@ -0,0 +1,172 @@ -+.encoding = "UTF-8" -+config.version = "8" -+virtualHW.version = "8" -+nvram = "BZ1308535_21disks.nvram" -+pciBridge0.present = "TRUE" -+svga.present = "TRUE" -+pciBridge4.present = "TRUE" -+pciBridge4.virtualDev = "pcieRootPort" -+pciBridge4.functions = "8" -+pciBridge5.present = "TRUE" -+pciBridge5.virtualDev = "pcieRootPort" -+pciBridge5.functions = "8" -+pciBridge6.present = "TRUE" -+pciBridge6.virtualDev = "pcieRootPort" -+pciBridge6.functions = "8" -+pciBridge7.present = "TRUE" -+pciBridge7.virtualDev = "pcieRootPort" -+pciBridge7.functions = "8" -+vmci0.present = "TRUE" -+hpet0.present = "TRUE" -+displayName = "BZ1308535_21disks" -+extendedConfigFile = "BZ1308535_21disks.vmxf" -+virtualHW.productCompatibility = "hosted" -+memSize = "2048" -+sched.cpu.units = "mhz" -+powerType.powerOff = "soft" -+powerType.suspend = "hard" -+powerType.reset = "soft" -+scsi0.virtualDev = "pvscsi" -+scsi0.present = "TRUE" -+scsi1.virtualDev = "pvscsi" -+scsi1.present = "TRUE" -+ide1:0.deviceType = "cdrom-image" -+ide1:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/RHEL-7.1-20150219.1-Server-x86_64-boot.iso" -+ide1:0.present = "TRUE" -+floppy0.startConnected = "FALSE" -+floppy0.clientDevice = "TRUE" -+floppy0.fileName = "vmware-null-remote-floppy" -+ethernet0.virtualDev = "vmxnet3" -+ethernet0.networkName = "VM Network" -+ethernet0.addressType = "generated" -+ethernet0.present = "TRUE" -+scsi0:0.deviceType = "scsi-hardDisk" -+scsi0:0.fileName = "BZ1308535_21disks.vmdk" -+scsi0:0.present = "TRUE" -+scsi0:1.deviceType = "scsi-hardDisk" -+scsi0:1.fileName = "BZ1308535_21disks_1.vmdk" -+scsi0:1.present = "TRUE" -+scsi0:2.deviceType = "scsi-hardDisk" -+scsi0:2.fileName = "BZ1308535_21disks_2.vmdk" -+scsi0:2.present = "TRUE" -+scsi0:3.deviceType = "scsi-hardDisk" -+scsi0:3.fileName = "BZ1308535_21disks_3.vmdk" -+scsi0:3.present = "TRUE" -+scsi0:4.deviceType = "scsi-hardDisk" -+scsi0:4.fileName = "BZ1308535_21disks_4.vmdk" -+scsi0:4.present = "TRUE" -+scsi0:5.deviceType = "scsi-hardDisk" -+scsi0:5.fileName = "BZ1308535_21disks_5.vmdk" -+scsi0:5.present = "TRUE" -+scsi0:6.deviceType = "scsi-hardDisk" -+scsi0:6.fileName = "BZ1308535_21disks_6.vmdk" -+scsi0:6.present = "TRUE" -+scsi0:8.deviceType = "scsi-hardDisk" -+scsi0:8.fileName = "BZ1308535_21disks_7.vmdk" -+scsi0:8.present = "TRUE" -+scsi0:9.deviceType = "scsi-hardDisk" -+scsi0:9.fileName = "BZ1308535_21disks_8.vmdk" -+scsi0:9.present = "TRUE" -+scsi0:10.deviceType = "scsi-hardDisk" -+scsi0:10.fileName = "BZ1308535_21disks_9.vmdk" -+scsi0:10.present = "TRUE" -+scsi0:11.deviceType = "scsi-hardDisk" -+scsi0:11.fileName = "BZ1308535_21disks_10.vmdk" -+scsi0:11.present = "TRUE" -+scsi0:12.deviceType = "scsi-hardDisk" -+scsi0:12.fileName = "BZ1308535_21disks_11.vmdk" -+scsi0:12.present = "TRUE" -+scsi0:13.deviceType = "scsi-hardDisk" -+scsi0:13.fileName = "BZ1308535_21disks_12.vmdk" -+scsi0:13.present = "TRUE" -+scsi0:14.deviceType = "scsi-hardDisk" -+scsi0:14.fileName = "BZ1308535_21disks_13.vmdk" -+scsi0:14.present = "TRUE" -+scsi0:15.deviceType = "scsi-hardDisk" -+scsi0:15.fileName = "BZ1308535_21disks_14.vmdk" -+scsi0:15.present = "TRUE" -+scsi1:0.deviceType = "scsi-hardDisk" -+scsi1:0.fileName = "BZ1308535_21disks_15.vmdk" -+scsi1:0.present = "TRUE" -+scsi1:1.deviceType = "scsi-hardDisk" -+scsi1:1.fileName = "BZ1308535_21disks_16.vmdk" -+scsi1:1.present = "TRUE" -+scsi1:2.deviceType = "scsi-hardDisk" -+scsi1:2.fileName = "BZ1308535_21disks_17.vmdk" -+scsi1:2.present = "TRUE" -+scsi1:3.deviceType = "scsi-hardDisk" -+scsi1:3.fileName = "BZ1308535_21disks_18.vmdk" -+scsi1:3.present = "TRUE" -+scsi1:4.deviceType = "scsi-hardDisk" -+scsi1:4.fileName = "BZ1308535_21disks_19.vmdk" -+scsi1:4.present = "TRUE" -+scsi1:5.deviceType = "scsi-hardDisk" -+scsi1:5.fileName = "BZ1308535_21disks_20.vmdk" -+scsi1:5.present = "TRUE" -+guestOS = "rhel6-64" -+toolScripts.afterPowerOn = "TRUE" -+toolScripts.afterResume = "TRUE" -+toolScripts.beforeSuspend = "TRUE" -+toolScripts.beforePowerOff = "TRUE" -+uuid.bios = "56 4d 96 af e6 46 bd 86-5c 4d 65 4e 77 36 ef 31" -+uuid.location = "56 4d 96 af e6 46 bd 86-5c 4d 65 4e 77 36 ef 31" -+vc.uuid = "52 31 cb fc c1 3f 96 32-83 c0 bb 70 6c 90 5c fd" -+chipset.onlineStandby = "FALSE" -+sched.cpu.min = "0" -+sched.cpu.shares = "normal" -+sched.mem.min = "0" -+sched.mem.minSize = "0" -+sched.mem.shares = "normal" -+svga.vramSize = "8388608" -+sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/BZ1308535_21disks/BZ1308535_21disks-6a024f8a.vswp" -+replay.supported = "FALSE" -+replay.filename = "" -+scsi0:0.redo = "" -+scsi0:1.redo = "" -+scsi0:2.redo = "" -+scsi0:3.redo = "" -+scsi0:4.redo = "" -+scsi0:5.redo = "" -+scsi0:6.redo = "" -+scsi0:8.redo = "" -+scsi0:9.redo = "" -+scsi0:10.redo = "" -+scsi0:11.redo = "" -+scsi0:12.redo = "" -+scsi0:13.redo = "" -+scsi0:14.redo = "" -+scsi0:15.redo = "" -+scsi1:0.redo = "" -+scsi1:1.redo = "" -+scsi1:2.redo = "" -+scsi1:3.redo = "" -+scsi1:4.redo = "" -+scsi1:5.redo = "" -+pciBridge0.pciSlotNumber = "17" -+pciBridge4.pciSlotNumber = "21" -+pciBridge5.pciSlotNumber = "22" -+pciBridge6.pciSlotNumber = "23" -+pciBridge7.pciSlotNumber = "24" -+scsi0.pciSlotNumber = "160" -+scsi1.pciSlotNumber = "192" -+ethernet0.pciSlotNumber = "224" -+vmci0.pciSlotNumber = "32" -+scsi0.sasWWID = "50 05 05 6f e6 46 bd 80" -+scsi1.sasWWID = "50 05 05 6f e6 46 bc 80" -+ethernet0.generatedAddress = "00:0c:29:36:ef:31" -+ethernet0.generatedAddressOffset = "0" -+vmci0.id = "2000088881" -+hostCPUID.0 = "0000000d756e65476c65746e49656e69" -+hostCPUID.1 = "000206a700100800179ae3bfbfebfbff" -+hostCPUID.80000001 = "00000000000000000000000128100800" -+guestCPUID.0 = "0000000d756e65476c65746e49656e69" -+guestCPUID.1 = "000206a700010800969822030fabfbff" -+guestCPUID.80000001 = "00000000000000000000000128100800" -+userCPUID.0 = "0000000d756e65476c65746e49656e69" -+userCPUID.1 = "000206a700100800169822030fabfbff" -+userCPUID.80000001 = "00000000000000000000000128100800" -+evcCompatibilityMode = "FALSE" -+vmotion.checkpointFBSize = "8388608" -+cleanShutdown = "TRUE" -+softPowerOff = "TRUE" -+tools.remindInstall = "TRUE" -diff --git a/v2v/test-v2v-i-vmx-2.expected b/v2v/test-v2v-i-vmx-2.expected -new file mode 100644 -index 000000000..dc3eb60f2 ---- /dev/null -+++ b/v2v/test-v2v-i-vmx-2.expected -@@ -0,0 +1,22 @@ -+[ 0.0] Opening the source -i vmx test-v2v-i-vmx-2.vmx -+Source guest information (--print-source option): -+ -+ source name: Fedora 20 -+hypervisor type: vmware -+ memory: 2147483648 (bytes) -+ nr vCPUs: 1 -+ CPU vendor: -+ CPU model: -+ CPU topology: sockets: - cores/socket: - threads/core: - -+ CPU features: -+ firmware: bios -+ display: -+ video: vmvga -+ sound: -+disks: -+ /Fedora 20.vmdk (vmdk) [scsi] -+removable media: -+ -+NICs: -+ Network "VM Network" mac: 00:50:56:9b:5f:0d [vmxnet3] -+ -diff --git a/v2v/test-v2v-i-vmx-2.vmx b/v2v/test-v2v-i-vmx-2.vmx -new file mode 100644 -index 000000000..d9dcf3a5c ---- /dev/null -+++ b/v2v/test-v2v-i-vmx-2.vmx -@@ -0,0 +1,84 @@ -+.encoding = "UTF-8" -+config.version = "8" -+virtualHW.version = "10" -+nvram = "Fedora 20.nvram" -+pciBridge0.present = "TRUE" -+svga.present = "TRUE" -+pciBridge4.present = "TRUE" -+pciBridge4.virtualDev = "pcieRootPort" -+pciBridge4.functions = "8" -+pciBridge5.present = "TRUE" -+pciBridge5.virtualDev = "pcieRootPort" -+pciBridge5.functions = "8" -+pciBridge6.present = "TRUE" -+pciBridge6.virtualDev = "pcieRootPort" -+pciBridge6.functions = "8" -+pciBridge7.present = "TRUE" -+pciBridge7.virtualDev = "pcieRootPort" -+pciBridge7.functions = "8" -+vmci0.present = "TRUE" -+hpet0.present = "TRUE" -+displayName = "Fedora 20" -+extendedConfigFile = "Fedora 20.vmxf" -+virtualHW.productCompatibility = "hosted" -+svga.vramSize = "8388608" -+memSize = "2048" -+sched.cpu.units = "mhz" -+sched.cpu.affinity = "all" -+powerType.powerOff = "soft" -+powerType.suspend = "hard" -+powerType.reset = "soft" -+scsi0.virtualDev = "pvscsi" -+scsi0.present = "TRUE" -+sata0.present = "TRUE" -+scsi0:0.deviceType = "scsi-hardDisk" -+scsi0:0.fileName = "Fedora 20.vmdk" -+sched.scsi0:0.shares = "normal" -+sched.scsi0:0.throughputCap = "off" -+scsi0:0.present = "TRUE" -+ethernet0.virtualDev = "vmxnet3" -+ethernet0.networkName = "VM Network" -+ethernet0.addressType = "vpx" -+ethernet0.generatedAddress = "00:50:56:9b:5f:0d" -+ethernet0.present = "TRUE" -+sata0:0.startConnected = "FALSE" -+sata0:0.deviceType = "cdrom-image" -+sata0:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/Fedora-20-x86_64-netinst.iso" -+sata0:0.present = "TRUE" -+floppy0.startConnected = "FALSE" -+floppy0.clientDevice = "TRUE" -+floppy0.fileName = "vmware-null-remote-floppy" -+vmci.filter.enable = "TRUE" -+guestOS = "rhel7-64" -+toolScripts.afterPowerOn = "TRUE" -+toolScripts.afterResume = "TRUE" -+toolScripts.beforeSuspend = "TRUE" -+toolScripts.beforePowerOff = "TRUE" -+uuid.bios = "42 1b 4b 87 e6 b7 d8 81-07 a0 c9 d2 21 cd 3c 6b" -+vc.uuid = "50 1b 1f 1b 73 00 32 bf-93 a1 1c b2 b4 e6 17 d6" -+sched.cpu.min = "0" -+sched.cpu.shares = "normal" -+sched.mem.min = "0" -+sched.mem.minSize = "0" -+sched.mem.shares = "normal" -+sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/Fedora 20/Fedora 20-c71e4118.vswp" -+uuid.location = "56 4d 0f 53 00 63 d5 55-41 01 4c f7 55 ce 03 0e" -+replay.supported = "TRUE" -+replay.filename = "" -+scsi0:0.redo = "" -+pciBridge0.pciSlotNumber = "17" -+pciBridge4.pciSlotNumber = "21" -+pciBridge5.pciSlotNumber = "22" -+pciBridge6.pciSlotNumber = "23" -+pciBridge7.pciSlotNumber = "24" -+scsi0.pciSlotNumber = "160" -+ethernet0.pciSlotNumber = "192" -+vmci0.pciSlotNumber = "32" -+sata0.pciSlotNumber = "33" -+scsi0.sasWWID = "50 05 05 67 e6 b7 d8 80" -+vmci0.id = "567098475" -+vmotion.checkpointFBSize = "8388608" -+cleanShutdown = "TRUE" -+softPowerOff = "TRUE" -+sata0:0.allowGuestConnectionControl = "TRUE" -+tools.syncTime = "FALSE" -diff --git a/v2v/test-v2v-i-vmx-3.expected b/v2v/test-v2v-i-vmx-3.expected -new file mode 100644 -index 000000000..9e643526f ---- /dev/null -+++ b/v2v/test-v2v-i-vmx-3.expected -@@ -0,0 +1,22 @@ -+[ 0.0] Opening the source -i vmx test-v2v-i-vmx-3.vmx -+Source guest information (--print-source option): -+ -+ source name: RHEL 7.1 UEFI -+hypervisor type: vmware -+ memory: 2147483648 (bytes) -+ nr vCPUs: 1 -+ CPU vendor: -+ CPU model: -+ CPU topology: sockets: - cores/socket: - threads/core: - -+ CPU features: -+ firmware: uefi -+ display: -+ video: vmvga -+ sound: -+disks: -+ /RHEL 7.1 UEFI.vmdk (vmdk) [scsi] -+removable media: -+ CD-ROM [ide] in slot 2 -+NICs: -+ Network "VM Network" mac: 00:0c:29:4b:2b:8c [vmxnet3] -+ -diff --git a/v2v/test-v2v-i-vmx-3.vmx b/v2v/test-v2v-i-vmx-3.vmx -new file mode 100644 -index 000000000..c39215555 ---- /dev/null -+++ b/v2v/test-v2v-i-vmx-3.vmx -@@ -0,0 +1,91 @@ -+.encoding = "UTF-8" -+config.version = "8" -+virtualHW.version = "8" -+nvram = "RHEL 7.1 UEFI.nvram" -+pciBridge0.present = "TRUE" -+svga.present = "TRUE" -+pciBridge4.present = "TRUE" -+pciBridge4.virtualDev = "pcieRootPort" -+pciBridge4.functions = "8" -+pciBridge5.present = "TRUE" -+pciBridge5.virtualDev = "pcieRootPort" -+pciBridge5.functions = "8" -+pciBridge6.present = "TRUE" -+pciBridge6.virtualDev = "pcieRootPort" -+pciBridge6.functions = "8" -+pciBridge7.present = "TRUE" -+pciBridge7.virtualDev = "pcieRootPort" -+pciBridge7.functions = "8" -+vmci0.present = "TRUE" -+hpet0.present = "TRUE" -+displayName = "RHEL 7.1 UEFI" -+extendedConfigFile = "RHEL 7.1 UEFI.vmxf" -+virtualHW.productCompatibility = "hosted" -+memSize = "2048" -+firmware = "efi" -+sched.cpu.units = "mhz" -+powerType.powerOff = "soft" -+powerType.suspend = "hard" -+powerType.reset = "soft" -+scsi0.virtualDev = "pvscsi" -+scsi0.present = "TRUE" -+ide1:0.startConnected = "FALSE" -+ide1:0.deviceType = "cdrom-image" -+ide1:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/RHEL-7.1-20150219.1-Server-x86_64-boot.iso" -+ide1:0.present = "TRUE" -+floppy0.startConnected = "FALSE" -+floppy0.clientDevice = "TRUE" -+floppy0.fileName = "vmware-null-remote-floppy" -+ethernet0.virtualDev = "vmxnet3" -+ethernet0.networkName = "VM Network" -+ethernet0.addressType = "generated" -+ethernet0.present = "TRUE" -+scsi0:0.deviceType = "scsi-hardDisk" -+scsi0:0.fileName = "RHEL 7.1 UEFI.vmdk" -+scsi0:0.present = "TRUE" -+guestOS = "rhel6-64" -+toolScripts.afterPowerOn = "TRUE" -+toolScripts.afterResume = "TRUE" -+toolScripts.beforeSuspend = "TRUE" -+toolScripts.beforePowerOff = "TRUE" -+uuid.bios = "56 4d 99 89 a7 21 91 0d-cc 28 e2 db d5 4b 2b 8c" -+uuid.location = "56 4d 99 89 a7 21 91 0d-cc 28 e2 db d5 4b 2b 8c" -+vc.uuid = "52 3f 29 10 d3 81 16 43-fa b0 e3 af 3b ba 36 e5" -+chipset.onlineStandby = "FALSE" -+sched.cpu.min = "0" -+sched.cpu.shares = "normal" -+sched.mem.min = "0" -+sched.mem.minSize = "0" -+sched.mem.shares = "normal" -+svga.vramSize = "8388608" -+sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/RHEL 7.1 UEFI/RHEL 7.1 UEFI-58ff6e6f.vswp" -+replay.supported = "FALSE" -+replay.filename = "" -+scsi0:0.redo = "" -+pciBridge0.pciSlotNumber = "17" -+pciBridge4.pciSlotNumber = "21" -+pciBridge5.pciSlotNumber = "22" -+pciBridge6.pciSlotNumber = "23" -+pciBridge7.pciSlotNumber = "24" -+scsi0.pciSlotNumber = "160" -+ethernet0.pciSlotNumber = "192" -+vmci0.pciSlotNumber = "32" -+scsi0.sasWWID = "50 05 05 69 a7 21 91 00" -+ethernet0.generatedAddress = "00:0c:29:4b:2b:8c" -+ethernet0.generatedAddressOffset = "0" -+vmci0.id = "-716493940" -+hostCPUID.0 = "0000000d756e65476c65746e49656e69" -+hostCPUID.1 = "000206a700100800179ae3bfbfebfbff" -+hostCPUID.80000001 = "00000000000000000000000128100800" -+guestCPUID.0 = "0000000d756e65476c65746e49656e69" -+guestCPUID.1 = "000206a700010800969822030fabfbff" -+guestCPUID.80000001 = "00000000000000000000000128100800" -+userCPUID.0 = "0000000d756e65476c65746e49656e69" -+userCPUID.1 = "000206a700100800169822030fabfbff" -+userCPUID.80000001 = "00000000000000000000000128100800" -+evcCompatibilityMode = "FALSE" -+vmotion.checkpointFBSize = "8388608" -+cleanShutdown = "TRUE" -+softPowerOff = "TRUE" -+ide1:0.allowGuestConnectionControl = "TRUE" -+tools.syncTime = "FALSE" -diff --git a/v2v/test-v2v-i-vmx-4.expected b/v2v/test-v2v-i-vmx-4.expected -new file mode 100644 -index 000000000..a70533d2e ---- /dev/null -+++ b/v2v/test-v2v-i-vmx-4.expected -@@ -0,0 +1,22 @@ -+[ 0.0] Opening the source -i vmx test-v2v-i-vmx-4.vmx -+Source guest information (--print-source option): -+ -+ source name: Windows 7 x64 -+hypervisor type: vmware -+ memory: 2147483648 (bytes) -+ nr vCPUs: 1 -+ CPU vendor: -+ CPU model: -+ CPU topology: sockets: - cores/socket: - threads/core: - -+ CPU features: -+ firmware: bios -+ display: -+ video: vmvga -+ sound: -+disks: -+ /Windows 7 x64.vmdk (vmdk) [scsi] -+removable media: -+ CD-ROM [ide] in slot 2 -+NICs: -+ Network "VM Network" mac: 00:0c:29:94:89:23 [e1000] -+ -diff --git a/v2v/test-v2v-i-vmx-4.vmx b/v2v/test-v2v-i-vmx-4.vmx -new file mode 100644 -index 000000000..7756cf248 ---- /dev/null -+++ b/v2v/test-v2v-i-vmx-4.vmx -@@ -0,0 +1,88 @@ -+.encoding = "UTF-8" -+config.version = "8" -+virtualHW.version = "8" -+nvram = "Windows 7 x64.nvram" -+pciBridge0.present = "TRUE" -+svga.present = "TRUE" -+pciBridge4.present = "TRUE" -+pciBridge4.virtualDev = "pcieRootPort" -+pciBridge4.functions = "8" -+pciBridge5.present = "TRUE" -+pciBridge5.virtualDev = "pcieRootPort" -+pciBridge5.functions = "8" -+pciBridge6.present = "TRUE" -+pciBridge6.virtualDev = "pcieRootPort" -+pciBridge6.functions = "8" -+pciBridge7.present = "TRUE" -+pciBridge7.virtualDev = "pcieRootPort" -+pciBridge7.functions = "8" -+vmci0.present = "TRUE" -+hpet0.present = "TRUE" -+displayName = "Windows 7 x64" -+extendedConfigFile = "Windows 7 x64.vmxf" -+virtualHW.productCompatibility = "hosted" -+memSize = "2048" -+sched.cpu.units = "mhz" -+powerType.powerOff = "soft" -+powerType.suspend = "hard" -+powerType.reset = "soft" -+scsi0.virtualDev = "lsisas1068" -+scsi0.present = "TRUE" -+ide1:0.deviceType = "cdrom-image" -+ide1:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/en_windows_7_ultimate_with_sp1_x64_dvd_u_677332.iso" -+ide1:0.present = "TRUE" -+floppy0.startConnected = "FALSE" -+floppy0.clientDevice = "TRUE" -+floppy0.fileName = "vmware-null-remote-floppy" -+ethernet0.virtualDev = "e1000" -+ethernet0.networkName = "VM Network" -+ethernet0.addressType = "generated" -+ethernet0.present = "TRUE" -+scsi0:0.deviceType = "scsi-hardDisk" -+scsi0:0.fileName = "Windows 7 x64.vmdk" -+scsi0:0.present = "TRUE" -+guestOS = "windows7-64" -+toolScripts.afterPowerOn = "TRUE" -+toolScripts.afterResume = "TRUE" -+toolScripts.beforeSuspend = "TRUE" -+toolScripts.beforePowerOff = "TRUE" -+uuid.bios = "56 4d 6f ca 63 a5 a8 3e-13 ec 73 89 1d 94 89 23" -+uuid.location = "56 4d 6f ca 63 a5 a8 3e-13 ec 73 89 1d 94 89 23" -+vc.uuid = "52 7a 63 e1 2c 2f 50 46-91 66 3a e8 fa f9 c4 65" -+chipset.onlineStandby = "FALSE" -+sched.cpu.min = "0" -+sched.cpu.shares = "normal" -+sched.mem.min = "0" -+sched.mem.minSize = "0" -+sched.mem.shares = "normal" -+svga.vramSize = "8388608" -+sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/Windows 7 x64/Windows 7 x64-8e3b0929.vswp" -+replay.supported = "FALSE" -+replay.filename = "" -+scsi0:0.redo = "" -+pciBridge0.pciSlotNumber = "17" -+pciBridge4.pciSlotNumber = "21" -+pciBridge5.pciSlotNumber = "22" -+pciBridge6.pciSlotNumber = "23" -+pciBridge7.pciSlotNumber = "24" -+scsi0.pciSlotNumber = "160" -+ethernet0.pciSlotNumber = "32" -+vmci0.pciSlotNumber = "33" -+scsi0.sasWWID = "50 05 05 6a 63 a5 a8 30" -+ethernet0.generatedAddress = "00:0c:29:94:89:23" -+ethernet0.generatedAddressOffset = "0" -+vmci0.id = "496273699" -+hostCPUID.0 = "0000000b756e65476c65746e49656e69" -+hostCPUID.1 = "000206c220200800029ee3ffbfebfbff" -+hostCPUID.80000001 = "0000000000000000000000012c100800" -+guestCPUID.0 = "0000000b756e65476c65746e49656e69" -+guestCPUID.1 = "000206c200010800829822030fabfbff" -+guestCPUID.80000001 = "00000000000000000000000128100800" -+userCPUID.0 = "0000000b756e65476c65746e49656e69" -+userCPUID.1 = "000206c220200800029822030fabfbff" -+userCPUID.80000001 = "00000000000000000000000128100800" -+evcCompatibilityMode = "FALSE" -+vmotion.checkpointFBSize = "8388608" -+cleanShutdown = "TRUE" -+softPowerOff = "TRUE" -+tools.remindInstall = "TRUE" -diff --git a/v2v/test-v2v-i-vmx.sh b/v2v/test-v2v-i-vmx.sh -new file mode 100755 -index 000000000..5353e7e2a ---- /dev/null -+++ b/v2v/test-v2v-i-vmx.sh -@@ -0,0 +1,48 @@ -+#!/bin/bash - -+# libguestfs virt-v2v test script -+# Copyright (C) 2017 Red Hat Inc. -+# -+# This program is free software; you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 2 of the License, or -+# (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program; if not, write to the Free Software -+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ -+# Test -i ova option. -+ -+set -e -+ -+$TEST_FUNCTIONS -+skip_if_skipped -+skip_if_backend uml -+ -+export VIRT_TOOLS_DATA_DIR="$top_srcdir/test-data/fake-virt-tools" -+export VIRTIO_WIN="$top_srcdir/test-data/fake-virtio-win" -+ -+rm -f test-v2v-i-vmx-*.actual -+ -+for i in 1 2 3 4; do -+ $VG virt-v2v --debug-gc \ -+ -i vmx test-v2v-i-vmx-$i.vmx \ -+ --print-source > test-v2v-i-vmx-$i.actual -+ -+ # Normalize the print-source output. -+ mv test-v2v-i-vmx-$i.actual test-v2v-i-vmx-$i.actual.old -+ sed \ -+ -e "s,$(pwd),," \ -+ < test-v2v-i-vmx-$i.actual.old > test-v2v-i-vmx-$i.actual -+ rm test-v2v-i-vmx-$i.actual.old -+ -+ # Check the output. -+ diff -u test-v2v-i-vmx-$i.expected test-v2v-i-vmx-$i.actual -+done -+ -+rm test-v2v-i-vmx-*.actual -diff --git a/v2v/v2v_unit_tests.ml b/v2v/v2v_unit_tests.ml -index bd65788b0..dd805a3ab 100644 ---- a/v2v/v2v_unit_tests.ml -+++ b/v2v/v2v_unit_tests.ml -@@ -787,6 +787,148 @@ let test_qemu_img_supports ctx = - *) - ignore (Utils.qemu_img_supports_offset_and_size ()) - -+(* Test the VMX file parser in the Parse_vmx module. *) -+let test_vmx_parse_string ctx = -+ let cmp = Parse_vmx.equal in -+ let printer = Parse_vmx.to_string 0 in -+ -+ (* This should be identical to the empty file. *) -+ let t = Parse_vmx.parse_string "\ -+test.foo = \"a\" -+test.bar = \"b\" -+test.present = \"FALSE\" -+" in -+ assert_equal ~cmp ~printer Parse_vmx.empty t; -+ -+ (* Test weird escapes. *) -+ let t1 = Parse_vmx.parse_string "\ -+foo = \"a|20|21b\" -+" in -+ let t2 = Parse_vmx.parse_string "\ -+foo = \"a !b\" -+" in -+ assert_equal ~cmp ~printer t1 t2; -+ -+ (* Test case insensitivity. *) -+ let t1 = Parse_vmx.parse_string "\ -+foo = \"abc\" -+" in -+ let t2 = Parse_vmx.parse_string "\ -+fOO = \"abc\" -+" in -+ assert_equal ~cmp ~printer t1 t2; -+ let t = Parse_vmx.parse_string "\ -+flag = \"true\" -+" in -+ assert_bool "parse_vmx: failed case insensitivity test for booleans #1" -+ (Parse_vmx.get_bool t ["FLAG"] = Some true); -+ let t = Parse_vmx.parse_string "\ -+flag = \"TRUE\" -+" in -+ assert_bool "parse_vmx: failed case insensitivity test for booleans #2" -+ (Parse_vmx.get_bool t ["Flag"] = Some true); -+ -+ (* Missing keys. *) -+ let t = Parse_vmx.parse_string "\ -+foo = \"a\" -+" in -+ assert_bool "parse_vmx: failed missing key test" -+ (Parse_vmx.get_string t ["bar"] = None); -+ -+ (* namespace_present function *) -+ let t = Parse_vmx.parse_string "\ -+foo.bar.present = \"TRUE\" -+foo.baz.present = \"FALSE\" -+foo.a.b = \"abc\" -+foo.a.c = \"abc\" -+foo.b = \"abc\" -+foo.c.a = \"abc\" -+foo.c.b = \"abc\" -+" in -+ assert_bool "parse_vmx: namespace_present #1" -+ (Parse_vmx.namespace_present t ["foo"] = true); -+ assert_bool "parse_vmx: namespace_present #2" -+ (Parse_vmx.namespace_present t ["foo"; "bar"] = true); -+ assert_bool "parse_vmx: namespace_present #3" -+ (* this whole namespace should have been culled *) -+ (Parse_vmx.namespace_present t ["foo"; "baz"] = false); -+ assert_bool "parse_vmx: namespace_present #4" -+ (Parse_vmx.namespace_present t ["foo"; "a"] = true); -+ assert_bool "parse_vmx: namespace_present #5" -+ (* this is a key, not a namespace *) -+ (Parse_vmx.namespace_present t ["foo"; "a"; "b"] = false); -+ assert_bool "parse_vmx: namespace_present #6" -+ (Parse_vmx.namespace_present t ["foo"; "b"] = false); -+ assert_bool "parse_vmx: namespace_present #7" -+ (Parse_vmx.namespace_present t ["foo"; "c"] = true); -+ assert_bool "parse_vmx: namespace_present #8" -+ (Parse_vmx.namespace_present t ["foo"; "d"] = false); -+ -+ (* map function *) -+ let t = Parse_vmx.parse_string "\ -+foo.bar.present = \"TRUE\" -+foo.baz.present = \"FALSE\" -+foo.a.b = \"abc\" -+foo.a.c = \"abc\" -+foo.b = \"abc\" -+foo.c.a = \"abc\" -+foo.c.b = \"abc\" -+" in -+ let xs = -+ Parse_vmx.map ( -+ fun path -> -+ let path = String.concat "." path in -+ function -+ | None -> sprintf "%s.present = \"true\"\n" path -+ | Some v -> sprintf "%s = \"%s\"\n" path v -+ ) t in -+ let xs = List.sort compare xs in -+ let s = String.concat "" xs in -+ assert_equal ~printer:identity "\ -+foo.a.b = \"abc\" -+foo.a.c = \"abc\" -+foo.a.present = \"true\" -+foo.b = \"abc\" -+foo.bar.present = \"TRUE\" -+foo.bar.present = \"true\" -+foo.c.a = \"abc\" -+foo.c.b = \"abc\" -+foo.c.present = \"true\" -+foo.present = \"true\" -+" s; -+ -+ (* select_namespaces function *) -+ let t1 = Parse_vmx.parse_string "\ -+foo.bar.present = \"TRUE\" -+foo.a.b = \"abc\" -+foo.a.c = \"abc\" -+foo.b = \"abc\" -+foo.c.a = \"abc\" -+foo.c.b = \"abc\" -+" in -+ let t2 = -+ Parse_vmx.select_namespaces -+ (function ["foo"] -> true | _ -> false) t1 in -+ assert_equal ~cmp ~printer t1 t2; -+ -+ let t1 = Parse_vmx.parse_string "\ -+foo.bar.present = \"TRUE\" -+foo.a.b = \"abc\" -+foo.a.c = \"abc\" -+foo.b = \"abc\" -+foo.c.a = \"abc\" -+foo.c.b = \"abc\" -+foo.c.c.d.e.f = \"abc\" -+" in -+ let t1 = -+ Parse_vmx.select_namespaces -+ (function ["foo"; "a"] -> true | _ -> false) t1 in -+ let t2 = Parse_vmx.parse_string "\ -+foo.a.b = \"abc\" -+foo.a.c = \"abc\" -+" in -+ assert_equal ~cmp ~printer t2 t1 -+ - (* Suites declaration. *) - let suite = - "virt-v2v" >::: -@@ -798,6 +940,7 @@ let suite = - test_virtio_iso_path_matches_guest_os; - "Utils.shell_unquote" >:: test_shell_unquote; - "Utils.qemu_img_supports" >:: test_qemu_img_supports; -+ "Parse_vmx.parse_string" >::test_vmx_parse_string; - ] - - let () = -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index 7ad674d43..31d1ce029 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -41,7 +41,8 @@ libguestfs E 1.28. - ... ───▶│ (default) │ │ │ ──┐ └────────────┘ - └────────────┘ │ │ ─┐└──────▶ -o glance - -i libvirtxml ─────────▶ │ │ ┐└─────────▶ -o rhv -- └────────────┘ └──────────▶ -o vdsm -+ -i vmx ────────────────▶ │ │ └──────────▶ -o vdsm -+ └────────────┘ - - Virt-v2v has a number of possible input and output modes, selected - using the I<-i> and I<-o> options. Only one input and output mode can -@@ -60,6 +61,8 @@ method used by L behind the scenes. - - I<-i ova> is used for reading from a VMware ova source file. - -+I<-i vmx> is used for reading from a VMware vmx file. -+ - I<-o glance> is used for writing to OpenStack Glance. - - I<-o libvirt> is used for writing to any libvirt target. Libvirt can -@@ -215,6 +218,14 @@ ova manifest file and check the vmdk volumes for validity (checksums) - as well as analyzing the ovf file, and then convert the guest. See - L below - -+=item B<-i> B -+ -+Set the input method to I. -+ -+In this mode you can read a VMware vmx file directly. This is useful -+when VMware VMs are stored on an NFS server which you can mount -+directly. See L below -+ - =item B<-ic> libvirtURI - - Specify a libvirt connection URI to use when reading the guest. This -@@ -843,9 +854,10 @@ I<--bridge> option instead. For example: - - Virt-v2v is able to import guests from VMware vCenter Server. - --vCenter E 5.0 is required. If you don't have vCenter, using OVA --is recommended instead (see L below), or if --that is not possible then see L. -+vCenter E 5.0 is required. If you don’t have vCenter, using OVA -+or VMX is recommended instead (see L and/or -+L below), or if that is not possible then see -+L. - - Virt-v2v uses libvirt for access to vCenter, and therefore the input - mode should be I<-i libvirt>. As this is the default, you don't need -@@ -1116,12 +1128,58 @@ directory containing the files: - - $ virt-v2v -i ova /path/to/files -o local -os /var/tmp - -+=head1 INPUT FROM VMWARE VMX -+ -+Virt-v2v is able to import guests from VMware’s vmx files. This is -+useful where VMware virtual machines are stored on a separate NFS -+server and you are able to mount the NFS storage directly. -+ -+If you find a folder of files called F.vmx>, -+F.vmxf>, F.nvram> and one or more F<.vmdk> disk -+images, then you can use this method. -+ -+=head2 VMX: REMOVE VMWARE TOOLS FROM WINDOWS GUESTS -+ -+For Windows guests, you should remove VMware tools before conversion. -+Although this is not strictly necessary, and the guest will still be -+able to run, if you don't do this then the converted guest will -+complain on every boot. The tools cannot be removed after conversion -+because the uninstaller checks if it is running on VMware and refuses -+to start (which is also the reason that virt-v2v cannot remove them). -+ -+This is not necessary for Linux guests, as virt-v2v is able to remove -+VMware tools. -+ -+=head2 VMX: GUEST MUST BE SHUT DOWN -+ -+B. If you don't -+shut it down, you will end up with a corrupted VM disk on the target. -+With other methods, virt-v2v tries to prevent concurrent access, but -+because the I<-i vmx> method works directly against the storage, -+checking for concurrent access is not possible. -+ -+=head2 VMX: MOUNT THE NFS STORAGE ON THE CONVERSION SERVER -+ -+Virt-v2v must be able to access the F<.vmx> file and any local -+F<.vmdk> disks. Normally this means you must mount the NFS storage -+containing these files. -+ -+=head2 VMX: IMPORTING A GUEST -+ -+To import a vmx file, do: -+ -+ $ virt-v2v -i vmx guest.vmx -o local -os /var/tmp -+ -+Virt-v2v processes the vmx file and uses it to find the location of -+any vmdk disks. -+ - =head1 INPUT FROM VMWARE ESXi HYPERVISOR - - Virt-v2v cannot access an ESXi hypervisor directly. You should use --the OVA method above (see L) if possible, as --it is much faster and requires much less disk space than the method --described in this section. -+the OVA or VMX methods above (see L and/or -+L) if possible, as it is much faster and -+requires much less disk space than the method described in this -+section. - - You can use the L tool to copy the guest - off the hypervisor into a local file, and then convert it. --- -2.13.4 - diff --git a/SOURCES/0037-s390x-launch-direct-Use-sclp-as-serial-console-on-th.patch b/SOURCES/0037-s390x-launch-direct-Use-sclp-as-serial-console-on-th.patch new file mode 100644 index 0000000..a4346dd --- /dev/null +++ b/SOURCES/0037-s390x-launch-direct-Use-sclp-as-serial-console-on-th.patch @@ -0,0 +1,37 @@ +From f774a2efed860774ba3a8e47e8ac81eeed2508fa Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 17 May 2017 12:16:07 +0200 +Subject: [PATCH] s390x: launch: direct: Use sclp as serial console on this + architecture. + +The same change to the direct backend as made to the libvirt backend +in the previous commit. + +(cherry picked from commit ade2652bdac16656ba4ed821d74528a6de188fa0) +--- + lib/launch-direct.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/lib/launch-direct.c b/lib/launch-direct.c +index 9cc153b21..147e158de 100644 +--- a/lib/launch-direct.c ++++ b/lib/launch-direct.c +@@ -592,8 +592,15 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) + ADD_CMDLINE (VIRTIO_SERIAL); + + /* Create the serial console. */ ++#ifndef __s390x__ + ADD_CMDLINE ("-serial"); + ADD_CMDLINE ("stdio"); ++#else ++ ADD_CMDLINE ("-chardev"); ++ ADD_CMDLINE ("stdio,id=charconsole0"); ++ ADD_CMDLINE ("-device"); ++ ADD_CMDLINE ("sclpconsole,chardev=charconsole0"); ++#endif + + if (g->verbose && + guestfs_int_qemu_supports_device (g, data->qemu_data, +-- +2.14.3 + diff --git a/SOURCES/0037-v2v-tests-Fix-i-vmx-test-so-it-is-more-stable.patch b/SOURCES/0037-v2v-tests-Fix-i-vmx-test-so-it-is-more-stable.patch deleted file mode 100644 index 81b8164..0000000 --- a/SOURCES/0037-v2v-tests-Fix-i-vmx-test-so-it-is-more-stable.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 427106e2ca70009c30706f0a55ba72c51cd13e0d Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Wed, 12 Apr 2017 08:32:58 +0100 -Subject: [PATCH] v2v: tests: Fix -i vmx test so it is more stable. - -When running under valgrind, the process takes a fraction of a second -to start up, changing the "Opening the guest" timestamp, which broke -the test. - -Fixes commit ca40078cdda9167d4658ddfe24c828c7ee76be37. - -(cherry picked from commit ec61873d397f050fe28987f10ec919778d27818a) ---- - v2v/test-v2v-i-vmx-1.expected | 2 +- - v2v/test-v2v-i-vmx-2.expected | 2 +- - v2v/test-v2v-i-vmx-3.expected | 2 +- - v2v/test-v2v-i-vmx-4.expected | 2 +- - v2v/test-v2v-i-vmx.sh | 1 + - 5 files changed, 5 insertions(+), 4 deletions(-) - -diff --git a/v2v/test-v2v-i-vmx-1.expected b/v2v/test-v2v-i-vmx-1.expected -index d32a29987..902a850c5 100644 ---- a/v2v/test-v2v-i-vmx-1.expected -+++ b/v2v/test-v2v-i-vmx-1.expected -@@ -1,4 +1,4 @@ --[ 0.0] Opening the source -i vmx test-v2v-i-vmx-1.vmx -+ - Source guest information (--print-source option): - - source name: BZ1308535_21disks -diff --git a/v2v/test-v2v-i-vmx-2.expected b/v2v/test-v2v-i-vmx-2.expected -index dc3eb60f2..6e87862ac 100644 ---- a/v2v/test-v2v-i-vmx-2.expected -+++ b/v2v/test-v2v-i-vmx-2.expected -@@ -1,4 +1,4 @@ --[ 0.0] Opening the source -i vmx test-v2v-i-vmx-2.vmx -+ - Source guest information (--print-source option): - - source name: Fedora 20 -diff --git a/v2v/test-v2v-i-vmx-3.expected b/v2v/test-v2v-i-vmx-3.expected -index 9e643526f..0d1585b96 100644 ---- a/v2v/test-v2v-i-vmx-3.expected -+++ b/v2v/test-v2v-i-vmx-3.expected -@@ -1,4 +1,4 @@ --[ 0.0] Opening the source -i vmx test-v2v-i-vmx-3.vmx -+ - Source guest information (--print-source option): - - source name: RHEL 7.1 UEFI -diff --git a/v2v/test-v2v-i-vmx-4.expected b/v2v/test-v2v-i-vmx-4.expected -index a70533d2e..06f58d7ad 100644 ---- a/v2v/test-v2v-i-vmx-4.expected -+++ b/v2v/test-v2v-i-vmx-4.expected -@@ -1,4 +1,4 @@ --[ 0.0] Opening the source -i vmx test-v2v-i-vmx-4.vmx -+ - Source guest information (--print-source option): - - source name: Windows 7 x64 -diff --git a/v2v/test-v2v-i-vmx.sh b/v2v/test-v2v-i-vmx.sh -index 5353e7e2a..997103d41 100755 ---- a/v2v/test-v2v-i-vmx.sh -+++ b/v2v/test-v2v-i-vmx.sh -@@ -37,6 +37,7 @@ for i in 1 2 3 4; do - # Normalize the print-source output. - mv test-v2v-i-vmx-$i.actual test-v2v-i-vmx-$i.actual.old - sed \ -+ -e "s,.*Opening the source.*,," \ - -e "s,$(pwd),," \ - < test-v2v-i-vmx-$i.actual.old > test-v2v-i-vmx-$i.actual - rm test-v2v-i-vmx-$i.actual.old --- -2.13.4 - diff --git a/SOURCES/0038-s390x-appliance-Use-dev-ttysclp0-for-serial-console.patch b/SOURCES/0038-s390x-appliance-Use-dev-ttysclp0-for-serial-console.patch new file mode 100644 index 0000000..6592e9d --- /dev/null +++ b/SOURCES/0038-s390x-appliance-Use-dev-ttysclp0-for-serial-console.patch @@ -0,0 +1,26 @@ +From 1dc3311d91d3d0caa2796ea5b52e07d84b2d3a90 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 17 May 2017 11:24:39 +0200 +Subject: [PATCH] s390x: appliance: Use /dev/ttysclp0 for serial console. + +(cherry picked from commit 5fc76d6d10a1095c9301edbf4716114e4e94882c) +--- + lib/appliance-kcmdline.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/lib/appliance-kcmdline.c b/lib/appliance-kcmdline.c +index 4dde7a865..ff7bda494 100644 +--- a/lib/appliance-kcmdline.c ++++ b/lib/appliance-kcmdline.c +@@ -44,6 +44,8 @@ + #define SERIAL_CONSOLE "console=hvc0 console=ttyS0" + #elif defined(__arm__) || defined(__aarch64__) + #define SERIAL_CONSOLE "console=ttyAMA0" ++#elif defined(__s390x__) ++#define SERIAL_CONSOLE "console=ttysclp0" + #else + #define SERIAL_CONSOLE "console=ttyS0" + #endif +-- +2.14.3 + diff --git a/SOURCES/0038-v2v-o-rhv-Quote-parameter-to-rm-rf.patch b/SOURCES/0038-v2v-o-rhv-Quote-parameter-to-rm-rf.patch deleted file mode 100644 index 4646451..0000000 --- a/SOURCES/0038-v2v-o-rhv-Quote-parameter-to-rm-rf.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0828c8f3f4fceaba6fab17d2dfaf689702265c85 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 13 Apr 2017 09:57:37 +0100 -Subject: [PATCH] v2v: -o rhv: Quote parameter to rm -rf. - -This was safe before, the change just prevents accidental errors. - -(cherry picked from commit 24a6c5b57c25e0e59697831b55000d6f8e21fd38) ---- - v2v/output_rhv.ml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/output_rhv.ml b/v2v/output_rhv.ml -index f407b4eda..02bd31269 100644 ---- a/v2v/output_rhv.ml -+++ b/v2v/output_rhv.ml -@@ -205,7 +205,7 @@ object - List.iter ( - fun image_uuid -> - let d = images_dir // image_uuid in -- let cmd = sprintf "rm -rf %s" d in -+ let cmd = sprintf "rm -rf %s" (quote d) in - Changeuid.command changeuid_t cmd - ) image_uuids - ) --- -2.13.4 - diff --git a/SOURCES/0039-init-Add-comment-that-we-should-consider-using-proc-.patch b/SOURCES/0039-init-Add-comment-that-we-should-consider-using-proc-.patch new file mode 100644 index 0000000..98cdce5 --- /dev/null +++ b/SOURCES/0039-init-Add-comment-that-we-should-consider-using-proc-.patch @@ -0,0 +1,29 @@ +From 630c80558888131c094c15d8854a527d3c41261f Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 17 May 2017 11:38:05 +0200 +Subject: [PATCH] init: Add comment that we should consider using + /proc/consoles. + +Although we can't use it at the moment because it is incorrect +on at least s390x (RHBZ#1351968). + +(cherry picked from commit fa6bc0fd83317d43df38c50bf94966b31024ca35) +--- + appliance/init | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/appliance/init b/appliance/init +index 2c9aecd5f..735ba8946 100755 +--- a/appliance/init ++++ b/appliance/init +@@ -179,6 +179,7 @@ else + # Run virt-rescue shell. + + # Get name of the serial port, from console= passed by libguestfs. ++ # XXX Consider using /proc/consoles + guestfs_serial=$(grep -Eo 'console=[^[:space:]]+' /proc/cmdline | + sed s/console=//) + +-- +2.14.3 + diff --git a/SOURCES/0039-v2v-windows-Install-both-legacy-and-modern-virtio-ke.patch b/SOURCES/0039-v2v-windows-Install-both-legacy-and-modern-virtio-ke.patch deleted file mode 100644 index 62912ab..0000000 --- a/SOURCES/0039-v2v-windows-Install-both-legacy-and-modern-virtio-ke.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 30ffdce6bc603f1aaf0ee77270bd1d8ff09cbf0c Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Wed, 12 Apr 2017 23:09:32 +0100 -Subject: [PATCH] v2v: windows: Install both legacy and modern virtio keys in - the registry (RHBZ#1431579). - -Thanks: Kun Wei (for finding the bug) -Thanks: Ladi Prosek (for diagnosing the problem and proposing the fix) -(cherry picked from commit d8e1c4bb474203d71903261fb06fe267c3cce3c7) ---- - v2v/windows_virtio.ml | 12 ++++++++---- - 1 file changed, 8 insertions(+), 4 deletions(-) - -diff --git a/v2v/windows_virtio.ml b/v2v/windows_virtio.ml -index 965d6ac8b..9e6088c28 100644 ---- a/v2v/windows_virtio.ml -+++ b/v2v/windows_virtio.ml -@@ -34,8 +34,10 @@ let virtio_win = - Guestfs_config.datadir // "virtio-win" - - let scsi_class_guid = "{4D36E97B-E325-11CE-BFC1-08002BE10318}" --let viostor_pciid = "VEN_1AF4&DEV_1001&SUBSYS_00021AF4&REV_00" --let vioscsi_pciid = "VEN_1AF4&DEV_1004&SUBSYS_00081AF4&REV_00" -+let viostor_legacy_pciid = "VEN_1AF4&DEV_1001&SUBSYS_00021AF4&REV_00" -+let viostor_modern_pciid = "VEN_1AF4&DEV_1042&SUBSYS_11001AF4&REV_01" -+let vioscsi_legacy_pciid = "VEN_1AF4&DEV_1004&SUBSYS_00081AF4&REV_00" -+let vioscsi_modern_pciid = "VEN_1AF4&DEV_1048&SUBSYS_11001AF4&REV_01" - - let rec install_drivers ((g, _) as reg) inspect rcaps = - (* Copy the virtio drivers to the guest. *) -@@ -102,7 +104,8 @@ let rec install_drivers ((g, _) as reg) inspect rcaps = - inspect.i_windows_systemroot driver_name in - let target = g#case_sensitive_path target in - g#cp source target; -- add_guestor_to_registry reg inspect driver_name viostor_pciid; -+ add_guestor_to_registry reg inspect driver_name viostor_legacy_pciid; -+ add_guestor_to_registry reg inspect driver_name viostor_modern_pciid; - Virtio_blk - - | Some Virtio_SCSI, _, true -> -@@ -113,7 +116,8 @@ let rec install_drivers ((g, _) as reg) inspect rcaps = - inspect.i_windows_systemroot in - let target = g#case_sensitive_path target in - g#cp source target; -- add_guestor_to_registry reg inspect "vioscsi" vioscsi_pciid; -+ add_guestor_to_registry reg inspect "vioscsi" vioscsi_legacy_pciid; -+ add_guestor_to_registry reg inspect "vioscsi" vioscsi_modern_pciid; - Virtio_SCSI - - | Some IDE, _, _ -> --- -2.13.4 - diff --git a/SOURCES/0040-s390x-launch-direct-Use-virtio-ccw-on-this-architect.patch b/SOURCES/0040-s390x-launch-direct-Use-virtio-ccw-on-this-architect.patch new file mode 100644 index 0000000..478530a --- /dev/null +++ b/SOURCES/0040-s390x-launch-direct-Use-virtio-ccw-on-this-architect.patch @@ -0,0 +1,77 @@ +From 516f008f29e77d676907208e51e2f57bb73888aa Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 16 May 2017 19:58:59 +0200 +Subject: [PATCH] s390x: launch: direct: Use virtio-*-ccw on this architecture. + +PCI devices don't exist/work. You would see errors such as: + +qemu-system-s390x: -device virtio-rng-pci,rng=rng0: MSI-X support is mandatory in the S390 architecture +(cherry picked from commit ddde6f9e2f14ccf8d91a8587052d0abcfb6496f1) +--- + lib/guestfs-internal.h | 26 +++++++++++++++++--------- + lib/launch-direct.c | 4 ++-- + 2 files changed, 19 insertions(+), 11 deletions(-) + +diff --git a/lib/guestfs-internal.h b/lib/guestfs-internal.h +index 949cacfef..f035e0931 100644 +--- a/lib/guestfs-internal.h ++++ b/lib/guestfs-internal.h +@@ -142,20 +142,28 @@ + /* Maximum size of Windows explorer.exe. 2.6MB on Windows 7. */ + #define MAX_WINDOWS_EXPLORER_SIZE (4 * 1000 * 1000) + +-/* Differences in device names on ARM (virtio-mmio) vs normal +- * hardware with PCI. ++/* Differences in device names on ARMv7 (virtio-mmio), s/390x (CCW) vs ++ * normal hardware with PCI. + */ +-#if !defined(__arm__) +-#define VIRTIO_BLK "virtio-blk-pci" +-#define VIRTIO_SCSI "virtio-scsi-pci" +-#define VIRTIO_SERIAL "virtio-serial-pci" +-#define VIRTIO_NET "virtio-net-pci" +-#else /* ARMv7 */ ++#if defined(__arm__) + #define VIRTIO_BLK "virtio-blk-device" + #define VIRTIO_SCSI "virtio-scsi-device" + #define VIRTIO_SERIAL "virtio-serial-device" + #define VIRTIO_NET "virtio-net-device" +-#endif /* ARMv7 */ ++#define VIRTIO_RNG "virtio-rng-device" ++#elif defined(__s390x__) ++#define VIRTIO_BLK "virtio-blk-ccw" ++#define VIRTIO_SCSI "virtio-scsi-ccw" ++#define VIRTIO_SERIAL "virtio-serial-ccw" ++#define VIRTIO_NET "virtio-net-ccw" ++#define VIRTIO_RNG "virtio-rng-ccw" ++#else ++#define VIRTIO_BLK "virtio-blk-pci" ++#define VIRTIO_SCSI "virtio-scsi-pci" ++#define VIRTIO_SERIAL "virtio-serial-pci" ++#define VIRTIO_NET "virtio-net-pci" ++#define VIRTIO_RNG "virtio-rng-pci" ++#endif + + /* Machine types. */ + #ifdef __arm__ +diff --git a/lib/launch-direct.c b/lib/launch-direct.c +index 147e158de..c8841bfe4 100644 +--- a/lib/launch-direct.c ++++ b/lib/launch-direct.c +@@ -463,11 +463,11 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) + * when needing entropy. + */ + if (guestfs_int_qemu_supports_device (g, data->qemu_data, +- "virtio-rng-pci")) { ++ VIRTIO_RNG)) { + ADD_CMDLINE ("-object"); + ADD_CMDLINE ("rng-random,filename=/dev/urandom,id=rng0"); + ADD_CMDLINE ("-device"); +- ADD_CMDLINE ("virtio-rng-pci,rng=rng0"); ++ ADD_CMDLINE (VIRTIO_RNG ",rng=rng0"); + } + + /* Add drives */ +-- +2.14.3 + diff --git a/SOURCES/0040-v2v-o-rhv-Add-Windows-2016-Server-type-in-OVF-output.patch b/SOURCES/0040-v2v-o-rhv-Add-Windows-2016-Server-type-in-OVF-output.patch deleted file mode 100644 index 895d438..0000000 --- a/SOURCES/0040-v2v-o-rhv-Add-Windows-2016-Server-type-in-OVF-output.patch +++ /dev/null @@ -1,38 +0,0 @@ -From e2ebd5a963612aec0f9035c7603739cf8245ce59 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 2 May 2017 10:57:53 +0100 -Subject: [PATCH] v2v: -o rhv: Add Windows 2016 Server type in OVF output - (RHBZ#1447202). - -Thanks: Kun Wei - -See also: -https://github.com/oVirt/ovirt-engine/commit/d233325d7b808e8bae83645ac645dfea9dfe8407 - -(cherry picked from commit d0344f3522c116d3ccba6d52cd100562ee6e1e23) ---- - v2v/OVF.ml | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/v2v/OVF.ml b/v2v/OVF.ml -index 1f838f543..e380d35f6 100644 ---- a/v2v/OVF.ml -+++ b/v2v/OVF.ml -@@ -194,9 +194,13 @@ and get_ostype = function - "windows_10" - - | { i_type = "windows"; i_major_version = 10; i_minor_version = 0; -- i_arch = "x86_64" } -> -+ i_arch = "x86_64"; i_product_variant = "Client" } -> - "windows_10x64" - -+ | { i_type = "windows"; i_major_version = 10; i_minor_version = 0; -+ i_arch = "x86_64" } -> -+ "windows_2016x64" -+ - | { i_type = typ; i_distro = distro; - i_major_version = major; i_minor_version = minor; i_arch = arch; - i_product_name = product } -> --- -2.13.4 - diff --git a/SOURCES/0041-daemon-lvm-Pass-yes-option-to-force-pvresize-RHBZ-14.patch b/SOURCES/0041-daemon-lvm-Pass-yes-option-to-force-pvresize-RHBZ-14.patch deleted file mode 100644 index ab0ecee..0000000 --- a/SOURCES/0041-daemon-lvm-Pass-yes-option-to-force-pvresize-RHBZ-14.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 8b72cf35f3c758aca31269f454339fdffeccbcf0 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 12 Jun 2017 13:15:34 +0100 -Subject: [PATCH] daemon: lvm: Pass --yes option to force pvresize - (RHBZ#1460577). -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -LVM2 >= 2.02.171 requires the ‘--yes’ option to force pvresize to work -in various circumstances, eg. reducing the size of an existing PV. - -Pass this flag unconditionally. - -Note this does NOT break earlier versions which just ignore this flag. - -(cherry picked from commit 8a98fe91b889f666c8160f4c23af220247b4b8f3) ---- - daemon/lvm.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/daemon/lvm.c b/daemon/lvm.c -index a270b1305..085e852f1 100644 ---- a/daemon/lvm.c -+++ b/daemon/lvm.c -@@ -625,6 +625,7 @@ do_pvresize_size (const char *device, int64_t size) - - r = command (NULL, &err, - str_lvm, "pvresize", -+ "--yes", - "--setphysicalvolumesize", buf, - device, NULL); - if (r == -1) { --- -2.13.4 - diff --git a/SOURCES/0041-s390x-tests-regressions-Skip-IDE-tests-on-S-390.patch b/SOURCES/0041-s390x-tests-regressions-Skip-IDE-tests-on-S-390.patch new file mode 100644 index 0000000..a9ecc13 --- /dev/null +++ b/SOURCES/0041-s390x-tests-regressions-Skip-IDE-tests-on-S-390.patch @@ -0,0 +1,40 @@ +From a5a3600b8341278ee8c18dca89b9a9ba75ec2eca Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 17 May 2017 13:38:43 +0200 +Subject: [PATCH] s390x: tests: regressions: Skip IDE tests on S/390. + +IDE interface is not supported. + +(cherry picked from commit 93af83de853b87c555624227741bdf8af1918703) +--- + tests/regressions/rhbz690819.sh | 1 + + tests/regressions/rhbz975797.sh | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/tests/regressions/rhbz690819.sh b/tests/regressions/rhbz690819.sh +index d18b4d81a..0b790862d 100755 +--- a/tests/regressions/rhbz690819.sh ++++ b/tests/regressions/rhbz690819.sh +@@ -29,6 +29,7 @@ skip_if_arch arm + skip_if_arch aarch64 + skip_if_arch ppc64 + skip_if_arch ppc64le ++skip_if_arch s390x + skip_if_backend libvirt + # UML doesn't support the 'iface' parameter. + skip_if_backend uml +diff --git a/tests/regressions/rhbz975797.sh b/tests/regressions/rhbz975797.sh +index bc6a1c63f..04e8d23de 100755 +--- a/tests/regressions/rhbz975797.sh ++++ b/tests/regressions/rhbz975797.sh +@@ -29,6 +29,7 @@ skip_if_arch arm + skip_if_arch aarch64 + skip_if_arch ppc64 + skip_if_arch ppc64le ++skip_if_arch s390x + skip_if_backend libvirt + # UML doesn't support the 'iface' parameter. + skip_if_backend uml +-- +2.14.3 + diff --git a/SOURCES/0042-lib-Add-VIRTIO_DEVICE_NAME-macro-to-handle-virtio-mm.patch b/SOURCES/0042-lib-Add-VIRTIO_DEVICE_NAME-macro-to-handle-virtio-mm.patch new file mode 100644 index 0000000..bf204d6 --- /dev/null +++ b/SOURCES/0042-lib-Add-VIRTIO_DEVICE_NAME-macro-to-handle-virtio-mm.patch @@ -0,0 +1,155 @@ +From eddfb0a765e0246d0fb397414f32403f055488a3 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 18 May 2017 15:59:38 +0100 +Subject: [PATCH] lib: Add VIRTIO_DEVICE_NAME macro to handle virtio-mmio vs + CCW vs virtio-PCI. + +(cherry picked from commit a5bd493e3f90945cb8e913f9c680bedbdf26aaaa) + +PT: the VIRTIO_DEVICE_NAME macros are left in guestfs-internal.h, since +the VIRTIO_* macros were used in other places than launch-direct.c. +--- + lib/guestfs-internal.h | 22 +++++----------------- + lib/launch-direct.c | 16 ++++++++-------- + lib/launch-libvirt.c | 2 +- + lib/qemu.c | 2 +- + 4 files changed, 15 insertions(+), 27 deletions(-) + +diff --git a/lib/guestfs-internal.h b/lib/guestfs-internal.h +index f035e0931..d962aacd4 100644 +--- a/lib/guestfs-internal.h ++++ b/lib/guestfs-internal.h +@@ -142,27 +142,15 @@ + /* Maximum size of Windows explorer.exe. 2.6MB on Windows 7. */ + #define MAX_WINDOWS_EXPLORER_SIZE (4 * 1000 * 1000) + +-/* Differences in device names on ARMv7 (virtio-mmio), s/390x (CCW) vs +- * normal hardware with PCI. ++/* Differences in qemu device names on ARMv7 (virtio-mmio), s/390x ++ * (CCW) vs normal hardware with PCI. + */ + #if defined(__arm__) +-#define VIRTIO_BLK "virtio-blk-device" +-#define VIRTIO_SCSI "virtio-scsi-device" +-#define VIRTIO_SERIAL "virtio-serial-device" +-#define VIRTIO_NET "virtio-net-device" +-#define VIRTIO_RNG "virtio-rng-device" ++#define VIRTIO_DEVICE_NAME(type) type "-device" + #elif defined(__s390x__) +-#define VIRTIO_BLK "virtio-blk-ccw" +-#define VIRTIO_SCSI "virtio-scsi-ccw" +-#define VIRTIO_SERIAL "virtio-serial-ccw" +-#define VIRTIO_NET "virtio-net-ccw" +-#define VIRTIO_RNG "virtio-rng-ccw" ++#define VIRTIO_DEVICE_NAME(type) type "-ccw" + #else +-#define VIRTIO_BLK "virtio-blk-pci" +-#define VIRTIO_SCSI "virtio-scsi-pci" +-#define VIRTIO_SERIAL "virtio-serial-pci" +-#define VIRTIO_NET "virtio-net-pci" +-#define VIRTIO_RNG "virtio-rng-pci" ++#define VIRTIO_DEVICE_NAME(type) type "-pci" + #endif + + /* Machine types. */ +diff --git a/lib/launch-direct.c b/lib/launch-direct.c +index c8841bfe4..0fef05927 100644 +--- a/lib/launch-direct.c ++++ b/lib/launch-direct.c +@@ -349,7 +349,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) + */ + if (guestfs_int_qemu_supports (g, data->qemu_data, "-global")) { + ADD_CMDLINE ("-global"); +- ADD_CMDLINE (VIRTIO_BLK ".scsi=off"); ++ ADD_CMDLINE (VIRTIO_DEVICE_NAME ("virtio-blk") ".scsi=off"); + } + + if (guestfs_int_qemu_supports (g, data->qemu_data, "-nodefconfig")) +@@ -463,11 +463,11 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) + * when needing entropy. + */ + if (guestfs_int_qemu_supports_device (g, data->qemu_data, +- VIRTIO_RNG)) { ++ VIRTIO_DEVICE_NAME ("virtio-rng"))) { + ADD_CMDLINE ("-object"); + ADD_CMDLINE ("rng-random,filename=/dev/urandom,id=rng0"); + ADD_CMDLINE ("-device"); +- ADD_CMDLINE (VIRTIO_RNG ",rng=rng0"); ++ ADD_CMDLINE (VIRTIO_DEVICE_NAME ("virtio-rng") ",rng=rng0"); + } + + /* Add drives */ +@@ -477,7 +477,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) + if (virtio_scsi) { + /* Create the virtio-scsi bus. */ + ADD_CMDLINE ("-device"); +- ADD_CMDLINE (VIRTIO_SCSI ",id=scsi"); ++ ADD_CMDLINE (VIRTIO_DEVICE_NAME ("virtio-scsi") ",id=scsi"); + } + + ITER_DRIVES (g, i, drv) { +@@ -564,7 +564,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) + ADD_CMDLINE ("-drive"); + ADD_CMDLINE_PRINTF ("%s,if=none" /* sic */, param); + ADD_CMDLINE ("-device"); +- ADD_CMDLINE_PRINTF (VIRTIO_BLK ",drive=hd%zu", i); ++ ADD_CMDLINE_PRINTF (VIRTIO_DEVICE_NAME ("virtio-blk") ",drive=hd%zu", i); + } + } + +@@ -581,7 +581,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) + } + else { + ADD_CMDLINE ("-device"); +- ADD_CMDLINE (VIRTIO_BLK ",drive=appliance"); ++ ADD_CMDLINE (VIRTIO_DEVICE_NAME ("virtio-blk") ",drive=appliance"); + } + + appliance_dev = make_appliance_dev (g, virtio_scsi); +@@ -589,7 +589,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) + + /* Create the virtio serial bus. */ + ADD_CMDLINE ("-device"); +- ADD_CMDLINE (VIRTIO_SERIAL); ++ ADD_CMDLINE (VIRTIO_DEVICE_NAME ("virtio-serial")); + + /* Create the serial console. */ + #ifndef __s390x__ +@@ -626,7 +626,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) + ADD_CMDLINE ("-netdev"); + ADD_CMDLINE ("user,id=usernet,net=169.254.0.0/16"); + ADD_CMDLINE ("-device"); +- ADD_CMDLINE (VIRTIO_NET ",netdev=usernet"); ++ ADD_CMDLINE (VIRTIO_DEVICE_NAME ("virtio-net") ",netdev=usernet"); + } + + ADD_CMDLINE ("-append"); +diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c +index 49bd40583..d10c7cb40 100644 +--- a/lib/launch-libvirt.c ++++ b/lib/launch-libvirt.c +@@ -1803,7 +1803,7 @@ construct_libvirt_xml_qemu_cmdline (guestfs_h *g, + } end_element (); + + start_element ("qemu:arg") { +- attribute ("value", VIRTIO_NET ",netdev=usernet"); ++ attribute ("value", VIRTIO_DEVICE_NAME ("virtio-net") ",netdev=usernet"); + } end_element (); + } + +diff --git a/lib/qemu.c b/lib/qemu.c +index c9debe937..887e31bc4 100644 +--- a/lib/qemu.c ++++ b/lib/qemu.c +@@ -619,7 +619,7 @@ guestfs_int_qemu_supports_virtio_scsi (guestfs_h *g, struct qemu_data *data, + if (old_or_broken_virtio_scsi (qemu_version)) + data->virtio_scsi = 2; + else { +- r = guestfs_int_qemu_supports_device (g, data, VIRTIO_SCSI); ++ r = guestfs_int_qemu_supports_device (g, data, VIRTIO_DEVICE_NAME ("virtio-scsi")); + if (r > 0) + data->virtio_scsi = 1; + else if (r == 0) +-- +2.14.3 + diff --git a/SOURCES/0042-resize-make-sure-the-input-disk-is-read-only.patch b/SOURCES/0042-resize-make-sure-the-input-disk-is-read-only.patch deleted file mode 100644 index 57f41f9..0000000 --- a/SOURCES/0042-resize-make-sure-the-input-disk-is-read-only.patch +++ /dev/null @@ -1,28 +0,0 @@ -From f1ed6a32939717d89e7bc3f9c0934b7788f2708a Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Wed, 21 Jun 2017 16:34:05 +0200 -Subject: [PATCH] resize: make sure the input disk is read-only - -Fixes commit 8a2b0738d1b79f288b14fc35294567430d10b7ec. - -(cherry picked from commit 1ca2a8b7ba41d7e4baf1aec5d65ace3b66f2dc37) ---- - resize/resize.ml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/resize/resize.ml b/resize/resize.ml -index dc96b23ea..4028aa1ac 100644 ---- a/resize/resize.ml -+++ b/resize/resize.ml -@@ -348,7 +348,7 @@ read the man page virt-resize(1). - (* Add in and out disks to the handle and launch. *) - let connect_both_disks () = - let g = open_guestfs () in -- add_drive_uri g ?format (snd infile); -+ add_drive_uri g ?format ~readonly:true (snd infile); - (* The output disk is being created, so use cache=unsafe here. *) - add_drive_uri g ?format:output_format ~readonly:false ~cachemode:"unsafe" - (snd outfile); --- -2.13.4 - diff --git a/SOURCES/0043-lib-libvirt-Pass-copyonread-flag-through-to-the-libv.patch b/SOURCES/0043-lib-libvirt-Pass-copyonread-flag-through-to-the-libv.patch deleted file mode 100644 index 5fb5f1d..0000000 --- a/SOURCES/0043-lib-libvirt-Pass-copyonread-flag-through-to-the-libv.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 1f182ed648b7cf9d4f9f9fdceeb5be69cd2be4ae Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 29 Jun 2017 23:59:15 +0100 -Subject: [PATCH] lib: libvirt: Pass copyonread flag through to the libvirt XML - (RHBZ#1466563). - -We were dropping the add_drive copyonread flag when using the libvirt -backend. This resulted in significant performance degradation (2x-3x -slower) when running virt-v2v against VMware servers. - -Thanks: Kun Wei. - -(cherry picked from commit d96209ef07fef3db0e411648348f1b1dcf384e70) ---- - lib/launch-libvirt.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c -index 0c2879dbf..144937b5b 100644 ---- a/lib/launch-libvirt.c -+++ b/lib/launch-libvirt.c -@@ -1547,7 +1547,8 @@ construct_libvirt_xml_disk (guestfs_h *g, - - if (construct_libvirt_xml_disk_driver_qemu (g, data, drv, xo, format, - drv->cachemode ? : "writeback", -- drv->discard, false) -+ drv->discard, -+ drv->copyonread) - == -1) - return -1; - } --- -2.13.4 - diff --git a/SOURCES/0043-v2v-i-vmx-Allow-deviceType-field-to-be-completely-om.patch b/SOURCES/0043-v2v-i-vmx-Allow-deviceType-field-to-be-completely-om.patch new file mode 100644 index 0000000..718d515 --- /dev/null +++ b/SOURCES/0043-v2v-i-vmx-Allow-deviceType-field-to-be-completely-om.patch @@ -0,0 +1,81 @@ +From 46aaa657c76d473fcd6ac41a84101d7805306f58 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 11 Oct 2017 13:43:26 +0100 +Subject: [PATCH] v2v: -i vmx: Allow deviceType field to be completely omitted. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Microsoft make some VMX files available here which we could not parse. +These files lack the expected ‘scsi0:0.deviceType’ field: +https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/ + +According to +http://faq.sanbarrow.com/index.php?action=artikel&cat=7&id=54&artlang=en +this is permitted. Also several other deviceType values may be found. + +Allow such VMX to be parsed. + +Thanks: Tom Sorensen + +Cherry picked from commit 418289029da9641b74984eb15eb1563649c38dd1. +For RHEL 7.5: I inlined the Option.map function since that does not +exist in this branch. +--- + v2v/input_vmx.ml | 19 +++++++++++-------- + 1 file changed, 11 insertions(+), 8 deletions(-) + +diff --git a/v2v/input_vmx.ml b/v2v/input_vmx.ml +index bb09f0bf8..a4f77c2ab 100644 +--- a/v2v/input_vmx.ml ++++ b/v2v/input_vmx.ml +@@ -35,7 +35,8 @@ let rec find_disks vmx vmx_filename = + * + * In the VMX file: + * scsi0.virtualDev = "pvscsi" # or may be "lsilogic" etc. +- * scsi0:0.deviceType = "scsi-hardDisk" ++ * scsi0:0.deviceType = "disk" | "plainDisk" | "rawDisk" | "scsi-hardDisk" ++ * | omitted + * scsi0:0.fileName = "guest.vmdk" + *) + and find_scsi_disks vmx vmx_filename = +@@ -46,7 +47,8 @@ and find_scsi_disks vmx vmx_filename = + try ignore (get_scsi_controller_target ns); true + with Scanf.Scan_failure _ | End_of_file | Failure _ -> false + in +- let scsi_device_types = [ "scsi-harddisk" ] in ++ let scsi_device_types = [ Some "disk"; Some "plaindisk"; Some "rawdisk"; ++ Some "scsi-harddisk"; None ] in + let scsi_controller = Source_SCSI in + + find_hdds vmx vmx_filename +@@ -67,7 +69,7 @@ and find_ide_disks vmx vmx_filename = + try ignore (get_ide_controller_target ns); true + with Scanf.Scan_failure _ | End_of_file | Failure _ -> false + in +- let ide_device_types = [ "ata-harddisk" ] in ++ let ide_device_types = [ Some "ata-harddisk" ] in + let ide_controller = Source_IDE in + + find_hdds vmx vmx_filename +@@ -86,11 +88,12 @@ and find_hdds vmx vmx_filename + if not (is_controller_target ns) then false + else ( + (* Check the deviceType is one we are looking for. *) +- match Parse_vmx.get_string vmx [ns; "deviceType"] with +- | Some str -> +- let str = String.lowercase_ascii str in +- List.mem str device_types +- | None -> false ++ let dt = Parse_vmx.get_string vmx [ns; "deviceType"] in ++ let dt = ++ match dt with ++ | None -> None ++ | Some dt -> Some (String.lowercase_ascii dt) in ++ List.mem dt device_types + ) + | _ -> false + ) vmx in +-- +2.14.3 + diff --git a/SOURCES/0044-RHEL-7-v2v-disable-unconfig-of-manually-installed-VM.patch b/SOURCES/0044-RHEL-7-v2v-disable-unconfig-of-manually-installed-VM.patch deleted file mode 100644 index 2bb50df..0000000 --- a/SOURCES/0044-RHEL-7-v2v-disable-unconfig-of-manually-installed-VM.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 6e33d4506d9a454921cac0207646ff1a1ba02684 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Mon, 14 Aug 2017 10:02:13 +0200 -Subject: [PATCH] RHEL 7: v2v: disable unconfig of manually installed VMware - tools (RHBZ#1477905) - -It looks like they may require connection to the VMware servers, which -is not always available during conversion. ---- - v2v/convert_linux.ml | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml -index 6c4985e84..d5c5825f4 100644 ---- a/v2v/convert_linux.ml -+++ b/v2v/convert_linux.ml -@@ -295,6 +295,7 @@ let rec convert (g : G.guestfs) inspect source output rcaps = - let remove = !remove in - Linux.remove g inspect remove; - -+(* - (* VMware Tools may have been installed from a tarball, so the - * above code won't remove it. Look for the uninstall tool and run - * if present. -@@ -311,6 +312,8 @@ let rec convert (g : G.guestfs) inspect source output rcaps = - warning (f_"VMware tools was detected, but uninstallation failed. The error message was: %s (ignored)") - msg - ) -+*) -+ () - - and unconfigure_citrix () = - let pkgs = --- -2.13.4 - diff --git a/SOURCES/0044-v2v-i-vmx-Add-a-test-case-which-lacks-scsi0-0.device.patch b/SOURCES/0044-v2v-i-vmx-Add-a-test-case-which-lacks-scsi0-0.device.patch new file mode 100644 index 0000000..f0522a5 --- /dev/null +++ b/SOURCES/0044-v2v-i-vmx-Add-a-test-case-which-lacks-scsi0-0.device.patch @@ -0,0 +1,146 @@ +From 18f83f6a6945e7356a880c6b861c758e399ac55c Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 11 Oct 2017 13:33:12 +0100 +Subject: [PATCH] v2v: -i vmx: Add a test case which lacks scsi0:0.deviceType = + "scsi-hardDisk" + +VMX file from: +https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/ + +Thanks: Tom Sorensen +(cherry picked from commit 6c54b68acb707d8f3dcd80453c23f57c54989be9) +--- + v2v/test-v2v-i-vmx-5.expected | 19 ++++++++++ + v2v/test-v2v-i-vmx-5.vmx | 80 +++++++++++++++++++++++++++++++++++++++++++ + v2v/test-v2v-i-vmx.sh | 2 +- + 3 files changed, 100 insertions(+), 1 deletion(-) + create mode 100644 v2v/test-v2v-i-vmx-5.expected + create mode 100644 v2v/test-v2v-i-vmx-5.vmx + +diff --git a/v2v/test-v2v-i-vmx-5.expected b/v2v/test-v2v-i-vmx-5.expected +new file mode 100644 +index 000000000..4a33db13c +--- /dev/null ++++ b/v2v/test-v2v-i-vmx-5.expected +@@ -0,0 +1,19 @@ ++ ++Source guest information (--print-source option): ++ ++ source name: MSEdge - Win10_preview ++hypervisor type: vmware ++ memory: 2147483648 (bytes) ++ nr vCPUs: 1 ++ CPU features: ++ firmware: bios ++ display: ++ video: ++ sound: ++disks: ++ /MSEdge - Win10_preview.vmdk (vmdk) [scsi] ++removable media: ++ ++NICs: ++ Bridge "ethernet0" mac: 00:0c:29:bf:e4:5d [e1000e] ++ +diff --git a/v2v/test-v2v-i-vmx-5.vmx b/v2v/test-v2v-i-vmx-5.vmx +new file mode 100644 +index 000000000..eb54d85be +--- /dev/null ++++ b/v2v/test-v2v-i-vmx-5.vmx +@@ -0,0 +1,80 @@ ++.encoding = "UTF-8" ++config.version = "8" ++virtualHW.version = "11" ++memsize = "2048" ++MemAllowAutoScaleDown = "FALSE" ++displayName = "MSEdge - Win10_preview" ++guestOS = "windows9-64" ++cpuid.coresPerSocket = "1" ++vmci0.present = "TRUE" ++ethernet0.present = "TRUE" ++ethernet0.addressType = "generated" ++ethernet0.connectionType = "bridged" ++ethernet0.virtualDev = "e1000e" ++ethernet0.startConnected = "TRUE" ++scsi0.present = "TRUE" ++scsi0.virtualDev = "lsisas1068" ++scsi0:0.present = "TRUE" ++scsi0:0.fileName = "MSEdge - Win10_preview.vmdk" ++bios.bootorder = "hdd,CDROM" ++cleanshutdown = "TRUE" ++ethernet0.bsdname = "en0" ++ethernet0.displayname = "Ethernet" ++ethernet0.linkstatepropagation.enable = "FALSE" ++gui.fullscreenatpoweron = "FALSE" ++gui.viewmodeatpoweron = "windowed" ++hgfs.linkrootshare = "TRUE" ++hgfs.maprootshare = "TRUE" ++isolation.tools.hgfs.disable = "FALSE" ++monitor.phys_bits_used = "42" ++msg.autoanswer = "true" ++numa.autosize.cookie = "10001" ++numa.autosize.vcpu.maxpervirtualnode = "1" ++nvram = "MSEdge - Win10_preview.nvram" ++proxyapps.publishtohost = "FALSE" ++remotedisplay.vnc.enabled = "FALSE" ++remotedisplay.vnc.port = "5900" ++replay.filename = "" ++replay.supported = "FALSE" ++scsi0:0.redo = "" ++softpoweroff = "TRUE" ++tools.synctime = "true" ++uuid.action = "create" ++virtualhw.productcompatibility = "hosted" ++vm.genid = "-570734802784577186" ++vm.genidx = "-5042519231342505152" ++vmotion.checkpointfbsize = "33554432" ++pciBridge0.present = "TRUE" ++tools.upgrade.policy = "useGlobal" ++pciBridge4.present = "TRUE" ++pciBridge4.virtualDev = "pcieRootPort" ++pciBridge4.functions = "8" ++pciBridge5.present = "TRUE" ++pciBridge5.virtualDev = "pcieRootPort" ++pciBridge5.functions = "8" ++pciBridge6.present = "TRUE" ++pciBridge6.virtualDev = "pcieRootPort" ++pciBridge6.functions = "8" ++pciBridge7.present = "TRUE" ++pciBridge7.virtualDev = "pcieRootPort" ++pciBridge7.functions = "8" ++hpet0.present = "TRUE" ++extendedConfigFile = "MSEdge - Win10_preview.vmxf" ++uuid.bios = "56 4d 54 59 5d 0c 51 8d-d3 40 38 4f fe bf e4 5d" ++uuid.location = "56 4d 54 59 5d 0c 51 8d-d3 40 38 4f fe bf e4 5d" ++migrate.hostlog = ".\MSEdge - Win10_preview-aee69569.hlog" ++pciBridge0.pciSlotNumber = "17" ++pciBridge4.pciSlotNumber = "21" ++pciBridge5.pciSlotNumber = "22" ++pciBridge6.pciSlotNumber = "23" ++pciBridge7.pciSlotNumber = "24" ++scsi0.pciSlotNumber = "160" ++ethernet0.pciSlotNumber = "192" ++vmci0.pciSlotNumber = "32" ++scsi0.sasWWID = "50 05 05 69 5d 0c 51 80" ++ethernet0.generatedAddress = "00:0c:29:bf:e4:5d" ++ethernet0.generatedAddressOffset = "0" ++vmci0.id = "-20978595" ++vmotion.checkpointSVGAPrimarySize = "33554432" ++toolsInstallManager.updateCounter = "1" ++toolsInstallManager.lastInstallError = "21004" +diff --git a/v2v/test-v2v-i-vmx.sh b/v2v/test-v2v-i-vmx.sh +index 997103d41..3822e7426 100755 +--- a/v2v/test-v2v-i-vmx.sh ++++ b/v2v/test-v2v-i-vmx.sh +@@ -29,7 +29,7 @@ export VIRTIO_WIN="$top_srcdir/test-data/fake-virtio-win" + + rm -f test-v2v-i-vmx-*.actual + +-for i in 1 2 3 4; do ++for i in 1 2 3 4 5; do + $VG virt-v2v --debug-gc \ + -i vmx test-v2v-i-vmx-$i.vmx \ + --print-source > test-v2v-i-vmx-$i.actual +-- +2.14.3 + diff --git a/SOURCES/0045-v2v-vddk-Print-passthrough-options.patch b/SOURCES/0045-v2v-vddk-Print-passthrough-options.patch new file mode 100644 index 0000000..355d423 --- /dev/null +++ b/SOURCES/0045-v2v-vddk-Print-passthrough-options.patch @@ -0,0 +1,78 @@ +From e94aedc6fc64f255ab1fa2fcd31f78e86c28c5de Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 16 Oct 2017 14:32:28 +0100 +Subject: [PATCH] v2v: vddk: Print passthrough options. + +Changes the output to look like: + +[ 0.0] Opening the source -i libvirt -ic vpx://... guestname --vddk ... --vddk-thumbprint ... + +(cherry picked from commit ce2aa47d1d79223c1a7a49b3f41e09078f22f554) +--- + v2v/input_libvirt_vddk.ml | 42 ++++++++++++++++++++++++++++++++---------- + 1 file changed, 32 insertions(+), 10 deletions(-) + +diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml +index 89d2552f6..b322a9c49 100644 +--- a/v2v/input_libvirt_vddk.ml ++++ b/v2v/input_libvirt_vddk.ml +@@ -101,8 +101,34 @@ See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") library_path + error (f_"You must pass the ‘--vddk-thumbprint’ option with the SSL thumbprint of the VMware server. To find the thumbprint, see the nbdkit-vddk-plugin(1) manual. See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") + in + ++ (* List of passthrough parameters. *) ++ let vddk_passthrus = ++ [ "config", (fun { vddk_config } -> vddk_config); ++ "cookie", (fun { vddk_cookie } -> vddk_cookie); ++ "nfchostport", (fun { vddk_nfchostport } -> vddk_nfchostport); ++ "port", (fun { vddk_port } -> vddk_port); ++ "snapshot", (fun { vddk_snapshot } -> vddk_snapshot); ++ "thumbprint", (fun { vddk_thumbprint } -> vddk_thumbprint); ++ "transports", (fun { vddk_transports } -> vddk_transports); ++ "vimapiver", (fun { vddk_vimapiver } -> vddk_vimapiver) ] in ++ + object +- inherit input_libvirt password libvirt_uri guest ++ inherit input_libvirt password libvirt_uri guest as super ++ ++ method as_options = ++ let pt_options = ++ String.concat "" ( ++ List.map ( ++ fun (name, get_field) -> ++ match get_field vddk_options with ++ | None -> "" ++ | Some field -> sprintf " --vddk-%s %s" name field ++ ) vddk_passthrus ++ ) in ++ sprintf "%s --vddk %s%s" ++ super#as_options (* superclass prints "-i libvirt etc" *) ++ vddk_options.vddk_libdir ++ pt_options + + method source () = + error_unless_vddk_libdir (); +@@ -209,15 +235,11 @@ object + add_arg (sprintf "libdir=%s" libdir); + + (* The passthrough parameters. *) +- let pt name = may (fun field -> add_arg (sprintf "%s=%s" name field)) in +- pt "config" vddk_options.vddk_config; +- pt "cookie" vddk_options.vddk_cookie; +- pt "nfchostport" vddk_options.vddk_nfchostport; +- pt "port" vddk_options.vddk_port; +- pt "snapshot" vddk_options.vddk_snapshot; +- pt "thumbprint" vddk_options.vddk_thumbprint; +- pt "transports" vddk_options.vddk_transports; +- pt "vimapiver" vddk_options.vddk_vimapiver; ++ List.iter ( ++ fun (name, get_field) -> ++ may (fun field -> add_arg (sprintf "%s=%s" name field)) ++ (get_field vddk_options) ++ ) vddk_passthrus; + + get_args () in + +-- +2.14.3 + diff --git a/SOURCES/0046-v2v-vddk-Check-if-nbdkit-supports-selinux-label-befo.patch b/SOURCES/0046-v2v-vddk-Check-if-nbdkit-supports-selinux-label-befo.patch new file mode 100644 index 0000000..1401342 --- /dev/null +++ b/SOURCES/0046-v2v-vddk-Check-if-nbdkit-supports-selinux-label-befo.patch @@ -0,0 +1,51 @@ +From bf7dba21337b2671f877f4e37e5eb031b26fc6e2 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 17 Oct 2017 10:43:30 +0100 +Subject: [PATCH] v2v: vddk: Check if nbdkit supports --selinux-label before + using. + +Give a better error message if not. + +Thanks: Ming Xie. +(cherry picked from commit 59b4c4779f7dac645c794393d91c46467afab91c) +--- + v2v/input_libvirt_vddk.ml | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml +index b322a9c49..f0b150efa 100644 +--- a/v2v/input_libvirt_vddk.ml ++++ b/v2v/input_libvirt_vddk.ml +@@ -101,6 +101,20 @@ See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") library_path + error (f_"You must pass the ‘--vddk-thumbprint’ option with the SSL thumbprint of the VMware server. To find the thumbprint, see the nbdkit-vddk-plugin(1) manual. See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") + in + ++ (* Check that nbdkit was compiled with SELinux support (for the ++ * --selinux-label option). ++ *) ++ let error_unless_nbdkit_compiled_with_selinux () = ++ let lines = external_command "nbdkit --dump-config" in ++ (* In nbdkit <= 1.1.15 the selinux attribute was not present ++ * at all in --dump-config output so there was no way to tell. ++ * Ignore this case because there will be an error later when ++ * we try to use the --selinux-label parameter. ++ *) ++ if List.mem "selinux=no" (List.map String.trim lines) then ++ error (f_"nbdkit was compiled without SELinux support. You will have to recompile nbdkit with libselinux-devel installed, or else set SELinux to Permissive mode while doing the conversion.") ++ in ++ + (* List of passthrough parameters. *) + let vddk_passthrus = + [ "config", (fun { vddk_config } -> vddk_config); +@@ -135,6 +149,8 @@ object + error_unless_nbdkit_working (); + error_unless_nbdkit_vddk_working (); + error_unless_thumbprint (); ++ if have_selinux then ++ error_unless_nbdkit_compiled_with_selinux (); + + (* Get the libvirt XML. This also checks (as a side-effect) + * that the domain is not running. (RHBZ#1138586) +-- +2.14.3 + diff --git a/SOURCES/0047-v2v-vddk-Force-source-format-to-raw.patch b/SOURCES/0047-v2v-vddk-Force-source-format-to-raw.patch new file mode 100644 index 0000000..0771002 --- /dev/null +++ b/SOURCES/0047-v2v-vddk-Force-source-format-to-raw.patch @@ -0,0 +1,31 @@ +From 37f2bf9dff5e01904556248203f1dce9c9034eed Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 17 Oct 2017 10:56:14 +0100 +Subject: [PATCH] v2v: vddk: Force source format to raw. + +Thanks: Ming Xie. +(cherry picked from commit 2ff287c4a7f12c26b8fb3a574129fbfb9a9157e7) +--- + v2v/input_libvirt_vddk.ml | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml +index f0b150efa..33b34bd2e 100644 +--- a/v2v/input_libvirt_vddk.ml ++++ b/v2v/input_libvirt_vddk.ml +@@ -338,7 +338,11 @@ If the messages above are not sufficient to diagnose the problem then add the + *) + chmod sock 0o777; + +- { disk with s_qemu_uri = qemu_uri } ++ (* nbdkit from a vddk source always presents us with the raw ++ * disk blocks from the guest, so force the format to raw here. ++ *) ++ { disk with s_qemu_uri = qemu_uri; ++ s_format = Some "raw" } + ) disks in + + if verbose () then ( +-- +2.14.3 + diff --git a/SOURCES/0048-v2v-Remove-dcpath-parameter-and-related-functionalit.patch b/SOURCES/0048-v2v-Remove-dcpath-parameter-and-related-functionalit.patch new file mode 100644 index 0000000..5eeaae5 --- /dev/null +++ b/SOURCES/0048-v2v-Remove-dcpath-parameter-and-related-functionalit.patch @@ -0,0 +1,322 @@ +From 8018cf4c1206253c0f58e79b9afc171b3855b826 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 13 Oct 2017 15:45:39 +0100 +Subject: [PATCH] v2v: Remove --dcpath parameter and related functionality. + +With modern libvirt, when fetching the XML of a VMware guest libvirt +passes us the datacenter path (dcpath). However with older libvirt we +had to guess this value, or else the user had to supply it on the +command line. + +This commit removes all the guessing code and the --dcpath parameter +(which will now give an error). + +This requires libvirt >= 1.2.20 for virt-v2v, released Oct 2015. + +(cherry picked from commit 3fdd923ce2d31e21a441042f9ded3c45dec6bbcb) +--- + v2v/cmdline.ml | 6 +---- + v2v/copy_to_local.ml | 15 ++++++------ + v2v/input_libvirt.ml | 4 ++-- + v2v/input_libvirt.mli | 4 ++-- + v2v/input_libvirt_vcenter_https.ml | 31 +++++++----------------- + v2v/input_libvirt_vcenter_https.mli | 2 +- + v2v/test-v2v-docs.sh | 2 +- + v2v/vCenter.ml | 47 +------------------------------------ + v2v/vCenter.mli | 8 ------- + v2v/virt-v2v.pod | 13 ---------- + 10 files changed, 24 insertions(+), 108 deletions(-) + +diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml +index 3050104d0..dfbb776ab 100644 +--- a/v2v/cmdline.ml ++++ b/v2v/cmdline.ml +@@ -54,7 +54,6 @@ let parse_cmdline () = + let print_source = ref false in + let qemu_boot = ref false in + +- let dcpath = ref None in + let input_conn = ref None in + let input_format = ref None in + let in_place = ref false in +@@ -181,8 +180,6 @@ let parse_cmdline () = + let argspec = [ + [ S 'b'; L"bridge" ], Getopt.String ("in:out", add_bridge), s_"Map bridge 'in' to 'out'"; + [ L"compressed" ], Getopt.Set compressed, s_"Compress output file (-of qcow2 only)"; +- [ L"dcpath"; L"dcPath" ], Getopt.String ("path", set_string_option_once "--dcpath" dcpath), +- s_"Override dcPath (for vCenter)"; + [ L"debug-overlay"; L"debug-overlays" ], Getopt.Set debug_overlays, s_"Save overlay files"; + [ S 'i' ], Getopt.String (i_options, set_input_mode), s_"Set input mode (default: libvirt)"; + [ M"ic" ], Getopt.String ("uri", set_string_option_once "-ic" input_conn), +@@ -268,7 +265,6 @@ read the man page virt-v2v(1). + (* Dereference the arguments. *) + let args = List.rev !args in + let compressed = !compressed in +- let dcpath = !dcpath in + let debug_overlays = !debug_overlays in + let do_copy = !do_copy in + let input_conn = !input_conn in +@@ -367,7 +363,7 @@ read the man page virt-v2v(1). + | [guest] -> guest + | _ -> + error (f_"expecting a libvirt guest name on the command line") in +- Input_libvirt.input_libvirt dcpath vddk_options password input_conn guest ++ Input_libvirt.input_libvirt vddk_options password input_conn guest + + | `LibvirtXML -> + (* -i libvirtxml: Expecting a filename (XML file). *) +diff --git a/v2v/copy_to_local.ml b/v2v/copy_to_local.ml +index 88fd9abde..ca5578f3f 100644 +--- a/v2v/copy_to_local.ml ++++ b/v2v/copy_to_local.ml +@@ -144,6 +144,11 @@ read the man page virt-v2v-copy-to-local(1). + let disks = + match source with + | ESXi server -> ++ let dcpath = ++ match dcpath with ++ | Some dcpath -> dcpath ++ | None -> ++ error (f_"vcenter: was not found in the XML. You need to upgrade to libvirt ≥ 1.2.20.") in + List.map ( + fun (remote_disk, local_disk) -> + let url, sslverify = +@@ -242,14 +247,10 @@ and parse_libvirt_xml guest_name xml = + let xpathctx = Xml.xpath_new_context doc in + Xml.xpath_register_ns xpathctx + "vmware" "http://libvirt.org/schemas/domain/vmware/1.0"; +- let xpath_string = xpath_string xpathctx +- and xpath_string_default = xpath_string_default xpathctx in ++ let xpath_string = xpath_string xpathctx in + +- (* Get the dcpath, only present for libvirt >= 1.2.20 so use a +- * sensible default for older versions. +- *) +- let dcpath = +- xpath_string_default "/domain/vmware:datacenterpath" "ha-datacenter" in ++ (* Get the dcpath, present in libvirt >= 1.2.20. *) ++ let dcpath = xpath_string "/domain/vmware:datacenterpath" in + + (* Parse the disks. *) + let get_disks, add_disk = +diff --git a/v2v/input_libvirt.ml b/v2v/input_libvirt.ml +index e8143b6ad..f4a8114f0 100644 +--- a/v2v/input_libvirt.ml ++++ b/v2v/input_libvirt.ml +@@ -27,7 +27,7 @@ open Types + open Utils + + (* Choose the right subclass based on the URI. *) +-let input_libvirt dcpath vddk_options password libvirt_uri guest = ++let input_libvirt vddk_options password libvirt_uri guest = + match libvirt_uri with + | None -> + Input_libvirt_other.input_libvirt_other password libvirt_uri guest +@@ -54,7 +54,7 @@ let input_libvirt dcpath vddk_options password libvirt_uri guest = + (match vddk_options with + | None -> + Input_libvirt_vcenter_https.input_libvirt_vcenter_https +- dcpath password libvirt_uri parsed_uri scheme server guest ++ password libvirt_uri parsed_uri scheme server guest + | Some vddk_options -> + Input_libvirt_vddk.input_libvirt_vddk vddk_options password + libvirt_uri parsed_uri guest +diff --git a/v2v/input_libvirt.mli b/v2v/input_libvirt.mli +index 0a6aa3c54..acf2ca417 100644 +--- a/v2v/input_libvirt.mli ++++ b/v2v/input_libvirt.mli +@@ -18,7 +18,7 @@ + + (** [-i libvirt] source. *) + +-val input_libvirt : string option -> Types.vddk_options option -> string option -> string option -> string -> Types.input +-(** [input_libvirt dcpath vddk_options password libvirt_uri guest] creates ++val input_libvirt : Types.vddk_options option -> string option -> string option -> string -> Types.input ++(** [input_libvirt vddk_options password libvirt_uri guest] creates + and returns a new {!Types.input} object specialized for reading input + from libvirt sources. *) +diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml +index df0e89315..497caca4f 100644 +--- a/v2v/input_libvirt_vcenter_https.ml ++++ b/v2v/input_libvirt_vcenter_https.ml +@@ -36,7 +36,7 @@ let readahead_for_copying = Some (64 * 1024 * 1024) + + (* Subclass specialized for handling VMware vCenter over https. *) + class input_libvirt_vcenter_https +- cmdline_dcPath password libvirt_uri parsed_uri scheme server guest = ++ password libvirt_uri parsed_uri scheme server guest = + object + inherit input_libvirt password libvirt_uri guest + +@@ -68,33 +68,18 @@ object + let xml = Libvirt_utils.dumpxml ?password ?conn:libvirt_uri guest in + let source, disks = parse_libvirt_xml ?conn:libvirt_uri xml in + +- (* Find the element from the XML, if it +- * exists. This was added in libvirt >= 1.2.20. ++ (* Find the element from the XML. This ++ * was added in libvirt >= 1.2.20. + *) +- let xml_dcPath = ++ dcPath <- ( + let doc = Xml.parse_memory xml in + let xpathctx = Xml.xpath_new_context doc in + Xml.xpath_register_ns xpathctx + "vmware" "http://libvirt.org/schemas/domain/vmware/1.0"; +- let xpath_string = xpath_string xpathctx in +- xpath_string "/domain/vmware:datacenterpath" in +- +- (* Calculate the dcPath we're going to use. *) +- dcPath <- ( +- match cmdline_dcPath, xml_dcPath with +- (* Command line --dcpath parameter overrides everything, allowing +- * users to correct any mistakes in v2v or libvirt. +- *) +- | Some p, (None|Some _) -> +- debug "vcenter: using --dcpath from the command line: %s" p; +- p +- | None, Some p -> +- debug "vcenter: using from libvirt: %s" p; +- p +- | None, None -> +- let p = VCenter.guess_dcPath parsed_uri scheme in +- debug "vcenter: guessed dcPath from URI: %s" p; +- p ++ match xpath_string xpathctx "/domain/vmware:datacenterpath" with ++ | Some dcPath -> dcPath ++ | None -> ++ error (f_"vcenter: was not found in the XML. You need to upgrade to libvirt ≥ 1.2.20.") + ); + + (* Save the original source paths, so that we can remap them again +diff --git a/v2v/input_libvirt_vcenter_https.mli b/v2v/input_libvirt_vcenter_https.mli +index 840b5a90f..d347f5fe6 100644 +--- a/v2v/input_libvirt_vcenter_https.mli ++++ b/v2v/input_libvirt_vcenter_https.mli +@@ -18,4 +18,4 @@ + + (** [-i libvirt] when the source is VMware vCenter *) + +-val input_libvirt_vcenter_https : string option -> string option -> string option -> Xml.uri -> string -> string -> string -> Types.input ++val input_libvirt_vcenter_https : string option -> string option -> Xml.uri -> string -> string -> string -> Types.input +diff --git a/v2v/test-v2v-docs.sh b/v2v/test-v2v-docs.sh +index c5d98de7f..5e49d5240 100755 +--- a/v2v/test-v2v-docs.sh ++++ b/v2v/test-v2v-docs.sh +@@ -22,4 +22,4 @@ $TEST_FUNCTIONS + skip_if_skipped + + $top_srcdir/podcheck.pl virt-v2v.pod virt-v2v \ +- --ignore=--dcPath,--debug-overlay,--ic,--if,--in-place,--no-trim,--oa,--oc,--of,--on,--os,--vmtype ++ --ignore=--debug-overlay,--ic,--if,--in-place,--no-trim,--oa,--oc,--of,--on,--os,--vmtype +diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml +index f6e4288f2..2f7e32ad6 100644 +--- a/v2v/vCenter.ml ++++ b/v2v/vCenter.ml +@@ -99,7 +99,7 @@ let get_session_cookie password scheme uri sslverify url = + + if status = "404" then ( + dump_response stderr; +- error (f_"vcenter: URL not found: %s\n\nThe '--dcpath' parameter may be useful. See the explanation in the virt-v2v(1) man page OPTIONS section.") url ++ error (f_"vcenter: URL not found: %s") url + ); + + if status <> "200" then ( +@@ -126,51 +126,6 @@ let get_session_cookie password scheme uri sslverify url = + Some !session_cookie + ) + +-let multiple_slash = Str.regexp "/+" +-let default_dc = "ha-datacenter" +- +-let guess_dcPath uri = function +- | "vpx" -> +- (match uri.uri_path with +- | None -> +- warning (f_"vcenter: URI (-ic parameter) contains no path, so we cannot determine the dcPath (datacenter name)"); +- default_dc +- | Some path -> +- (* vCenter: URIs are *usually* '/Folder/Datacenter/esxi' so we can +- * just chop off the first '/' and final '/esxi' to get the dcPath. +- * +- * The libvirt driver allows things like '/DC///esxi////' so we also +- * have to handle trailing slashes and collapse multiple slashes into +- * single (RHBZ#1258342). +- * +- * However if there is a cluster involved then the URI may be +- * /Folder/Datacenter/Cluster/esxi but dcPath=Folder/Datacenter/Cluster +- * won't work. In this case the user has to adjust the path to +- * remove the Cluster name (which still works in libvirt). +- *) +- (* Collapse multiple slashes to single slash. *) +- let path = Str.global_replace multiple_slash "/" path in +- (* Chop off the first and trailing '/' (if found). *) +- let path = +- let len = String.length path in +- if len > 0 && path.[0] = '/' then +- String.sub path 1 (len-1) +- else path in +- let path = +- let len = String.length path in +- if len > 0 && path.[len-1] = '/' then +- String.sub path 0 (len-1) +- else path in +- (* Chop off the final element (ESXi hostname). *) +- let len = +- try String.rindex path '/' with Not_found -> String.length path in +- String.sub path 0 len +- ); +- | "esx" -> (* Connecting to an ESXi hypervisor directly, so it's fixed. *) +- default_dc +- | _ -> (* Don't know, so guess. *) +- default_dc +- + let source_re = Str.regexp "^\\[\\(.*\\)\\] \\(.*\\)\\.vmdk$" + + let map_source_to_https dcPath uri server path = +diff --git a/v2v/vCenter.mli b/v2v/vCenter.mli +index 224f45009..55d70b486 100644 +--- a/v2v/vCenter.mli ++++ b/v2v/vCenter.mli +@@ -35,14 +35,6 @@ val get_session_cookie : string option -> string -> Xml.uri -> bool -> string -> + The session cookie is memoized so you can call this function as + often as you want, and only a single log in is made. *) + +-val guess_dcPath : Xml.uri -> string -> string +-(** Try to guess the dcPath parameter from a URI. The mapping is +- not precise. +- +- This function is only used with [libvirt < 1.2.20] because later +- versions of libvirt provide the dcPath (see +- https://bugzilla.redhat.com/1263574). *) +- + val map_source_to_uri : int option -> string -> string option -> Xml.uri -> string -> string -> string -> string + (** [map_source_to_uri readahead dcPath password uri scheme server path] + maps the [] string to a qemu URI. +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index d713d0b1f..92ed147d7 100644 +--- a/v2v/virt-v2v.pod ++++ b/v2v/virt-v2v.pod +@@ -172,19 +172,6 @@ Write a compressed output file. This is only allowed if the output + format is qcow2 (see I<-of> below), and is equivalent to the I<-c> + option of L. + +-=item B<--dcpath> Folder/Datacenter +- +-B You don't need to use this parameter if you have +-S 1.2.20>. +- +-For VMware vCenter, override the C parameter used to +-select the datacenter. Virt-v2v can usually calculate this from the +-C URI, but if it gets it wrong, then you can override it using +-this setting. Go to your vCenter web folder interface, eg. +-C (I a trailing slash), +-and examine the C parameter in the URLs that appear on this +-page. +- + =item B<--debug-overlays> + + Save the overlay file(s) created during conversion. This option is +-- +2.14.3 + diff --git a/SOURCES/0049-v2v-vCenter-Refactor-the-API-to-this-module.patch b/SOURCES/0049-v2v-vCenter-Refactor-the-API-to-this-module.patch new file mode 100644 index 0000000..fe05d32 --- /dev/null +++ b/SOURCES/0049-v2v-vCenter-Refactor-the-API-to-this-module.patch @@ -0,0 +1,496 @@ +From f00bde700faf0708c8af440efdcc6b48e93f3ce4 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 13 Oct 2017 16:30:16 +0100 +Subject: [PATCH] v2v: vCenter: Refactor the API to this module. + +This module had a selection of functions taking a different mix of +parameters and doing slightly different things. You could call one +function to return an https://... URL, or another function to return a +qemu URL, and there was a third function to get the session cookie but +you generally had to call that anyway (and it was implicitly called +when making the qemu URL!) + +Integrate these into a single function which returns a struct +returning all possible values. + +This is conceptually refactoring, except that the session cookie is no +longer memoized, but we didn't use this feature (of calling +get_session_cookie multiple times) anyway. + +(cherry picked from commit fb79fcde2947ff7e73f96343e8311e43b22a6f66) +--- + v2v/copy_to_local.ml | 12 +- + v2v/input_libvirt_vcenter_https.ml | 12 +- + v2v/vCenter.ml | 319 +++++++++++++++++++------------------ + v2v/vCenter.mli | 66 +++++--- + 4 files changed, 211 insertions(+), 198 deletions(-) + +diff --git a/v2v/copy_to_local.ml b/v2v/copy_to_local.ml +index ca5578f3f..5fb1b79ff 100644 +--- a/v2v/copy_to_local.ml ++++ b/v2v/copy_to_local.ml +@@ -151,14 +151,10 @@ read the man page virt-v2v-copy-to-local(1). + error (f_"vcenter: was not found in the XML. You need to upgrade to libvirt ≥ 1.2.20.") in + List.map ( + fun (remote_disk, local_disk) -> +- let url, sslverify = +- VCenter.map_source_to_https dcpath parsed_uri +- server remote_disk in +- debug "esxi: source disk %s (sslverify=%b)" url sslverify; +- let cookie = +- VCenter.get_session_cookie password "esx" +- parsed_uri sslverify url in +- (url, local_disk, sslverify, cookie) ++ let { VCenter.https_url; sslverify; session_cookie } = ++ VCenter.map_source dcpath parsed_uri "esx" server remote_disk in ++ debug "esxi: source disk %s (sslverify=%b)" https_url sslverify; ++ (https_url, local_disk, sslverify, session_cookie) + ) disks + | Test | Xen_ssh _ -> + List.map (fun (remote_disk, local_disk) -> +diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml +index 497caca4f..1153e74a3 100644 +--- a/v2v/input_libvirt_vcenter_https.ml ++++ b/v2v/input_libvirt_vcenter_https.ml +@@ -102,9 +102,9 @@ object + | { p_source = P_source_dev _ } -> assert false + | { p_source_disk = disk; p_source = P_dont_rewrite } -> disk + | { p_source_disk = disk; p_source = P_source_file path } -> +- let qemu_uri = +- VCenter.map_source_to_uri readahead dcPath password +- parsed_uri scheme server path in ++ let { VCenter.qemu_uri } = ++ VCenter.map_source ?readahead ?password ++ dcPath parsed_uri scheme server path in + + (* The libvirt ESX driver doesn't normally specify a format, but + * the format of the -flat file is *always* raw, so force it here. +@@ -123,9 +123,9 @@ object + | None -> () + | Some orig_path -> + let readahead = readahead_for_copying in +- let backing_qemu_uri = +- VCenter.map_source_to_uri readahead dcPath password +- parsed_uri scheme server orig_path in ++ let { VCenter.qemu_uri = backing_qemu_uri } = ++ VCenter.map_source ?readahead ?password ++ dcPath parsed_uri scheme server orig_path in + + (* Rebase the qcow2 overlay to adjust the readahead parameter. *) + let cmd = [ "qemu-img"; "rebase"; "-u"; "-b"; backing_qemu_uri; +diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml +index 2f7e32ad6..341a40b25 100644 +--- a/v2v/vCenter.ml ++++ b/v2v/vCenter.ml +@@ -38,167 +38,168 @@ let uri_quote str = + done; + String.concat "" (List.rev !xs) + +-(* Memoized session cookie. *) +-let session_cookie = ref "" +- +-let get_session_cookie password scheme uri sslverify url = +- if !session_cookie <> "" then +- Some !session_cookie +- else ( +- let curl_args = ref [ +- "head", None; +- "silent", None; +- "url", Some url; +- ] in +- (match uri.uri_user, password with +- | None, None -> () +- | None, Some _ -> +- warning (f_"--password-file parameter ignored because 'user@' was not given in the URL") +- | Some user, None -> +- push_back curl_args ("user", Some user) +- | Some user, Some password -> +- push_back curl_args ("user", Some (user ^ ":" ^ password)) +- ); +- if not sslverify then push_back curl_args ("insecure", None); +- +- let curl_h = Curl.create !curl_args in +- let lines = Curl.run curl_h in +- +- let dump_response chan = +- Curl.print chan curl_h; +- +- (* Dump out the output of the command. *) +- List.iter (fun x -> fprintf chan "%s\n" x) lines; +- flush chan +- in +- +- if verbose () then dump_response stderr; +- +- (* Look for the last HTTP/x.y NNN status code in the output. *) +- let status = ref "" in +- List.iter ( +- fun line -> +- let len = String.length line in +- if len >= 12 && String.sub line 0 5 = "HTTP/" then +- status := String.sub line 9 3 +- ) lines; +- let status = !status in +- if status = "" then ( +- dump_response stderr; +- error (f_"vcenter: no status code in output of 'curl' command. Is 'curl' installed?") +- ); +- +- if status = "401" then ( +- dump_response stderr; +- if uri.uri_user <> None then +- error (f_"vcenter: incorrect username or password") +- else +- error (f_"vcenter: incorrect username or password. You might need to specify the username in the URI like this: %s://USERNAME@[etc]") +- scheme +- ); +- +- if status = "404" then ( +- dump_response stderr; +- error (f_"vcenter: URL not found: %s") url +- ); +- +- if status <> "200" then ( +- dump_response stderr; +- error (f_"vcenter: invalid response from server") +- ); +- +- (* Get the cookie. *) +- List.iter ( +- fun line -> +- let len = String.length line in +- if len >= 12 && String.sub line 0 12 = "Set-Cookie: " then ( +- let line = String.sub line 12 (len-12) in +- let cookie, _ = String.split ";" line in +- session_cookie := cookie +- ) +- ) lines; +- if !session_cookie = "" then ( +- dump_response stderr; +- warning (f_"vcenter: could not read session cookie from the vCenter Server, conversion may consume all sessions on the server and fail part way through"); +- None +- ) +- else +- Some !session_cookie +- ) ++type remote_resource = { ++ https_url : string; ++ qemu_uri : string; ++ session_cookie : string option; ++ sslverify : bool; ++} + + let source_re = Str.regexp "^\\[\\(.*\\)\\] \\(.*\\)\\.vmdk$" + +-let map_source_to_https dcPath uri server path = +- if not (Str.string_match source_re path 0) then +- (path, true) +- else ( +- let datastore = Str.matched_group 1 path +- and path = Str.matched_group 2 path in +- +- let port = +- match uri.uri_port with +- | 443 -> "" +- | n when n >= 1 -> ":" ^ string_of_int n +- | _ -> "" in +- +- (* XXX Old virt-v2v could also handle snapshots, ie: +- * "[datastore1] Fedora 20/Fedora 20-NNNNNN.vmdk" +- * XXX Need to handle templates. The file is called "-delta.vmdk" in +- * place of "-flat.vmdk". +- *) +- let url = +- sprintf +- "https://%s%s/folder/%s-flat.vmdk?dcPath=%s&dsName=%s" +- server port +- (uri_quote path) (uri_quote dcPath) (uri_quote datastore) in +- +- (* If no_verify=1 was passed in the libvirt URI, then we have to +- * turn off certificate verification here too. +- *) +- let sslverify = +- match uri.uri_query_raw with +- | None -> true +- | Some query -> +- (* XXX only works if the query string is not URI-quoted *) +- String.find query "no_verify=1" = -1 in +- +- (url, sslverify) +- ) +- +-let map_source_to_uri readahead dcPath password uri scheme server path = +- let url, sslverify = map_source_to_https dcPath uri server path in +- +- (* Now we have to query the server to get the session cookie. *) +- let session_cookie = get_session_cookie password scheme uri sslverify url in +- +- (* Construct the JSON parameters. *) +- let json_params = [ +- "file.driver", JSON.String "https"; +- "file.url", JSON.String url; +- (* https://bugzilla.redhat.com/show_bug.cgi?id=1146007#c10 *) +- "file.timeout", JSON.Int 2000; +- ] in +- +- let json_params = +- match readahead with +- | None -> json_params +- | Some readahead -> +- ("file.readahead", JSON.Int readahead) :: json_params in +- +- let json_params = +- if sslverify then json_params +- else ("file.sslverify", JSON.String "off") :: json_params in +- +- let json_params = +- match session_cookie with +- | None -> json_params +- | Some cookie -> ("file.cookie", JSON.String cookie) :: json_params in +- +- debug "vcenter: json parameters: %s" (JSON.string_of_doc json_params); +- +- (* Turn the JSON parameters into a 'json:' protocol string. +- * Note this requires qemu-img >= 2.1.0. ++let rec map_source ?readahead ?password dcPath uri scheme server path = ++ (* If no_verify=1 was passed in the libvirt URI, then we have to ++ * turn off certificate verification here too. + *) +- let qemu_uri = "json: " ^ JSON.string_of_doc json_params in ++ let sslverify = ++ match uri.uri_query_raw with ++ | None -> true ++ | Some query -> ++ (* XXX only works if the query string is not URI-quoted *) ++ String.find query "no_verify=1" = -1 in + +- qemu_uri ++ let https_url = ++ if not (Str.string_match source_re path 0) then ++ path ++ else ( ++ let datastore = Str.matched_group 1 path ++ and path = Str.matched_group 2 path in ++ ++ let port = ++ match uri.uri_port with ++ | 443 -> "" ++ | n when n >= 1 -> ":" ^ string_of_int n ++ | _ -> "" in ++ ++ (* XXX Old virt-v2v could also handle snapshots, ie: ++ * "[datastore1] Fedora 20/Fedora 20-NNNNNN.vmdk" ++ * XXX Need to handle templates. The file is called "-delta.vmdk" in ++ * place of "-flat.vmdk". ++ *) ++ sprintf "https://%s%s/folder/%s-flat.vmdk?dcPath=%s&dsName=%s" ++ server port ++ (uri_quote path) (uri_quote dcPath) (uri_quote datastore) ++ ) in ++ ++ let session_cookie = ++ get_session_cookie password scheme uri sslverify https_url in ++ ++ let qemu_uri = ++ (* Construct the JSON parameters for the qemu URI. *) ++ let json_params = [ ++ "file.driver", JSON.String "https"; ++ "file.url", JSON.String https_url; ++ (* https://bugzilla.redhat.com/show_bug.cgi?id=1146007#c10 *) ++ "file.timeout", JSON.Int 2000; ++ ] in ++ ++ let json_params = ++ match readahead with ++ | None -> json_params ++ | Some readahead -> ++ ("file.readahead", JSON.Int readahead) :: json_params in ++ ++ let json_params = ++ if sslverify then json_params ++ else ("file.sslverify", JSON.String "off") :: json_params in ++ ++ let json_params = ++ match session_cookie with ++ | None -> json_params ++ | Some cookie -> ("file.cookie", JSON.String cookie) :: json_params in ++ ++ debug "vcenter: json parameters: %s" (JSON.string_of_doc json_params); ++ ++ (* Turn the JSON parameters into a 'json:' protocol string. ++ * Note this requires qemu-img >= 2.1.0. ++ *) ++ let qemu_uri = "json: " ^ JSON.string_of_doc json_params in ++ ++ qemu_uri in ++ ++ (* Return the struct. *) ++ { https_url = https_url; ++ qemu_uri = qemu_uri; ++ session_cookie = session_cookie; ++ sslverify = sslverify } ++ ++and get_session_cookie password scheme uri sslverify https_url = ++ let curl_args = ref [ ++ "head", None; ++ "silent", None; ++ "url", Some https_url; ++ ] in ++ (match uri.uri_user, password with ++ | None, None -> () ++ | None, Some _ -> ++ warning (f_"--password-file parameter ignored because 'user@' was not given in the URL") ++ | Some user, None -> ++ push_back curl_args ("user", Some user) ++ | Some user, Some password -> ++ push_back curl_args ("user", Some (user ^ ":" ^ password)) ++ ); ++ if not sslverify then push_back curl_args ("insecure", None); ++ ++ let curl_h = Curl.create !curl_args in ++ let lines = Curl.run curl_h in ++ ++ let dump_response chan = ++ Curl.print chan curl_h; ++ ++ (* Dump out the output of the command. *) ++ List.iter (fun x -> fprintf chan "%s\n" x) lines; ++ flush chan ++ in ++ ++ if verbose () then dump_response stderr; ++ ++ (* Look for the last HTTP/x.y NNN status code in the output. *) ++ let status = ref "" in ++ List.iter ( ++ fun line -> ++ let len = String.length line in ++ if len >= 12 && String.sub line 0 5 = "HTTP/" then ++ status := String.sub line 9 3 ++ ) lines; ++ let status = !status in ++ if status = "" then ( ++ dump_response stderr; ++ error (f_"vcenter: no status code in output of ‘curl’ command. Is ‘curl’ installed?") ++ ); ++ ++ if status = "401" then ( ++ dump_response stderr; ++ if uri.uri_user <> None then ++ error (f_"vcenter: incorrect username or password") ++ else ++ error (f_"vcenter: incorrect username or password. You might need to specify the username in the URI like this: %s://USERNAME@[etc]") ++ scheme ++ ); ++ ++ if status = "404" then ( ++ dump_response stderr; ++ error (f_"vcenter: URL not found: %s") https_url ++ ); ++ ++ if status <> "200" then ( ++ dump_response stderr; ++ error (f_"vcenter: invalid response from server") ++ ); ++ ++ (* Get the cookie. *) ++ let rec loop = function ++ | [] -> ++ dump_response stderr; ++ warning (f_"vcenter: could not read session cookie from the vCenter Server, conversion may consume all sessions on the server and fail part way through"); ++ None ++ | line :: lines -> ++ let len = String.length line in ++ if len >= 12 && String.sub line 0 12 = "Set-Cookie: " then ( ++ let line = String.sub line 12 (len-12) in ++ let cookie, _ = String.split ";" line in ++ Some cookie ++ ) ++ else ++ loop lines ++ in ++ loop lines +diff --git a/v2v/vCenter.mli b/v2v/vCenter.mli +index 55d70b486..03749966f 100644 +--- a/v2v/vCenter.mli ++++ b/v2v/vCenter.mli +@@ -18,35 +18,51 @@ + + (** Functions for dealing with VMware vCenter. *) + +-val get_session_cookie : string option -> string -> Xml.uri -> bool -> string -> string option +-(** [get_session_cookie password scheme uri sslverify url] +- contacts the vCenter server, logs in, and gets the session cookie, +- which can later be passed back to the server instead of having to +- log in each time (this is also more efficient since it avoids +- vCenter running out of authentication sessions). ++type remote_resource = { ++ https_url : string; ++ (** The full URL of the remote disk as an https link on the vCenter ++ server. It will have the general form ++ [https://vcenter/folder/.../guest-flat.vmdk?dcPath=...&...] *) + +- Returns [None] if the session cookie could not be read (but +- authentication was successful). You can proceed without the +- session cookie in this case, but there is an unavoidable +- danger of running out of authentication sessions. If the +- session cookie could not be read, this function prints a +- warning. ++ qemu_uri : string; ++ (** The remote disk as a QEMU URI. This opaque blob (usually a ++ [json:] URL) can be passed to [qemu] or [qemu-img] as a backing ++ file. *) + +- The session cookie is memoized so you can call this function as +- often as you want, and only a single log in is made. *) ++ session_cookie : string option; ++ (** When creating the URLs above, the module contacts the vCenter ++ server, logs in, and gets the session cookie, which can later ++ be passed back to the server instead of having to log in each ++ time (this is also more efficient since it avoids vCenter ++ running out of authentication sessions). + +-val map_source_to_uri : int option -> string -> string option -> Xml.uri -> string -> string -> string -> string +-(** [map_source_to_uri readahead dcPath password uri scheme server path] +- maps the [] string to a qemu URI. ++ This can be [None] if the session cookie could not be read (but ++ authentication was successful). You can proceed without the ++ session cookie in this case, but there is an unavoidable ++ danger of running out of authentication sessions. If the ++ session cookie could not be read, this function prints a ++ warning. + +- The [path] will be something like: ++ If authentication {i failed} then the {!map_source} function ++ would exit with an error, so [None] does not indicate auth ++ failure. *) + ++ sslverify : bool; ++ (** This is true except when the libvirt URI had [?no_verify=1] in ++ the parameters. *) ++} ++(** The "remote resource" is the structure returned by the {!map_source} ++ function. *) ++ ++val map_source : ?readahead:int -> ?password:string -> string -> Xml.uri -> string -> string -> string -> remote_resource ++(** [map_source ?readahead ?password dcPath uri scheme server path] ++ maps the [] string to a {!remote_resource} ++ structure containing both an [https://] URL and a qemu URI, ++ both pointing the guest disk. ++ ++ The input [path] comes from libvirt and will be something like: + ["[datastore1] Fedora 20/Fedora 20.vmdk"] ++ (including those literal spaces in the string). + +- including those literal spaces in the string. *) +- +-val map_source_to_https : string -> Xml.uri -> string -> string -> string * bool +-(** [map_source_to_https dcPath uri server path] is the same as +- {!map_source_to_uri} but it produces a regular [https://...] URL. +- The returned boolean is whether TLS certificate verification +- should be done. *) ++ This checks that the disk exists and that authentication is ++ correct, otherwise it will fail. *) +-- +2.14.3 + diff --git a/SOURCES/0050-v2v-vCenter-Split-up-get_session_cookie-function.patch b/SOURCES/0050-v2v-vCenter-Split-up-get_session_cookie-function.patch new file mode 100644 index 0000000..9267e21 --- /dev/null +++ b/SOURCES/0050-v2v-vCenter-Split-up-get_session_cookie-function.patch @@ -0,0 +1,140 @@ +From 4965f1eae5bb56c47c7acf295822afb1108f624e Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 13 Oct 2017 17:01:04 +0100 +Subject: [PATCH] v2v: vCenter: Split up get_session_cookie function. + +This is a small refactoring where we split get_session_cookie into a +function to fetch the URL and a function to parse the cookie. + +(cherry picked from commit 2052fb7d1f9a173d71ab88358281def0c6b03f06) +--- + v2v/vCenter.ml | 106 ++++++++++++++++++++++++++++++++------------------------- + 1 file changed, 59 insertions(+), 47 deletions(-) + +diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml +index 341a40b25..7fc0811a4 100644 +--- a/v2v/vCenter.ml ++++ b/v2v/vCenter.ml +@@ -124,6 +124,45 @@ let rec map_source ?readahead ?password dcPath uri scheme server path = + sslverify = sslverify } + + and get_session_cookie password scheme uri sslverify https_url = ++ let status, headers, dump_response = ++ fetch_headers_from_url password scheme uri sslverify https_url in ++ ++ if status = "401" then ( ++ dump_response stderr; ++ if uri.uri_user <> None then ++ error (f_"vcenter: incorrect username or password") ++ else ++ error (f_"vcenter: incorrect username or password. You might need to specify the username in the URI like this: %s://USERNAME@[etc]") ++ scheme ++ ); ++ ++ if status = "404" then ( ++ dump_response stderr; ++ error (f_"vcenter: URL not found: %s") https_url ++ ); ++ ++ if status <> "200" then ( ++ dump_response stderr; ++ error (f_"vcenter: invalid response from server") ++ ); ++ ++ (* Get the cookie. *) ++ let rec loop = function ++ | [] -> ++ dump_response stderr; ++ warning (f_"vcenter: could not read session cookie from the vCenter Server, conversion may consume all sessions on the server and fail part way through"); ++ None ++ | ("set-cookie", cookie) :: _ -> ++ let cookie, _ = String.split ";" cookie in ++ Some cookie ++ ++ | _ :: headers -> ++ loop headers ++ in ++ loop headers ++ ++(* Fetch the status and reply headers from a URL. *) ++and fetch_headers_from_url password scheme uri sslverify https_url = + let curl_args = ref [ + "head", None; + "silent", None; +@@ -153,53 +192,26 @@ and get_session_cookie password scheme uri sslverify https_url = + + if verbose () then dump_response stderr; + ++ let statuses, headers = ++ List.partition ( ++ fun line -> ++ let len = String.length line in ++ len >= 12 && String.sub line 0 5 = "HTTP/" ++ ) lines in ++ + (* Look for the last HTTP/x.y NNN status code in the output. *) +- let status = ref "" in +- List.iter ( +- fun line -> +- let len = String.length line in +- if len >= 12 && String.sub line 0 5 = "HTTP/" then +- status := String.sub line 9 3 +- ) lines; +- let status = !status in +- if status = "" then ( +- dump_response stderr; +- error (f_"vcenter: no status code in output of ‘curl’ command. Is ‘curl’ installed?") +- ); +- +- if status = "401" then ( +- dump_response stderr; +- if uri.uri_user <> None then +- error (f_"vcenter: incorrect username or password") +- else +- error (f_"vcenter: incorrect username or password. You might need to specify the username in the URI like this: %s://USERNAME@[etc]") +- scheme +- ); +- +- if status = "404" then ( +- dump_response stderr; +- error (f_"vcenter: URL not found: %s") https_url +- ); +- +- if status <> "200" then ( +- dump_response stderr; +- error (f_"vcenter: invalid response from server") +- ); +- +- (* Get the cookie. *) +- let rec loop = function ++ let status = ++ match statuses with + | [] -> + dump_response stderr; +- warning (f_"vcenter: could not read session cookie from the vCenter Server, conversion may consume all sessions on the server and fail part way through"); +- None +- | line :: lines -> +- let len = String.length line in +- if len >= 12 && String.sub line 0 12 = "Set-Cookie: " then ( +- let line = String.sub line 12 (len-12) in +- let cookie, _ = String.split ";" line in +- Some cookie +- ) +- else +- loop lines +- in +- loop lines ++ error (f_"vcenter: no status code in output of ‘curl’ command. Is ‘curl’ installed?") ++ | ss -> String.sub (List.hd (List.rev ss)) 9 3 in ++ ++ let headers = ++ List.map ( ++ fun header -> ++ let h, c = String.split ": " header in ++ String.lowercase_ascii h, c ++ ) headers in ++ ++ status, headers, dump_response +-- +2.14.3 + diff --git a/SOURCES/0051-v2v-vCenter-Factor-out-get_https_url-code.patch b/SOURCES/0051-v2v-vCenter-Factor-out-get_https_url-code.patch new file mode 100644 index 0000000..2ee10a3 --- /dev/null +++ b/SOURCES/0051-v2v-vCenter-Factor-out-get_https_url-code.patch @@ -0,0 +1,79 @@ +From 56835fbc66a9ae540764d1628922afaaa5b2fffc Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 13 Oct 2017 17:08:23 +0100 +Subject: [PATCH] v2v: vCenter: Factor out get_https_url code. + +Pure refactoring. + +(cherry picked from commit 388a70139910ed4b03d9765e403c35bb26cbe422) +--- + v2v/vCenter.ml | 46 ++++++++++++++++++++++++---------------------- + 1 file changed, 24 insertions(+), 22 deletions(-) + +diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml +index 7fc0811a4..f53affb48 100644 +--- a/v2v/vCenter.ml ++++ b/v2v/vCenter.ml +@@ -58,28 +58,7 @@ let rec map_source ?readahead ?password dcPath uri scheme server path = + (* XXX only works if the query string is not URI-quoted *) + String.find query "no_verify=1" = -1 in + +- let https_url = +- if not (Str.string_match source_re path 0) then +- path +- else ( +- let datastore = Str.matched_group 1 path +- and path = Str.matched_group 2 path in +- +- let port = +- match uri.uri_port with +- | 443 -> "" +- | n when n >= 1 -> ":" ^ string_of_int n +- | _ -> "" in +- +- (* XXX Old virt-v2v could also handle snapshots, ie: +- * "[datastore1] Fedora 20/Fedora 20-NNNNNN.vmdk" +- * XXX Need to handle templates. The file is called "-delta.vmdk" in +- * place of "-flat.vmdk". +- *) +- sprintf "https://%s%s/folder/%s-flat.vmdk?dcPath=%s&dsName=%s" +- server port +- (uri_quote path) (uri_quote dcPath) (uri_quote datastore) +- ) in ++ let https_url = get_https_url dcPath uri server path in + + let session_cookie = + get_session_cookie password scheme uri sslverify https_url in +@@ -123,6 +102,29 @@ let rec map_source ?readahead ?password dcPath uri scheme server path = + session_cookie = session_cookie; + sslverify = sslverify } + ++and get_https_url dcPath uri server path = ++ if not (Str.string_match source_re path 0) then ++ path ++ else ( ++ let datastore = Str.matched_group 1 path ++ and path = Str.matched_group 2 path in ++ ++ let port = ++ match uri.uri_port with ++ | 443 -> "" ++ | n when n >= 1 -> ":" ^ string_of_int n ++ | _ -> "" in ++ ++ (* XXX Old virt-v2v could also handle snapshots, ie: ++ * "[datastore1] Fedora 20/Fedora 20-NNNNNN.vmdk" ++ * XXX Need to handle templates. The file is called "-delta.vmdk" in ++ * place of "-flat.vmdk". ++ *) ++ sprintf "https://%s%s/folder/%s-flat.vmdk?dcPath=%s&dsName=%s" ++ server port ++ (uri_quote path) (uri_quote dcPath) (uri_quote datastore) ++ ) ++ + and get_session_cookie password scheme uri sslverify https_url = + let status, headers, dump_response = + fetch_headers_from_url password scheme uri sslverify https_url in +-- +2.14.3 + diff --git a/SOURCES/0052-v2v-vCenter-Handle-disks-with-snapshots-RHBZ-1172425.patch b/SOURCES/0052-v2v-vCenter-Handle-disks-with-snapshots-RHBZ-1172425.patch new file mode 100644 index 0000000..f4b8b62 --- /dev/null +++ b/SOURCES/0052-v2v-vCenter-Handle-disks-with-snapshots-RHBZ-1172425.patch @@ -0,0 +1,71 @@ +From bdeb7926bea75bb62a5165eb94ee4084d678f7fe Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 13 Oct 2017 17:14:07 +0100 +Subject: [PATCH] v2v: vCenter: Handle disks with snapshots (RHBZ#1172425). + +This implements a missing feature from old virt-v2v, namely being able +to cope with a guest with snapshots. Note this only converts the top +(latest) snapshot. As in old virt-v2v it does NOT convert the whole +chain of snapshots. + +(cherry picked from commit c380920034612290eef4476ab4e731c492c68869) +--- + v2v/vCenter.ml | 28 ++++++++++++++++++++++++---- + 1 file changed, 24 insertions(+), 4 deletions(-) + +diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml +index f53affb48..a1aaf7b7e 100644 +--- a/v2v/vCenter.ml ++++ b/v2v/vCenter.ml +@@ -46,6 +46,7 @@ type remote_resource = { + } + + let source_re = Str.regexp "^\\[\\(.*\\)\\] \\(.*\\)\\.vmdk$" ++let snapshot_re = Str.regexp "^\\(.*\\)-[0-9][0-9][0-9][0-9][0-9][0-9]\\(\\.vmdk\\)$" + + let rec map_source ?readahead ?password dcPath uri scheme server path = + (* If no_verify=1 was passed in the libvirt URI, then we have to +@@ -58,7 +59,28 @@ let rec map_source ?readahead ?password dcPath uri scheme server path = + (* XXX only works if the query string is not URI-quoted *) + String.find query "no_verify=1" = -1 in + +- let https_url = get_https_url dcPath uri server path in ++ let https_url = ++ let https_url = get_https_url dcPath uri server path in ++ (* Check the URL exists. *) ++ let status, _, _ = ++ fetch_headers_from_url password scheme uri sslverify https_url in ++ (* If a disk is actually a snapshot image it will have '-00000n' ++ * appended to its name, e.g.: ++ * [yellow:storage1] RHEL4-X/RHEL4-X-000003.vmdk ++ * The flat storage is still called RHEL4-X-flat, however. If we got ++ * a 404 and the vmdk name looks like it might be a snapshot, try ++ * again without the snapshot suffix. ++ *) ++ if status = "404" && Str.string_match snapshot_re path 0 then ( ++ let path = Str.matched_group 1 path ^ Str.matched_group 2 path in ++ get_https_url dcPath uri server path ++ ) ++ else ++ (* Note that other non-200 status errors will be handled ++ * in get_session_cookie below, so we don't have to worry ++ * about them here. ++ *) ++ https_url in + + let session_cookie = + get_session_cookie password scheme uri sslverify https_url in +@@ -115,9 +137,7 @@ and get_https_url dcPath uri server path = + | n when n >= 1 -> ":" ^ string_of_int n + | _ -> "" in + +- (* XXX Old virt-v2v could also handle snapshots, ie: +- * "[datastore1] Fedora 20/Fedora 20-NNNNNN.vmdk" +- * XXX Need to handle templates. The file is called "-delta.vmdk" in ++ (* XXX Need to handle templates. The file is called "-delta.vmdk" in + * place of "-flat.vmdk". + *) + sprintf "https://%s%s/folder/%s-flat.vmdk?dcPath=%s&dsName=%s" +-- +2.14.3 + diff --git a/SOURCES/0053-generator-Deprecate-direct-mode-guestfs_set_direct-g.patch b/SOURCES/0053-generator-Deprecate-direct-mode-guestfs_set_direct-g.patch new file mode 100644 index 0000000..09a4f80 --- /dev/null +++ b/SOURCES/0053-generator-Deprecate-direct-mode-guestfs_set_direct-g.patch @@ -0,0 +1,126 @@ +From 9dcd0326952b2d0ad6f95f51bd9e0f5487603e30 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 2 Mar 2017 12:42:46 +0000 +Subject: [PATCH] generator: Deprecate direct mode (guestfs_set_direct, + guestfs_get_direct). + +(cherry picked from commit 26948d5cb17391a32856b18b8a5d6ae58a179507) +--- + generator/actions_properties.ml | 28 ---------------------------- + generator/actions_properties_deprecated.ml | 30 ++++++++++++++++++++++++++++++ + rescue/rescue.c | 3 +++ + test-tool/test-tool.c | 1 - + 4 files changed, 33 insertions(+), 29 deletions(-) + +diff --git a/generator/actions_properties.ml b/generator/actions_properties.ml +index 8f6455b81..87144b14f 100644 +--- a/generator/actions_properties.ml ++++ b/generator/actions_properties.ml +@@ -259,34 +259,6 @@ C)." }; + longdesc = "\ + Return the command trace flag." }; + +- { defaults with +- name = "set_direct"; added = (1, 0, 72); +- style = RErr, [Bool "direct"], []; +- fish_alias = ["direct"]; config_only = true; +- blocking = false; +- shortdesc = "enable or disable direct appliance mode"; +- longdesc = "\ +-If the direct appliance mode flag is enabled, then stdin and +-stdout are passed directly through to the appliance once it +-is launched. +- +-One consequence of this is that log messages aren't caught +-by the library and handled by C, +-but go straight to stdout. +- +-You probably don't want to use this unless you know what you +-are doing. +- +-The default is disabled." }; +- +- { defaults with +- name = "get_direct"; added = (1, 0, 72); +- style = RBool "direct", [], []; +- blocking = false; +- shortdesc = "get direct appliance mode flag"; +- longdesc = "\ +-Return the direct appliance mode flag." }; +- + { defaults with + name = "set_recovery_proc"; added = (1, 0, 77); + style = RErr, [Bool "recoveryproc"], []; +diff --git a/generator/actions_properties_deprecated.ml b/generator/actions_properties_deprecated.ml +index def17b926..53277822e 100644 +--- a/generator/actions_properties_deprecated.ml ++++ b/generator/actions_properties_deprecated.ml +@@ -125,6 +125,36 @@ Return the current backend. + + See C and L." }; + ++ { defaults with ++ name = "set_direct"; added = (1, 0, 72); ++ style = RErr, [Bool "direct"], []; ++ deprecated_by = Deprecated_no_replacement; ++ fish_alias = ["direct"]; config_only = true; ++ blocking = false; ++ shortdesc = "enable or disable direct appliance mode"; ++ longdesc = "\ ++If the direct appliance mode flag is enabled, then stdin and ++stdout are passed directly through to the appliance once it ++is launched. ++ ++One consequence of this is that log messages aren't caught ++by the library and handled by C, ++but go straight to stdout. ++ ++You probably don't want to use this unless you know what you ++are doing. ++ ++The default is disabled." }; ++ ++ { defaults with ++ name = "get_direct"; added = (1, 0, 72); ++ style = RBool "direct", [], []; ++ deprecated_by = Deprecated_no_replacement; ++ blocking = false; ++ shortdesc = "get direct appliance mode flag"; ++ longdesc = "\ ++Return the direct appliance mode flag." }; ++ + ] + + let daemon_functions = [ +diff --git a/rescue/rescue.c b/rescue/rescue.c +index 45967b2ad..b692e5a07 100644 +--- a/rescue/rescue.c ++++ b/rescue/rescue.c +@@ -295,9 +295,12 @@ main (int argc, char *argv[]) + usage (EXIT_FAILURE); + } + ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + /* Setting "direct mode" is required for the rescue appliance. */ + if (guestfs_set_direct (g, 1) == -1) + exit (EXIT_FAILURE); ++#pragma GCC diagnostic pop + + { + /* The libvirt backend doesn't support direct mode. As a temporary +diff --git a/test-tool/test-tool.c b/test-tool/test-tool.c +index 20e2a32fa..2ae266d7d 100644 +--- a/test-tool/test-tool.c ++++ b/test-tool/test-tool.c +@@ -224,7 +224,6 @@ main (int argc, char *argv[]) + p = guestfs_get_cachedir (g); + printf ("guestfs_get_cachedir: %s\n", p ? : "(null)"); + free (p); +- printf ("guestfs_get_direct: %d\n", guestfs_get_direct (g)); + p = guestfs_get_hv (g); + printf ("guestfs_get_hv: %s\n", p); + free (p); +-- +2.14.3 + diff --git a/SOURCES/0054-New-API-internal-get-console-socket-to-support-virt-.patch b/SOURCES/0054-New-API-internal-get-console-socket-to-support-virt-.patch new file mode 100644 index 0000000..30eced5 --- /dev/null +++ b/SOURCES/0054-New-API-internal-get-console-socket-to-support-virt-.patch @@ -0,0 +1,184 @@ +From 78588ae92828fad9b8ea09e2edf3899466975470 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 2 Mar 2017 11:06:27 +0000 +Subject: [PATCH] New API: internal-get-console-socket to support virt-rescue. + +This API intended for use by virt-rescue only gets the file descriptor +of the console socket. + +(cherry picked from commit 84c9f98c2e09a459ced3c7e85191f2e47d149a52) +--- + generator/actions_core.ml | 11 +++++++ + generator/actions_properties_deprecated.ml | 4 +-- + lib/Makefile.am | 1 + + lib/conn-socket.c | 16 +++++++++- + lib/guestfs-internal.h | 3 ++ + lib/rescue.c | 47 ++++++++++++++++++++++++++++++ + 6 files changed, 79 insertions(+), 3 deletions(-) + create mode 100644 lib/rescue.c + +diff --git a/generator/actions_core.ml b/generator/actions_core.ml +index ee2539c09..dbacdfadf 100644 +--- a/generator/actions_core.ml ++++ b/generator/actions_core.ml +@@ -1678,6 +1678,17 @@ call it returns a simple true/false boolean result, instead + of throwing an exception if a feature is not found. For + other documentation see C." }; + ++ { defaults with ++ name = "internal_get_console_socket"; added = (1, 37, 1); ++ style = RInt "fd", [], []; ++ visibility = VInternal; ++ test_excuse = "writing to the socket may block"; ++ shortdesc = "get the appliance console socket"; ++ longdesc = "\ ++This call is used by L to write directly to ++appliance console (for passing through keystrokes). It should ++not normally be used by other libguestfs users." }; ++ + ] + + let daemon_functions = [ +diff --git a/generator/actions_properties_deprecated.ml b/generator/actions_properties_deprecated.ml +index 53277822e..f36509e75 100644 +--- a/generator/actions_properties_deprecated.ml ++++ b/generator/actions_properties_deprecated.ml +@@ -128,7 +128,7 @@ See C and L." }; + { defaults with + name = "set_direct"; added = (1, 0, 72); + style = RErr, [Bool "direct"], []; +- deprecated_by = Deprecated_no_replacement; ++ deprecated_by = Replaced_by "internal_get_console_socket"; + fish_alias = ["direct"]; config_only = true; + blocking = false; + shortdesc = "enable or disable direct appliance mode"; +@@ -149,7 +149,7 @@ The default is disabled." }; + { defaults with + name = "get_direct"; added = (1, 0, 72); + style = RBool "direct", [], []; +- deprecated_by = Deprecated_no_replacement; ++ deprecated_by = Replaced_by "internal_get_console_socket"; + blocking = false; + shortdesc = "get direct appliance mode flag"; + longdesc = "\ +diff --git a/lib/Makefile.am b/lib/Makefile.am +index 22974187f..c3e013a52 100644 +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -117,6 +117,7 @@ libguestfs_la_SOURCES = \ + private-data.c \ + proto.c \ + qemu.c \ ++ rescue.c \ + stringsbuf.c \ + structs-compare.c \ + structs-copy.c \ +diff --git a/lib/conn-socket.c b/lib/conn-socket.c +index 2cd261a2b..8ecfed856 100644 +--- a/lib/conn-socket.c ++++ b/lib/conn-socket.c +@@ -1,5 +1,5 @@ + /* libguestfs +- * Copyright (C) 2013 Red Hat Inc. ++ * Copyright (C) 2013-2017 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public +@@ -397,6 +397,19 @@ handle_log_message (guestfs_h *g, + return 1; + } + ++static int ++get_console_sock (guestfs_h *g, struct connection *connv) ++{ ++ struct connection_socket *conn = (struct connection_socket *) connv; ++ ++ if (conn->console_sock == -1) { ++ error (g, _("console socket not connected")); ++ return -1; ++ } ++ ++ return conn->console_sock; ++} ++ + static void + free_conn_socket (guestfs_h *g, struct connection *connv) + { +@@ -418,6 +431,7 @@ static struct connection_ops ops = { + .read_data = read_data, + .write_data = write_data, + .can_read_data = can_read_data, ++ .get_console_sock = get_console_sock, + }; + + /** +diff --git a/lib/guestfs-internal.h b/lib/guestfs-internal.h +index d962aacd4..3bae02b8a 100644 +--- a/lib/guestfs-internal.h ++++ b/lib/guestfs-internal.h +@@ -369,6 +369,9 @@ struct connection_ops { + * Returns: 1 = yes, 0 = no, -1 = error + */ + int (*can_read_data) (guestfs_h *g, struct connection *); ++ ++ /* Get the console socket (to support virt-rescue). */ ++ int (*get_console_sock) (guestfs_h *g, struct connection *); + }; + + /** +diff --git a/lib/rescue.c b/lib/rescue.c +new file mode 100644 +index 000000000..ae7811a31 +--- /dev/null ++++ b/lib/rescue.c +@@ -0,0 +1,47 @@ ++/* libguestfs ++ * Copyright (C) 2017 Red Hat Inc. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/** ++ * Support for virt-rescue(1). ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "guestfs.h" ++#include "guestfs-internal.h" ++#include "guestfs-internal-actions.h" ++ ++int ++guestfs_impl_internal_get_console_socket (guestfs_h *g) ++{ ++ if (!g->conn) { ++ error (g, _("no console socket, the handle must be launched")); ++ return -1; ++ } ++ ++ if (!g->conn->ops->get_console_sock) ++ NOT_SUPPORTED (g, -1, ++ _("connection class does not support getting the console socket")); ++ ++ return g->conn->ops->get_console_sock (g, g->conn); ++} +-- +2.14.3 + diff --git a/SOURCES/0055-lib-Return-EPIPE-for-appliance-closed-the-connection.patch b/SOURCES/0055-lib-Return-EPIPE-for-appliance-closed-the-connection.patch new file mode 100644 index 0000000..62ca9b1 --- /dev/null +++ b/SOURCES/0055-lib-Return-EPIPE-for-appliance-closed-the-connection.patch @@ -0,0 +1,39 @@ +From ef4efa57d1c0fffe4d81ea70ad8f44d07667cfeb Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 3 Mar 2017 10:14:20 +0000 +Subject: [PATCH] lib: Return EPIPE for "appliance closed the connection + unexpectedly". + +(cherry picked from commit 8af9acd4e31e9880e14735b2242c496ee017c0d9) +--- + lib/errors.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/lib/errors.c b/lib/errors.c +index c2af611ee..ace6a89cf 100644 +--- a/lib/errors.c ++++ b/lib/errors.c +@@ -358,12 +358,15 @@ void + guestfs_int_unexpected_close_error (guestfs_h *g) + { + if (g->verbose) +- error (g, _("appliance closed the connection unexpectedly, see earlier error messages")); ++ guestfs_int_error_errno (g, EPIPE, ++ _("appliance closed the connection unexpectedly, " ++ "see earlier error messages")); + else +- error (g, _( +- "appliance closed the connection unexpectedly.\n" +- "This usually means the libguestfs appliance crashed.\n" +- DEBUG_ADVICE)); ++ guestfs_int_error_errno (g, EPIPE, ++ _("appliance closed the connection unexpectedly.\n" ++ "This usually means the libguestfs appliance " ++ "crashed.\n" ++ DEBUG_ADVICE)); + } + + /** +-- +2.14.3 + diff --git a/SOURCES/0056-rescue-Modify-virt-rescue-so-it-doesn-t-use-direct-m.patch b/SOURCES/0056-rescue-Modify-virt-rescue-so-it-doesn-t-use-direct-m.patch new file mode 100644 index 0000000..314e154 --- /dev/null +++ b/SOURCES/0056-rescue-Modify-virt-rescue-so-it-doesn-t-use-direct-m.patch @@ -0,0 +1,535 @@ +From 2d013d5d67d5896869dff4b08c0674b2d91e721f Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 2 Mar 2017 13:46:48 +0000 +Subject: [PATCH] rescue: Modify virt-rescue so it doesn't use direct mode + (RHBZ#1152819, RHBZ#1171654). + +Instead of using "direct mode" (which was basically a quick hack), +virt-rescue now launches the appliance with a running daemon. + +The daemon doesn't do much -- there is still a bash shell which the +user interacts with. The daemon is there simply to provide the +initial GUESTFS_LAUNCH_FLAG message and to handle shutdown a bit more +gracefully. + +To interact with the shell, and replacing direct mode, virt-rescue now +prints out log messages (the output of the shell), and sends input +typed by the user directly to the console socket. This uses the +guestfs_internal_get_console_socket API added previously. Most of the +complexity behind this is hidden in virt-rescue. + +This fully fixes the handling of ^C (RHBZ#1152819). Also there were +earlier reports that full screen commands like 'vim' didn't work well, +(RHBZ#1171654), but in this version vim appears to work fine, albeit +only using 80x24 of the screen because of the serial console. + +(cherry picked from commit 32d60801443647b3523b9374c431fefdbf054e3c) +--- + appliance/init | 93 ++++++++-------- + rescue/Makefile.am | 1 + + rescue/rescue.c | 306 +++++++++++++++++++++++++++++++++++++++++++++-------- + 3 files changed, 313 insertions(+), 87 deletions(-) + +diff --git a/appliance/init b/appliance/init +index 735ba8946..ea763c2d3 100755 +--- a/appliance/init ++++ b/appliance/init +@@ -160,60 +160,63 @@ if test "$guestfs_verbose" = 1 && test "$guestfs_boot_analysis" != 1; then + echo -n "uptime: "; cat /proc/uptime + fi + +-if ! test "$guestfs_rescue" = 1; then +- # Run the daemon. +- cmd="guestfsd" +- eval `grep -Eo 'guestfs_channel=[^[:space:]]+' /proc/cmdline` +- if test "x$guestfs_channel" != "x"; then ++# Run the daemon. ++cmd="guestfsd" ++eval `grep -Eo 'guestfs_channel=[^[:space:]]+' /proc/cmdline` ++if test "x$guestfs_channel" != "x"; then + cmd="$cmd --channel $guestfs_channel" +- fi +- if test "$guestfs_verbose" = 1; then ++fi ++if test "$guestfs_verbose" = 1; then + cmd="$cmd --verbose" +- fi +- if test "$guestfs_network" = 1; then ++fi ++if test "$guestfs_network" = 1; then + cmd="$cmd --network" +- fi +- echo $cmd +- $cmd ++fi ++if ! test "$guestfs_rescue" = 1; then ++ echo $cmd ++ $cmd + else +- # Run virt-rescue shell. ++ # Run virt-rescue shell. + +- # Get name of the serial port, from console= passed by libguestfs. +- # XXX Consider using /proc/consoles +- guestfs_serial=$(grep -Eo 'console=[^[:space:]]+' /proc/cmdline | +- sed s/console=//) ++ # We need a daemon, even in virt-rescue. ++ $cmd & + +- # Remove LD_PRELOAD=libSegFault set above. +- unset LD_PRELOAD ++ # Get name of the serial port, from console= passed by libguestfs. ++ # XXX Consider using /proc/consoles ++ guestfs_serial=$(grep -Eo 'console=[^[:space:]]+' /proc/cmdline | ++ sed s/console=//) + +- :> $HOME/.bashrc +- grep -Eo 'TERM=[^[:space:]]+' /proc/cmdline >> $HOME/.bashrc +- echo "PS1='> '" >> $HOME/.bashrc +- echo "export TERM PS1" >> $HOME/.bashrc ++ # Remove LD_PRELOAD=libSegFault set above. ++ unset LD_PRELOAD + +- # The shell is opened by default on /dev/console, which (on Linux) +- # is not a controlling terminal, causing job control to fail. For +- # how we work around this, see: +- # https://busybox.net/FAQ.html#job_control +- run_bash_with_ctty () +- { +- setsid bash -c \ +- "exec bash /dev/$guestfs_serial 2>&1" +- } ++ :> $HOME/.bashrc ++ grep -Eo 'TERM=[^[:space:]]+' /proc/cmdline >> $HOME/.bashrc ++ echo "PS1='> '" >> $HOME/.bashrc ++ echo "export TERM PS1" >> $HOME/.bashrc + +- echo +- echo "------------------------------------------------------------" +- echo +- echo "Welcome to virt-rescue, the libguestfs rescue shell." +- echo +- echo "Note: The contents of / are the rescue appliance." +- echo "You have to mount the guest's partitions under /sysroot" +- echo "before you can examine them." +- echo +- run_bash_with_ctty +- echo +- echo "virt-rescue: Syncing the disk now before exiting ..." +- echo ++ # The shell is opened by default on /dev/console, which (on Linux) ++ # is not a controlling terminal, causing job control to fail. For ++ # how we work around this, see: ++ # https://busybox.net/FAQ.html#job_control ++ run_bash_with_ctty () ++ { ++ setsid bash -c \ ++ "exec bash /dev/$guestfs_serial 2>&1" ++ } ++ ++ echo ++ echo "------------------------------------------------------------" ++ echo ++ echo "Welcome to virt-rescue, the libguestfs rescue shell." ++ echo ++ echo "Note: The contents of / (root) are the rescue appliance." ++ echo "You have to mount the guest's partitions under /sysroot" ++ echo "before you can examine them." ++ echo ++ run_bash_with_ctty ++ echo ++ echo "virt-rescue: Syncing the disk now before exiting ..." ++ echo + fi + + sync +diff --git a/rescue/Makefile.am b/rescue/Makefile.am +index 7919aafd5..99d4b79ae 100644 +--- a/rescue/Makefile.am ++++ b/rescue/Makefile.am +@@ -30,6 +30,7 @@ virt_rescue_SOURCES = \ + + virt_rescue_CPPFLAGS = \ + -DGUESTFS_WARN_DEPRECATED=1 \ ++ -DGUESTFS_PRIVATE=1 \ + -DLOCALEBASEDIR=\""$(datadir)/locale"\" \ + -I$(top_srcdir)/common/utils -I$(top_builddir)/common/utils \ + -I$(top_srcdir)/lib -I$(top_builddir)/lib \ +diff --git a/rescue/rescue.c b/rescue/rescue.c +index b692e5a07..b145dcd40 100644 +--- a/rescue/rescue.c ++++ b/rescue/rescue.c +@@ -23,21 +23,32 @@ + #include + #include + #include ++#include + #include + #include + #include ++#include ++#include ++#include + #include + #include + #include + ++#include "full-write.h" ++#include "getprogname.h" + #include "ignore-value.h" + #include "xvasprintf.h" +-#include "getprogname.h" + + #include "guestfs.h" + #include "options.h" + #include "display-options.h" + ++static void log_message_callback (guestfs_h *g, void *opaque, uint64_t event, int event_handle, int flags, const char *buf, size_t buf_len, const uint64_t *array, size_t array_len); ++static void do_rescue (int sock); ++static void raw_tty (void); ++static void restore_tty (void); ++static void tstp_handler (int sig); ++static void cont_handler (int sig); + static void add_scratch_disks (int n, struct drv **drvs); + static void do_suggestion (struct drv *drvs); + +@@ -54,6 +65,9 @@ int inspector = 0; + int in_guestfish = 0; + int in_virt_rescue = 1; + ++/* Old terminal settings. */ ++static struct termios old_termios; ++ + static void __attribute__((noreturn)) + usage (int status) + { +@@ -135,6 +149,8 @@ main (int argc, char *argv[]) + int memsize = 0; + int smp = 0; + int suggest = 0; ++ char *append_full; ++ int sock; + + g = guestfs_create (); + if (g == NULL) +@@ -295,30 +311,6 @@ main (int argc, char *argv[]) + usage (EXIT_FAILURE); + } + +-#pragma GCC diagnostic push +-#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +- /* Setting "direct mode" is required for the rescue appliance. */ +- if (guestfs_set_direct (g, 1) == -1) +- exit (EXIT_FAILURE); +-#pragma GCC diagnostic pop +- +- { +- /* The libvirt backend doesn't support direct mode. As a temporary +- * workaround, force the appliance backend, but warn about it. +- */ +- CLEANUP_FREE char *backend = guestfs_get_backend (g); +- if (backend) { +- if (STREQ (backend, "libvirt") || +- STRPREFIX (backend, "libvirt:")) { +- fprintf (stderr, _("%s: warning: virt-rescue doesn't work with the libvirt backend\n" +- "at the moment. As a workaround, forcing backend = 'direct'.\n"), +- getprogname ()); +- if (guestfs_set_backend (g, "direct") == -1) +- exit (EXIT_FAILURE); +- } +- } +- } +- + /* Set other features. */ + if (memsize > 0) + if (guestfs_set_memsize (g, memsize) == -1) +@@ -330,16 +322,15 @@ main (int argc, char *argv[]) + if (guestfs_set_smp (g, smp) == -1) + exit (EXIT_FAILURE); + +- { +- /* Kernel command line must include guestfs_rescue=1 (see +- * appliance/init) as well as other options. +- */ +- CLEANUP_FREE char *append_full = xasprintf ("guestfs_rescue=1%s%s", +- append ? " " : "", +- append ? append : ""); +- if (guestfs_set_append (g, append_full) == -1) +- exit (EXIT_FAILURE); +- } ++ /* Kernel command line must include guestfs_rescue=1 (see ++ * appliance/init) as well as other options. ++ */ ++ append_full = xasprintf ("guestfs_rescue=1%s%s", ++ append ? " " : "", ++ append ? append : ""); ++ if (guestfs_set_append (g, append_full) == -1) ++ exit (EXIT_FAILURE); ++ free (append_full); + + /* Add drives. */ + add_drives (drvs); +@@ -347,22 +338,253 @@ main (int argc, char *argv[]) + /* Free up data structures, no longer needed after this point. */ + free_drives (drvs); + +- /* Run the appliance. This won't return until the user quits the +- * appliance. ++ /* Add an event handler to print "log messages". These will be the ++ * output of the appliance console during launch and shutdown. ++ * After launch, we will read the console messages directly from the ++ * socket and they won't be passed through the event callback. + */ +- if (!verbose) +- guestfs_set_error_handler (g, NULL, NULL); ++ if (guestfs_set_event_callback (g, log_message_callback, ++ GUESTFS_EVENT_APPLIANCE, 0, NULL) == -1) ++ exit (EXIT_FAILURE); + +- /* We expect launch to fail, so ignore the return value, and don't +- * bother with explicit guestfs_shutdown either. ++ /* Run the appliance. */ ++ if (guestfs_launch (g) == -1) ++ exit (EXIT_FAILURE); ++ ++ sock = guestfs_internal_get_console_socket (g); ++ if (sock == -1) ++ exit (EXIT_FAILURE); ++ ++ /* Try to set all sockets to non-blocking. */ ++ if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1) ++ perror ("could not set stdin to non-blocking"); ++ if (fcntl (STDOUT_FILENO, F_SETFL, O_NONBLOCK) == -1) ++ perror ("could not set stdout to non-blocking"); ++ if (fcntl (sock, F_SETFL, O_NONBLOCK) == -1) ++ perror ("could not set console socket to non-blocking"); ++ ++ /* Save the initial state of the tty so we always have the original ++ * state to go back to. ++ */ ++ if (tcgetattr (STDIN_FILENO, &old_termios) == -1) { ++ perror ("tcgetattr: stdin"); ++ exit (EXIT_FAILURE); ++ } ++ ++ /* Put stdin in raw mode so that we can receive ^C and other ++ * special keys. ++ */ ++ raw_tty (); ++ ++ /* Restore the tty settings when the process exits. */ ++ atexit (restore_tty); ++ ++ /* Catch tty stop and cont signals so we can cleanup. ++ * See https://www.gnu.org/software/libc/manual/html_node/Signaling-Yourself.html + */ +- ignore_value (guestfs_launch (g)); ++ signal (SIGTSTP, tstp_handler); ++ signal (SIGCONT, cont_handler); ++ ++ do_rescue (sock); ++ ++ restore_tty (); ++ ++ /* Shut down the appliance. */ ++ guestfs_push_error_handler (g, NULL, NULL); ++ if (guestfs_shutdown (g) == -1) { ++ const char *err; ++ ++ /* Ignore "appliance closed the connection unexpectedly" since ++ * this can happen if the user reboots the appliance. ++ */ ++ if (guestfs_last_errno (g) == EPIPE) ++ goto next; + ++ /* Otherwise it's a real error. */ ++ err = guestfs_last_error (g); ++ fprintf (stderr, "libguestfs: error: %s\n", err); ++ exit (EXIT_FAILURE); ++ } ++ next: ++ guestfs_pop_error_handler (g); + guestfs_close (g); + + exit (EXIT_SUCCESS); + } + ++static void ++log_message_callback (guestfs_h *g, void *opaque, uint64_t event, ++ int event_handle, int flags, ++ const char *buf, size_t buf_len, ++ const uint64_t *array, size_t array_len) ++{ ++ if (buf_len > 0) { ++ ignore_value (full_write (STDOUT_FILENO, buf, buf_len)); ++ } ++} ++ ++/* This is the main loop for virt-rescue. We read and write ++ * directly to the console socket. ++ */ ++#define BUFSIZE 4096 ++static char rbuf[BUFSIZE]; /* appliance -> local tty */ ++static char wbuf[BUFSIZE]; /* local tty -> appliance */ ++ ++static void ++do_rescue (int sock) ++{ ++ size_t rlen = 0; ++ size_t wlen = 0; ++ ++ while (sock >= 0 || rlen > 0) { ++ struct pollfd fds[3]; ++ nfds_t nfds = 2; ++ int r; ++ ssize_t n; ++ ++ fds[0].fd = STDIN_FILENO; ++ fds[0].events = 0; ++ if (BUFSIZE-wlen > 0) ++ fds[0].events = POLLIN; ++ fds[0].revents = 0; ++ ++ fds[1].fd = STDOUT_FILENO; ++ fds[1].events = 0; ++ if (rlen > 0) ++ fds[1].events |= POLLOUT; ++ fds[1].revents = 0; ++ ++ if (sock >= 0) { ++ fds[2].fd = sock; ++ fds[2].events = 0; ++ if (BUFSIZE-rlen > 0) ++ fds[2].events |= POLLIN; ++ if (wlen > 0) ++ fds[2].events |= POLLOUT; ++ fds[2].revents = 0; ++ nfds++; ++ } ++ ++ r = poll (fds, nfds, -1); ++ if (r == -1) { ++ if (errno == EINTR || errno == EAGAIN) ++ continue; ++ perror ("poll"); ++ return; ++ } ++ ++ /* Input from local tty. */ ++ if ((fds[0].revents & POLLIN) != 0) { ++ assert (BUFSIZE-wlen > 0); ++ n = read (STDIN_FILENO, wbuf+wlen, BUFSIZE-wlen); ++ if (n == -1) { ++ if (errno == EINTR || errno == EAGAIN) ++ continue; ++ perror ("read"); ++ return; ++ } ++ if (n == 0) { ++ /* We don't expect this to happen. Maybe the whole tty went away? ++ * Anyway, we should exit as soon as possible. ++ */ ++ return; ++ } ++ if (n > 0) ++ wlen += n; ++ } ++ ++ /* Log message from appliance. */ ++ if (nfds > 2 && (fds[2].revents & POLLIN) != 0) { ++ assert (BUFSIZE-rlen > 0); ++ n = read (sock, rbuf+rlen, BUFSIZE-rlen); ++ if (n == -1) { ++ if (errno == EINTR || errno == EAGAIN) ++ continue; ++ if (errno == ECONNRESET) ++ goto appliance_closed; ++ perror ("read"); ++ return; ++ } ++ if (n == 0) { ++ appliance_closed: ++ sock = -1; ++ /* Don't actually close the socket, because it's owned by ++ * the guestfs handle. ++ */ ++ continue; ++ } ++ if (n > 0) ++ rlen += n; ++ } ++ ++ /* Write log messages to local tty. */ ++ if ((fds[1].revents & POLLOUT) != 0) { ++ assert (rlen > 0); ++ n = write (STDOUT_FILENO, rbuf, rlen); ++ if (n == -1) { ++ perror ("write"); ++ continue; ++ } ++ rlen -= n; ++ memmove (rbuf, rbuf+n, rlen); ++ } ++ ++ /* Write commands to the appliance. */ ++ if (nfds > 2 && (fds[2].revents & POLLOUT) != 0) { ++ assert (wlen > 0); ++ n = write (sock, wbuf, wlen); ++ if (n == -1) { ++ perror ("write"); ++ continue; ++ } ++ wlen -= n; ++ memmove (wbuf, wbuf+n, wlen); ++ } ++ } ++} ++ ++/* Put the tty in raw mode. */ ++static void ++raw_tty (void) ++{ ++ struct termios termios; ++ ++ if (tcgetattr (STDIN_FILENO, &termios) == -1) { ++ perror ("tcgetattr: stdin"); ++ exit (EXIT_FAILURE); ++ } ++ cfmakeraw (&termios); ++ if (tcsetattr (STDIN_FILENO, TCSANOW, &termios) == -1) { ++ perror ("tcsetattr: stdin"); ++ exit (EXIT_FAILURE); ++ } ++} ++ ++/* Restore the tty to (presumably) cooked mode as it was when ++ * the program was started. ++ */ ++static void ++restore_tty (void) ++{ ++ tcsetattr (STDIN_FILENO, TCSANOW, &old_termios); ++} ++ ++/* When we get SIGTSTP, switch back to cooked mode. */ ++static void ++tstp_handler (int sig) ++{ ++ restore_tty (); ++ signal (SIGTSTP, SIG_DFL); ++ raise (SIGTSTP); ++} ++ ++/* When we get SIGCONF, switch to raw mode. */ ++static void ++cont_handler (int sig) ++{ ++ raw_tty (); ++} ++ + static void suggest_filesystems (void); + + static int +-- +2.14.3 + diff --git a/SOURCES/0057-rescue-Implement-m-and-i-options.patch b/SOURCES/0057-rescue-Implement-m-and-i-options.patch new file mode 100644 index 0000000..cc57d7f --- /dev/null +++ b/SOURCES/0057-rescue-Implement-m-and-i-options.patch @@ -0,0 +1,400 @@ +From 5b0f9d72d49053d246463b7bb024f21f1c24d983 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 3 Mar 2017 13:52:31 +0000 +Subject: [PATCH] rescue: Implement -m and -i options. + +`virt-rescue -a disk -i' does the right thing. + +`-m' was previously an alternate form of `--memsize'. By sniffing the +parameter we can make `-m MB' continue to work, while also allowing +`-m' to be used as a short form for the `--mount' option. + +This also removes most of the description of `--suggest' from the man +page, since it is no longer needed. + +(cherry picked from commit 33d2ae796119ae5dd38e2afcbf1ba4216bd99846) +--- + appliance/init | 12 +++++-- + rescue/Makefile.am | 3 +- + rescue/rescue.c | 87 +++++++++++++++++++++++++++++++++++++------------- + rescue/virt-rescue.pod | 80 ++++++++++++++++++++++++++++------------------ + 4 files changed, 126 insertions(+), 56 deletions(-) + +diff --git a/appliance/init b/appliance/init +index ea763c2d3..4133de434 100755 +--- a/appliance/init ++++ b/appliance/init +@@ -181,6 +181,10 @@ else + # We need a daemon, even in virt-rescue. + $cmd & + ++ # XXX This gives a bit of time for virt-rescue to connect to the ++ # daemon and mount any filesystems. ++ sleep 2 ++ + # Get name of the serial port, from console= passed by libguestfs. + # XXX Consider using /proc/consoles + guestfs_serial=$(grep -Eo 'console=[^[:space:]]+' /proc/cmdline | +@@ -210,8 +214,12 @@ else + echo "Welcome to virt-rescue, the libguestfs rescue shell." + echo + echo "Note: The contents of / (root) are the rescue appliance." +- echo "You have to mount the guest's partitions under /sysroot" +- echo "before you can examine them." ++ if ! test -d "/sysroot/dev"; then ++ echo "You have to mount the guest's partitions under /sysroot" ++ echo "before you can examine them." ++ else ++ echo "Use 'cd /sysroot' or 'chroot /sysroot' to see guest filesystems." ++ fi + echo + run_bash_with_ctty + echo +diff --git a/rescue/Makefile.am b/rescue/Makefile.am +index 99d4b79ae..c83c43458 100644 +--- a/rescue/Makefile.am ++++ b/rescue/Makefile.am +@@ -35,7 +35,7 @@ virt_rescue_CPPFLAGS = \ + -I$(top_srcdir)/common/utils -I$(top_builddir)/common/utils \ + -I$(top_srcdir)/lib -I$(top_builddir)/lib \ + -I$(top_srcdir)/common/options -I$(top_builddir)/common/options \ +- -I$(top_srcdir)/fish \ ++ -I$(top_srcdir)/common/windows -I$(top_builddir)/common/windows \ + -I$(srcdir)/../gnulib/lib -I../gnulib/lib + + virt_rescue_CFLAGS = \ +@@ -43,6 +43,7 @@ virt_rescue_CFLAGS = \ + $(LIBXML2_CFLAGS) + + virt_rescue_LDADD = \ ++ $(top_builddir)/common/windows/libwindows.la \ + $(top_builddir)/common/options/liboptions.la \ + $(top_builddir)/common/utils/libutils.la \ + $(top_builddir)/lib/libguestfs.la \ +diff --git a/rescue/rescue.c b/rescue/rescue.c +index b145dcd40..2b461378d 100644 +--- a/rescue/rescue.c ++++ b/rescue/rescue.c +@@ -23,7 +23,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -37,9 +36,11 @@ + #include "full-write.h" + #include "getprogname.h" + #include "ignore-value.h" ++#include "nonblocking.h" + #include "xvasprintf.h" + + #include "guestfs.h" ++#include "windows.h" + #include "options.h" + #include "display-options.h" + +@@ -87,7 +88,9 @@ usage (int status) + " -d|--domain guest Add disks from libvirt guest\n" + " --format[=raw|..] Force disk format for -a option\n" + " --help Display brief help\n" +- " -m|--memsize MB Set memory size in megabytes\n" ++ " -i|--inspector Automatically mount filesystems\n" ++ " -m|--mount dev[:mnt[:opts[:fstype]] Mount dev on mnt (if omitted, /)\n" ++ " --memsize MB Set memory size in megabytes\n" + " --network Enable network\n" + " -r|--ro Access read-only\n" + " --scratch[=N] Add scratch disk(s)\n" +@@ -116,7 +119,7 @@ main (int argc, char *argv[]) + + enum { HELP_OPTION = CHAR_MAX + 1 }; + +- static const char options[] = "a:c:d:m:rvVwx"; ++ static const char options[] = "a:c:d:im:rvVwx"; + static const struct option long_options[] = { + { "add", 1, 0, 'a' }, + { "append", 1, 0, 0 }, +@@ -124,8 +127,10 @@ main (int argc, char *argv[]) + { "domain", 1, 0, 'd' }, + { "format", 2, 0, 0 }, + { "help", 0, 0, HELP_OPTION }, ++ { "inspector", 0, 0, 'i' }, + { "long-options", 0, 0, 0 }, +- { "memsize", 1, 0, 'm' }, ++ { "mount", 1, 0, 'm' }, ++ { "memsize", 1, 0, 0 }, + { "network", 0, 0, 0 }, + { "ro", 0, 0, 'r' }, + { "rw", 0, 0, 'w' }, +@@ -140,13 +145,16 @@ main (int argc, char *argv[]) + }; + struct drv *drvs = NULL; + struct drv *drv; ++ struct mp *mps = NULL; ++ struct mp *mp; ++ char *p; + const char *format = NULL; + bool format_consumed = true; + int c; + int option_index; + int network = 0; + const char *append = NULL; +- int memsize = 0; ++ int memsize = 0, m; + int smp = 0; + int suggest = 0; + char *append_full; +@@ -196,6 +204,10 @@ main (int argc, char *argv[]) + _("--scratch parameter '%s' should be >= 1"), optarg); + add_scratch_disks (n, &drvs); + } ++ } else if (STREQ (long_options[option_index].name, "memsize")) { ++ if (sscanf (optarg, "%d", &memsize) != 1) ++ error (EXIT_FAILURE, 0, ++ _("could not parse memory size '%s'"), optarg); + } else + error (EXIT_FAILURE, 0, + _("unknown long option: %s (%d)"), +@@ -214,10 +226,19 @@ main (int argc, char *argv[]) + OPTION_d; + break; + ++ case 'i': ++ OPTION_i; ++ break; ++ + case 'm': +- if (sscanf (optarg, "%d", &memsize) != 1) +- error (EXIT_FAILURE, 0, +- _("could not parse memory size '%s'"), optarg); ++ /* For backwards compatibility with virt-rescue <= 1.36, we ++ * must handle -m as a synonym for --memsize. ++ */ ++ if (sscanf (optarg, "%d", &m) == 1) ++ memsize = m; ++ else { ++ OPTION_m; ++ } + break; + + case 'r': +@@ -288,7 +309,6 @@ main (int argc, char *argv[]) + * options parsing code. Assert here that they have known-good + * values. + */ +- assert (inspector == 0); + assert (keys_from_stdin == 0); + assert (echo_keys == 0); + assert (live == 0); +@@ -332,12 +352,6 @@ main (int argc, char *argv[]) + exit (EXIT_FAILURE); + free (append_full); + +- /* Add drives. */ +- add_drives (drvs); +- +- /* Free up data structures, no longer needed after this point. */ +- free_drives (drvs); +- + /* Add an event handler to print "log messages". These will be the + * output of the appliance console during launch and shutdown. + * After launch, we will read the console messages directly from the +@@ -347,21 +361,50 @@ main (int argc, char *argv[]) + GUESTFS_EVENT_APPLIANCE, 0, NULL) == -1) + exit (EXIT_FAILURE); + +- /* Run the appliance. */ ++ /* Do the guest drives and mountpoints. */ ++ add_drives (drvs); + if (guestfs_launch (g) == -1) + exit (EXIT_FAILURE); ++ if (inspector) ++ inspect_mount (); ++ mount_mps (mps); ++ ++ free_drives (drvs); ++ free_mps (mps); ++ ++ /* Also bind-mount /dev etc under /sysroot, if -i was given. */ ++ if (inspector) { ++ CLEANUP_FREE_STRING_LIST char **roots; ++ int windows; ++ ++ roots = guestfs_inspect_get_roots (g); ++ windows = roots && roots[0] && is_windows (g, roots[0]); ++ if (!windows) { ++ const char *cmd[5] = { "mount", "--rbind", NULL, NULL, NULL }; ++ char *r; ++ ++ cmd[2] = "/dev"; cmd[3] = "/sysroot/dev"; ++ r = guestfs_debug (g, "sh", (char **) cmd); ++ free (r); ++ ++ cmd[2] = "/proc"; cmd[3] = "/sysroot/proc"; ++ r = guestfs_debug (g, "sh", (char **) cmd); ++ free (r); ++ ++ cmd[2] = "/sys"; cmd[3] = "/sysroot/sys"; ++ r = guestfs_debug (g, "sh", (char **) cmd); ++ free (r); ++ } ++ } + + sock = guestfs_internal_get_console_socket (g); + if (sock == -1) + exit (EXIT_FAILURE); + + /* Try to set all sockets to non-blocking. */ +- if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1) +- perror ("could not set stdin to non-blocking"); +- if (fcntl (STDOUT_FILENO, F_SETFL, O_NONBLOCK) == -1) +- perror ("could not set stdout to non-blocking"); +- if (fcntl (sock, F_SETFL, O_NONBLOCK) == -1) +- perror ("could not set console socket to non-blocking"); ++ ignore_value (set_nonblocking_flag (STDIN_FILENO, 1)); ++ ignore_value (set_nonblocking_flag (STDOUT_FILENO, 1)); ++ ignore_value (set_nonblocking_flag (sock, 1)); + + /* Save the initial state of the tty so we always have the original + * state to go back to. +diff --git a/rescue/virt-rescue.pod b/rescue/virt-rescue.pod +index b8aa32637..b651f84e7 100644 +--- a/rescue/virt-rescue.pod ++++ b/rescue/virt-rescue.pod +@@ -6,9 +6,7 @@ virt-rescue - Run a rescue shell on a virtual machine + + virt-rescue [--options] -d domname + +- virt-rescue [--options] -a disk.img [-a disk.img ...] +- +- virt-rescue --suggest (-d domname | -a disk.img ...) ++ virt-rescue [--options] -a disk.img [-a disk.img ...] [-i] + + Old style: + +@@ -26,13 +24,13 @@ machine or disk image. + You can run virt-rescue on any virtual machine known to libvirt, or + directly on disk image(s): + +- virt-rescue -d GuestName ++ virt-rescue -d GuestName -i + +- virt-rescue --ro -a /path/to/disk.img ++ virt-rescue --ro -a /path/to/disk.img -i + + virt-rescue -a /dev/sdc + +-For live VMs you I use the --ro option. ++For live VMs you I use the I<--ro> option. + + When you run virt-rescue on a virtual machine or disk image, you are + placed in an interactive bash shell where you can use many ordinary +@@ -41,26 +39,10 @@ rescue appliance. You must mount the virtual machine's filesystems by + hand. There is an empty directory called F where you can + mount filesystems. + +-You can get virt-rescue to suggest mount commands for you by using the +-I<--suggest> option (in another terminal): +- +- $ virt-rescue --suggest -d Fedora15 +- Inspecting the virtual machine or disk image ... +- +- This disk contains one or more operating systems. You can use these +- mount commands in virt-rescue (at the > prompt) to mount the +- filesystems. +- +- # /dev/vg_f15x32/lv_root is the root of a linux operating system +- # type: linux, distro: fedora, version: 15.0 +- # Fedora release 15 (Lovelock) +- +- mount /dev/vg_f15x32/lv_root /sysroot/ +- mount /dev/vda1 /sysroot/boot +- mount --bind /dev /sysroot/dev +- mount --bind /dev/pts /sysroot/dev/pts +- mount --bind /proc /sysroot/proc +- mount --bind /sys /sysroot/sys ++To automatically mount the virtual machine's filesystems under ++F use the I<-i> option. This uses libguestfs inspection to ++find the filesystems and mount them in the right place. You can also ++mount filesystems individually using the I<-m> option. + + Another way is to list the logical volumes (with L) and + partitions (with L) and mount them by hand: +@@ -170,7 +152,15 @@ If you have untrusted raw-format guest disk images, you should use + this option to specify the disk format. This avoids a possible + security problem with malicious guests (CVE-2010-3851). + +-=item B<-m> MB ++=item B<-i> ++ ++=item B<--inspector> ++ ++Using L code, inspect the disks looking for ++an operating system and mount filesystems as they would be ++mounted on the real virtual machine. ++ ++The filesystems are mounted on F in the rescue environment. + + =item B<--memsize> MB + +@@ -179,6 +169,33 @@ default is set by libguestfs and is small but adequate for running + system tools. The occasional program might need more memory. The + parameter is specified in megabytes. + ++=item B<-m> dev[:mountpoint[:options[:fstype]]] ++ ++=item B<--mount> dev[:mountpoint[:options[:fstype]]] ++ ++Mount the named partition or logical volume on the given mountpoint ++B (this has nothing to do with mountpoints in the host). ++ ++If the mountpoint is omitted, it defaults to F. You have to mount ++something on F. ++ ++The filesystems are mounted under F in the rescue environment. ++ ++The third (and rarely used) part of the mount parameter is the list of ++mount options used to mount the underlying filesystem. If this is not ++given, then the mount options are either the empty string or C ++(the latter if the I<--ro> flag is used). By specifying the mount ++options, you override this default choice. Probably the only time you ++would use this is to enable ACLs and/or extended attributes if the ++filesystem can support them: ++ ++ -m /dev/sda1:/:acl,user_xattr ++ ++The fourth part of the parameter is the filesystem driver to use, such ++as C or C. This is rarely needed, but can be useful if ++multiple drivers are valid for a filesystem (eg: C and C), ++or if libguestfs misidentifies a filesystem. ++ + =item B<--network> + + Enable QEMU user networking in the guest. See L. +@@ -217,9 +234,10 @@ Enable N E 2 virtual CPUs in the rescue appliance. + + =item B<--suggest> + +-Inspect the disk image and suggest what mount commands should be used +-to mount the disks. You should use the I<--suggest> option in a +-second terminal, then paste the commands into another virt-rescue. ++This option was used in older versions of virt-rescue to suggest what ++commands you could use to mount filesystems under F. For ++the current version of virt-rescue, it is easier to use the I<-i> ++option instead. + + This option implies I<--ro> and is safe to use even if the guest is up + or if another virt-rescue is running. +@@ -240,7 +258,7 @@ Display version number and exit. + + =item B<--rw> + +-This changes the I<-a> and I<-d> options so that disks are ++This changes the I<-a>, I<-d> and I<-m> options so that disks are + added and mounts are done read-write. + + See L. +-- +2.14.3 + diff --git a/SOURCES/0058-rescue-Implement-escape-sequences.patch b/SOURCES/0058-rescue-Implement-escape-sequences.patch new file mode 100644 index 0000000..4c00900 --- /dev/null +++ b/SOURCES/0058-rescue-Implement-escape-sequences.patch @@ -0,0 +1,615 @@ +From 50e044064b4388f11912d96d2eb52aea1b292734 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 4 Mar 2017 11:47:59 +0000 +Subject: [PATCH] rescue: Implement escape sequences. + +This implements a few useful escape sequences: + +> ^]? +virt-rescue escape sequences: + ^] ? - print this message + ^] h - print this message + ^] q - quit virt-rescue + ^] s - sync the filesystems + ^] u - unmount filesystems + ^] x - quit virt-rescue + ^] z - suspend virt-rescue +to pass the escape key through to the rescue shell, type it twice + +^]i + +root device: /dev/sda3 + product name: Fedora 25 (Twenty Five) + type: linux + distro: fedora + +^]z +[3]+ Stopped ./run virt-rescue --scratch +$ fg + +> ^]u + +unmounting filesystems ... +[ 21.158558] XFS (sda3): Unmounting Filesystem + +(cherry picked from commit 3637c42f4e521eb647d7dfae7f48eb1689d0af54) +--- + rescue/Makefile.am | 4 +- + rescue/escape.c | 302 +++++++++++++++++++++++++++++++++++++++++++++++++ + rescue/rescue.c | 30 ++++- + rescue/rescue.h | 47 ++++++++ + rescue/virt-rescue.pod | 74 ++++++++++++ + 5 files changed, 454 insertions(+), 3 deletions(-) + create mode 100644 rescue/escape.c + create mode 100644 rescue/rescue.h + +diff --git a/rescue/Makefile.am b/rescue/Makefile.am +index c83c43458..eb60bafa4 100644 +--- a/rescue/Makefile.am ++++ b/rescue/Makefile.am +@@ -26,7 +26,9 @@ EXTRA_DIST = \ + bin_PROGRAMS = virt-rescue + + virt_rescue_SOURCES = \ +- rescue.c ++ escape.c \ ++ rescue.c \ ++ rescue.h + + virt_rescue_CPPFLAGS = \ + -DGUESTFS_WARN_DEPRECATED=1 \ +diff --git a/rescue/escape.c b/rescue/escape.c +new file mode 100644 +index 000000000..f7f7d84c4 +--- /dev/null ++++ b/rescue/escape.c +@@ -0,0 +1,302 @@ ++/* virt-rescue ++ * Copyright (C) 2010-2017 Red Hat Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "c-ctype.h" ++ ++#include "guestfs.h" ++#include "guestfs-internal-frontend.h" ++ ++#include "rescue.h" ++ ++static void print_help (void); ++static void print_inspector (void); ++static void crlf (void); ++static void print_escape_key (void); ++ ++/* Parse the -e parameter from the command line. */ ++int ++parse_escape_key (const char *arg) ++{ ++ size_t len; ++ ++ if (STREQ (arg, "none")) ++ return 0; ++ ++ len = strlen (arg); ++ if (arg == 0) ++ return -1; ++ ++ switch (arg[0]) { ++ case '^': ++ if (len == 2 && ++ ((arg[1] >= 'a' && arg[1] <= 'z') || ++ (arg[1] >= 'A' && arg[1] <= '_'))) { ++ return c_toupper (arg[1]) - '@'; ++ } ++ else ++ return -1; ++ break; ++ } ++ ++ return -1; ++} ++ ++/* Print one-line end user description of the escape key. ++ * ++ * This is printed when virt-rescue starts. ++ */ ++void ++print_escape_key_help (void) ++{ ++ crlf (); ++ /* Difficult to translate this string. XXX */ ++ printf ("The virt-rescue escape key is ‘"); ++ print_escape_key (); ++ printf ("’. Type ‘"); ++ print_escape_key (); ++ printf (" h’ for help."); ++ crlf (); ++} ++ ++void ++init_escape_state (struct escape_state *state) ++{ ++ state->in_escape = false; ++} ++ ++/* Process escapes in the tty input buffer. ++ * ++ * This function has a state parameter so that we can handle an escape ++ * sequence split over the end of the buffer. ++ * ++ * Escape sequences are removed from the buffer. ++ * ++ * Returns true iff virt-rescue should exit. ++ */ ++bool ++process_escapes (struct escape_state *state, char *buf, size_t *len) ++{ ++ size_t i; ++ ++ for (i = 0; i < *len; ++i) { ++#define DROP_CURRENT_CHAR() \ ++ memmove (&buf[i], &buf[i+1], --(*len)) ++#define PRINT_ESC() \ ++ do { print_escape_key (); putchar (buf[i]); crlf (); } while (0) ++ ++ if (!state->in_escape) { ++ if (buf[i] == escape_key) { ++ /* Drop the escape key from the buffer and go to escape mode. */ ++ DROP_CURRENT_CHAR (); ++ state->in_escape = true; ++ } ++ } ++ else /* in escape sequence */ { ++ if (buf[i] == escape_key) /* ^] ^] means send ^] to rescue shell */ ++ state->in_escape = false; ++ else { ++ switch (buf[i]) { ++ case '?': case 'h': ++ PRINT_ESC (); ++ print_help (); ++ break; ++ ++ case 'i': ++ PRINT_ESC (); ++ print_inspector (); ++ break; ++ ++ case 'q': case 'x': ++ PRINT_ESC (); ++ return true /* exit virt-rescue at once */; ++ ++ case 's': ++ PRINT_ESC (); ++ printf (_("attempting to sync filesystems ...")); ++ crlf (); ++ guestfs_sync (g); ++ break; ++ ++ case 'u': ++ PRINT_ESC (); ++ printf (_("unmounting filesystems ...")); ++ crlf (); ++ guestfs_umount_all (g); ++ break; ++ ++ case 'z': ++ PRINT_ESC (); ++ raise (SIGTSTP); ++ break; ++ ++ default: ++ /* Any unrecognized escape sequence will be dropped. We ++ * could be obnoxious and ring the bell, but I hate it when ++ * programs do that. ++ */ ++ break; ++ } ++ ++ /* Drop the escape key and return to non-escape mode. */ ++ DROP_CURRENT_CHAR (); ++ state->in_escape = false; ++ ++ /* The output is line buffered, this is just to make sure ++ * everything gets written to stdout before we continue ++ * writing to STDOUT_FILENO. ++ */ ++ fflush (stdout); ++ } ++ } /* in escape sequence */ ++ } /* for */ ++ ++ return false /* don't exit */; ++} ++ ++/* This is called when the user types ^] h */ ++static void ++print_help (void) ++{ ++ printf (_("virt-rescue escape sequences:")); ++ crlf (); ++ ++ putchar (' '); ++ print_escape_key (); ++ printf (_(" ? - print this message")); ++ crlf (); ++ ++ putchar (' '); ++ print_escape_key (); ++ printf (_(" h - print this message")); ++ crlf (); ++ ++ if (inspector) { ++ putchar (' '); ++ print_escape_key (); ++ printf (_(" i - print inspection data")); ++ crlf (); ++ } ++ ++ putchar (' '); ++ print_escape_key (); ++ printf (_(" q - quit virt-rescue")); ++ crlf (); ++ ++ putchar (' '); ++ print_escape_key (); ++ printf (_(" s - sync the filesystems")); ++ crlf (); ++ ++ putchar (' '); ++ print_escape_key (); ++ printf (_(" u - unmount filesystems")); ++ crlf (); ++ ++ putchar (' '); ++ print_escape_key (); ++ printf (_(" x - quit virt-rescue")); ++ crlf (); ++ ++ putchar (' '); ++ print_escape_key (); ++ printf (_(" z - suspend virt-rescue")); ++ crlf (); ++ ++ printf (_("to pass the escape key through to the rescue shell, type it twice")); ++ crlf (); ++} ++ ++/* This is called when the user types ^] i */ ++static void ++print_inspector (void) ++{ ++ CLEANUP_FREE_STRING_LIST char **roots; ++ size_t i; ++ const char *root; ++ char *str; ++ ++ if (inspector) { ++ roots = guestfs_inspect_get_roots (g); ++ if (roots) { ++ crlf (); ++ for (i = 0; roots[i] != NULL; ++i) { ++ root = roots[i]; ++ printf (_("root device: %s"), root); ++ crlf (); ++ ++ str = guestfs_inspect_get_product_name (g, root); ++ if (str) { ++ printf (_(" product name: %s"), str); ++ crlf (); ++ } ++ free (str); ++ ++ str = guestfs_inspect_get_type (g, root); ++ if (str) { ++ printf (_(" type: %s"), str); ++ crlf (); ++ } ++ free (str); ++ ++ str = guestfs_inspect_get_distro (g, root); ++ if (str) { ++ printf (_(" distro: %s"), str); ++ crlf (); ++ } ++ free (str); ++ } ++ } ++ } ++} ++ ++/* Because the terminal is in raw mode, we have to send CR LF instead ++ * of printing just \n. ++ */ ++static void ++crlf (void) ++{ ++ putchar ('\r'); ++ putchar ('\n'); ++} ++ ++static void ++print_escape_key (void) ++{ ++ switch (escape_key) { ++ case 0: ++ printf ("none"); ++ break; ++ case '\x1'...'\x1f': ++ putchar ('^'); ++ putchar (escape_key + '@'); ++ break; ++ default: ++ abort (); ++ } ++} +diff --git a/rescue/rescue.c b/rescue/rescue.c +index 2b461378d..5281b1161 100644 +--- a/rescue/rescue.c ++++ b/rescue/rescue.c +@@ -1,5 +1,5 @@ + /* virt-rescue +- * Copyright (C) 2010-2012 Red Hat Inc. ++ * Copyright (C) 2010-2017 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -40,10 +40,14 @@ + #include "xvasprintf.h" + + #include "guestfs.h" ++#include "guestfs-internal-frontend.h" ++ + #include "windows.h" + #include "options.h" + #include "display-options.h" + ++#include "rescue.h" ++ + static void log_message_callback (guestfs_h *g, void *opaque, uint64_t event, int event_handle, int flags, const char *buf, size_t buf_len, const uint64_t *array, size_t array_len); + static void do_rescue (int sock); + static void raw_tty (void); +@@ -65,6 +69,7 @@ const char *libvirt_uri = NULL; + int inspector = 0; + int in_guestfish = 0; + int in_virt_rescue = 1; ++int escape_key = '\x1d'; /* ^] */ + + /* Old terminal settings. */ + static struct termios old_termios; +@@ -86,6 +91,7 @@ usage (int status) + " --append kernelopts Append kernel options\n" + " -c|--connect uri Specify libvirt URI for -d option\n" + " -d|--domain guest Add disks from libvirt guest\n" ++ " -e ^x|none Set or disable escape key (default ^])\n" + " --format[=raw|..] Force disk format for -a option\n" + " --help Display brief help\n" + " -i|--inspector Automatically mount filesystems\n" +@@ -119,7 +125,7 @@ main (int argc, char *argv[]) + + enum { HELP_OPTION = CHAR_MAX + 1 }; + +- static const char options[] = "a:c:d:im:rvVwx"; ++ static const char options[] = "a:c:d:e:im:rvVwx"; + static const struct option long_options[] = { + { "add", 1, 0, 'a' }, + { "append", 1, 0, 0 }, +@@ -226,6 +232,12 @@ main (int argc, char *argv[]) + OPTION_d; + break; + ++ case 'e': ++ escape_key = parse_escape_key (optarg); ++ if (escape_key == -1) ++ error (EXIT_FAILURE, 0, _("unrecognized escape key: %s"), optarg); ++ break; ++ + case 'i': + OPTION_i; + break; +@@ -428,6 +440,10 @@ main (int argc, char *argv[]) + signal (SIGTSTP, tstp_handler); + signal (SIGCONT, cont_handler); + ++ /* Print the escape key if set. */ ++ if (escape_key > 0) ++ print_escape_key_help (); ++ + do_rescue (sock); + + restore_tty (); +@@ -478,6 +494,9 @@ do_rescue (int sock) + { + size_t rlen = 0; + size_t wlen = 0; ++ struct escape_state escape_state; ++ ++ init_escape_state (&escape_state); + + while (sock >= 0 || rlen > 0) { + struct pollfd fds[3]; +@@ -534,6 +553,13 @@ do_rescue (int sock) + } + if (n > 0) + wlen += n; ++ ++ /* Process escape sequences in the tty input. If the function ++ * returns true, then we exit the loop causing virt-rescue to ++ * exit. ++ */ ++ if (escape_key > 0 && process_escapes (&escape_state, wbuf, &wlen)) ++ return; + } + + /* Log message from appliance. */ +diff --git a/rescue/rescue.h b/rescue/rescue.h +new file mode 100644 +index 000000000..ccffb5eb3 +--- /dev/null ++++ b/rescue/rescue.h +@@ -0,0 +1,47 @@ ++/* virt-rescue ++ * Copyright (C) 2010-2017 Red Hat Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#ifndef RESCUE_H ++#define RESCUE_H ++ ++#include ++ ++#include "guestfs.h" ++ ++extern guestfs_h *g; ++extern int read_only; ++extern int live; ++extern int verbose; ++extern int keys_from_stdin; ++extern int echo_keys; ++extern const char *libvirt_uri; ++extern int inspector; ++extern int in_guestfish; ++extern int in_virt_rescue; ++extern int escape_key; ++ ++/* escape.c */ ++struct escape_state { ++ bool in_escape; ++}; ++extern void init_escape_state (struct escape_state *state); ++extern bool process_escapes (struct escape_state *state, char *buf, size_t *len); ++extern int parse_escape_key (const char *); ++extern void print_escape_key_help (void); ++ ++#endif /* RESCUE_H */ +diff --git a/rescue/virt-rescue.pod b/rescue/virt-rescue.pod +index b651f84e7..bd6f954e9 100644 +--- a/rescue/virt-rescue.pod ++++ b/rescue/virt-rescue.pod +@@ -128,6 +128,29 @@ not used at all. + Add all the disks from the named libvirt guest. Domain UUIDs can be + used instead of names. + ++=item B<-e none> ++ ++Disable the escape key. ++ ++=item B<-e> KEY ++ ++Set the escape key to the given key sequence. The default is C<^]>. ++To specify the escape key you can use: ++ ++=over 4 ++ ++=item C<^x> ++ ++Control key + C key. ++ ++=item C ++ ++I<-e none> means there is no escape key, escapes are disabled. ++ ++=back ++ ++See L below for further information. ++ + =item B<--format=raw|qcow2|..> + + =item B<--format> +@@ -321,6 +344,57 @@ See L for more details. + + =back + ++=head1 ESCAPE KEY ++ ++Virt-rescue supports various keyboard escape sequences which are ++entered by pressing C<^]> (Control key + C<]> key). ++ ++You can change the escape key using the I<-e> option on the command ++line (see above), and you can disable escapes completely using ++I<-e none>. The rest of this section assumes the default escape key. ++ ++The following escapes can be used: ++ ++=over 4 ++ ++=item C<^] ?> ++ ++=item C<^] h> ++ ++Prints a brief help text about escape sequences. ++ ++=item C<^] i> ++ ++Prints brief libguestfs inspection information for the guest. This ++only works if you used I<-i> on the virt-rescue command line. ++ ++=item C<^] q> ++ ++=item C<^] x> ++ ++Quits virt-rescue immediately. ++ ++=item C<^] s> ++ ++Synchronize the filesystems (sync). ++ ++=item C<^] u> ++ ++Unmounts all the filesystems, except for the root (appliance) ++filesystems. ++ ++=item C<^] z> ++ ++Suspend virt-rescue (like pressing C<^Z> except that it affects ++virt-rescue rather than the program inside the rescue shell). ++ ++=item C<^] ^]> ++ ++Sends the literal character C<^]> (ASCII 0x1d) through to the rescue ++shell. ++ ++=back ++ + =head1 CAPTURING CORE DUMPS + + If you are testing a tool inside virt-rescue and the tool (B +-- +2.14.3 + diff --git a/SOURCES/0059-rescue-Move-suggest-code-to-separate-file.patch b/SOURCES/0059-rescue-Move-suggest-code-to-separate-file.patch new file mode 100644 index 0000000..00585e9 --- /dev/null +++ b/SOURCES/0059-rescue-Move-suggest-code-to-separate-file.patch @@ -0,0 +1,397 @@ +From 0a3e771414378057d0e838c6a45d2f840ff7a8af Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 4 Mar 2017 15:35:09 +0000 +Subject: [PATCH] rescue: Move --suggest code to separate file. + +Just code motion. + +(cherry picked from commit 5ea17e97e4413c3db4449ded72b9677cce09444f) +--- + rescue/Makefile.am | 3 +- + rescue/rescue.c | 144 ------------------------------------------- + rescue/rescue.h | 5 ++ + rescue/suggest.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 182 insertions(+), 145 deletions(-) + create mode 100644 rescue/suggest.c + +diff --git a/rescue/Makefile.am b/rescue/Makefile.am +index eb60bafa4..d478c8e3d 100644 +--- a/rescue/Makefile.am ++++ b/rescue/Makefile.am +@@ -28,7 +28,8 @@ bin_PROGRAMS = virt-rescue + virt_rescue_SOURCES = \ + escape.c \ + rescue.c \ +- rescue.h ++ rescue.h \ ++ suggest.c + + virt_rescue_CPPFLAGS = \ + -DGUESTFS_WARN_DEPRECATED=1 \ +diff --git a/rescue/rescue.c b/rescue/rescue.c +index 5281b1161..a1aac53e4 100644 +--- a/rescue/rescue.c ++++ b/rescue/rescue.c +@@ -55,7 +55,6 @@ static void restore_tty (void); + static void tstp_handler (int sig); + static void cont_handler (int sig); + static void add_scratch_disks (int n, struct drv **drvs); +-static void do_suggestion (struct drv *drvs); + + /* Currently open libguestfs handle. */ + guestfs_h *g; +@@ -654,149 +653,6 @@ cont_handler (int sig) + raw_tty (); + } + +-static void suggest_filesystems (void); +- +-static int +-compare_keys_len (const void *p1, const void *p2) +-{ +- const char *key1 = * (char * const *) p1; +- const char *key2 = * (char * const *) p2; +- return strlen (key1) - strlen (key2); +-} +- +-/* virt-rescue --suggest flag does a kind of inspection on the +- * drives and suggests mount commands that you should use. +- */ +-static void +-do_suggestion (struct drv *drvs) +-{ +- CLEANUP_FREE_STRING_LIST char **roots = NULL; +- size_t i; +- +- /* For inspection, force add_drives to add the drives read-only. */ +- read_only = 1; +- +- /* Add drives. */ +- add_drives (drvs); +- +- /* Free up data structures, no longer needed after this point. */ +- free_drives (drvs); +- +- printf (_("Inspecting the virtual machine or disk image ...\n\n")); +- fflush (stdout); +- +- if (guestfs_launch (g) == -1) +- exit (EXIT_FAILURE); +- +- /* Don't use inspect_mount, since for virt-rescue we should allow +- * arbitrary disks and disks with more than one OS on them. Let's +- * do this using the basic API instead. +- */ +- roots = guestfs_inspect_os (g); +- if (roots == NULL) +- exit (EXIT_FAILURE); +- +- if (roots[0] == NULL) { +- suggest_filesystems (); +- return; +- } +- +- printf (_("This disk contains one or more operating systems. You can use these mount\n" +- "commands in virt-rescue (at the > prompt) to mount the filesystems.\n\n")); +- +- for (i = 0; roots[i] != NULL; ++i) { +- CLEANUP_FREE_STRING_LIST char **mps = NULL; +- CLEANUP_FREE char *type = NULL, *distro = NULL, *product_name = NULL; +- int major, minor; +- size_t j; +- +- type = guestfs_inspect_get_type (g, roots[i]); +- distro = guestfs_inspect_get_distro (g, roots[i]); +- product_name = guestfs_inspect_get_product_name (g, roots[i]); +- major = guestfs_inspect_get_major_version (g, roots[i]); +- minor = guestfs_inspect_get_minor_version (g, roots[i]); +- +- printf (_("# %s is the root of a %s operating system\n" +- "# type: %s, distro: %s, version: %d.%d\n" +- "# %s\n\n"), +- roots[i], type ? : "unknown", +- type ? : "unknown", distro ? : "unknown", major, minor, +- product_name ? : ""); +- +- mps = guestfs_inspect_get_mountpoints (g, roots[i]); +- if (mps == NULL) +- exit (EXIT_FAILURE); +- +- /* Sort by key length, shortest key first, so that we end up +- * mounting the filesystems in the correct order. +- */ +- qsort (mps, guestfs_int_count_strings (mps) / 2, 2 * sizeof (char *), +- compare_keys_len); +- +- for (j = 0; mps[j] != NULL; j += 2) +- printf ("mount %s /sysroot%s\n", mps[j+1], mps[j]); +- +- /* If it's Linux, print the bind-mounts and a chroot command. */ +- if (type && STREQ (type, "linux")) { +- printf ("mount --rbind /dev /sysroot/dev\n"); +- printf ("mount --rbind /proc /sysroot/proc\n"); +- printf ("mount --rbind /sys /sysroot/sys\n"); +- printf ("\n"); +- printf ("cd /sysroot\n"); +- printf ("chroot /sysroot\n"); +- } +- +- printf ("\n"); +- } +-} +- +-/* Inspection failed, so it doesn't contain any OS that we recognise. +- * However there might still be filesystems so print some suggestions +- * for those. +- */ +-static void +-suggest_filesystems (void) +-{ +- size_t i, count; +- +- CLEANUP_FREE_STRING_LIST char **fses = guestfs_list_filesystems (g); +- if (fses == NULL) +- exit (EXIT_FAILURE); +- +- /* Count how many are not swap or unknown. Possibly we should try +- * mounting to see which are mountable, but that has a high +- * probability of breaking. +- */ +-#define TEST_MOUNTABLE(fs) STRNEQ ((fs), "swap") && STRNEQ ((fs), "unknown") +- count = 0; +- for (i = 0; fses[i] != NULL; i += 2) { +- if (TEST_MOUNTABLE (fses[i+1])) +- count++; +- } +- +- if (count == 0) { +- printf (_("This disk contains no mountable filesystems that we recognize.\n\n" +- "However you can still use virt-rescue on the disk image, to try to mount\n" +- "filesystems that are not recognized by libguestfs, or to create partitions,\n" +- "logical volumes and filesystems on a blank disk.\n")); +- return; +- } +- +- printf (_("This disk contains one or more filesystems, but we don't recognize any\n" +- "operating system. You can use these mount commands in virt-rescue (at the\n" +- "> prompt) to mount these filesystems.\n\n")); +- +- for (i = 0; fses[i] != NULL; i += 2) { +- printf (_("# %s has type '%s'\n"), fses[i], fses[i+1]); +- +- if (TEST_MOUNTABLE (fses[i+1])) +- printf ("mount %s /sysroot\n", fses[i]); +- +- printf ("\n"); +- } +-#undef TEST_MOUNTABLE +-} +- + static void add_scratch_disk (struct drv **drvs); + + static void +diff --git a/rescue/rescue.h b/rescue/rescue.h +index ccffb5eb3..4f5a04a71 100644 +--- a/rescue/rescue.h ++++ b/rescue/rescue.h +@@ -23,6 +23,8 @@ + + #include "guestfs.h" + ++#include "options.h" ++ + extern guestfs_h *g; + extern int read_only; + extern int live; +@@ -44,4 +46,7 @@ extern bool process_escapes (struct escape_state *state, char *buf, size_t *len) + extern int parse_escape_key (const char *); + extern void print_escape_key_help (void); + ++/* suggest.c */ ++extern void do_suggestion (struct drv *drvs); ++ + #endif /* RESCUE_H */ +diff --git a/rescue/suggest.c b/rescue/suggest.c +new file mode 100644 +index 000000000..13141ccc2 +--- /dev/null ++++ b/rescue/suggest.c +@@ -0,0 +1,175 @@ ++/* virt-rescue ++ * Copyright (C) 2010-2017 Red Hat Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "guestfs.h" ++#include "guestfs-internal-frontend.h" ++ ++#include "options.h" ++ ++#include "rescue.h" ++ ++static void suggest_filesystems (void); ++ ++static int ++compare_keys_len (const void *p1, const void *p2) ++{ ++ const char *key1 = * (char * const *) p1; ++ const char *key2 = * (char * const *) p2; ++ return strlen (key1) - strlen (key2); ++} ++ ++/* virt-rescue --suggest flag does a kind of inspection on the ++ * drives and suggests mount commands that you should use. ++ */ ++void ++do_suggestion (struct drv *drvs) ++{ ++ CLEANUP_FREE_STRING_LIST char **roots = NULL; ++ size_t i; ++ ++ /* For inspection, force add_drives to add the drives read-only. */ ++ read_only = 1; ++ ++ /* Add drives. */ ++ add_drives (drvs); ++ ++ /* Free up data structures, no longer needed after this point. */ ++ free_drives (drvs); ++ ++ printf (_("Inspecting the virtual machine or disk image ...\n\n")); ++ fflush (stdout); ++ ++ if (guestfs_launch (g) == -1) ++ exit (EXIT_FAILURE); ++ ++ /* Don't use inspect_mount, since for virt-rescue we should allow ++ * arbitrary disks and disks with more than one OS on them. Let's ++ * do this using the basic API instead. ++ */ ++ roots = guestfs_inspect_os (g); ++ if (roots == NULL) ++ exit (EXIT_FAILURE); ++ ++ if (roots[0] == NULL) { ++ suggest_filesystems (); ++ return; ++ } ++ ++ printf (_("This disk contains one or more operating systems. You can use these mount\n" ++ "commands in virt-rescue (at the > prompt) to mount the filesystems.\n\n")); ++ ++ for (i = 0; roots[i] != NULL; ++i) { ++ CLEANUP_FREE_STRING_LIST char **mps = NULL; ++ CLEANUP_FREE char *type = NULL, *distro = NULL, *product_name = NULL; ++ int major, minor; ++ size_t j; ++ ++ type = guestfs_inspect_get_type (g, roots[i]); ++ distro = guestfs_inspect_get_distro (g, roots[i]); ++ product_name = guestfs_inspect_get_product_name (g, roots[i]); ++ major = guestfs_inspect_get_major_version (g, roots[i]); ++ minor = guestfs_inspect_get_minor_version (g, roots[i]); ++ ++ printf (_("# %s is the root of a %s operating system\n" ++ "# type: %s, distro: %s, version: %d.%d\n" ++ "# %s\n\n"), ++ roots[i], type ? : "unknown", ++ type ? : "unknown", distro ? : "unknown", major, minor, ++ product_name ? : ""); ++ ++ mps = guestfs_inspect_get_mountpoints (g, roots[i]); ++ if (mps == NULL) ++ exit (EXIT_FAILURE); ++ ++ /* Sort by key length, shortest key first, so that we end up ++ * mounting the filesystems in the correct order. ++ */ ++ qsort (mps, guestfs_int_count_strings (mps) / 2, 2 * sizeof (char *), ++ compare_keys_len); ++ ++ for (j = 0; mps[j] != NULL; j += 2) ++ printf ("mount %s /sysroot%s\n", mps[j+1], mps[j]); ++ ++ /* If it's Linux, print the bind-mounts and a chroot command. */ ++ if (type && STREQ (type, "linux")) { ++ printf ("mount --rbind /dev /sysroot/dev\n"); ++ printf ("mount --rbind /proc /sysroot/proc\n"); ++ printf ("mount --rbind /sys /sysroot/sys\n"); ++ printf ("\n"); ++ printf ("cd /sysroot\n"); ++ printf ("chroot /sysroot\n"); ++ } ++ ++ printf ("\n"); ++ } ++} ++ ++/* Inspection failed, so it doesn't contain any OS that we recognise. ++ * However there might still be filesystems so print some suggestions ++ * for those. ++ */ ++static void ++suggest_filesystems (void) ++{ ++ size_t i, count; ++ ++ CLEANUP_FREE_STRING_LIST char **fses = guestfs_list_filesystems (g); ++ if (fses == NULL) ++ exit (EXIT_FAILURE); ++ ++ /* Count how many are not swap or unknown. Possibly we should try ++ * mounting to see which are mountable, but that has a high ++ * probability of breaking. ++ */ ++#define TEST_MOUNTABLE(fs) STRNEQ ((fs), "swap") && STRNEQ ((fs), "unknown") ++ count = 0; ++ for (i = 0; fses[i] != NULL; i += 2) { ++ if (TEST_MOUNTABLE (fses[i+1])) ++ count++; ++ } ++ ++ if (count == 0) { ++ printf (_("This disk contains no mountable filesystems that we recognize.\n\n" ++ "However you can still use virt-rescue on the disk image, to try to mount\n" ++ "filesystems that are not recognized by libguestfs, or to create partitions,\n" ++ "logical volumes and filesystems on a blank disk.\n")); ++ return; ++ } ++ ++ printf (_("This disk contains one or more filesystems, but we don't recognize any\n" ++ "operating system. You can use these mount commands in virt-rescue (at the\n" ++ "> prompt) to mount these filesystems.\n\n")); ++ ++ for (i = 0; fses[i] != NULL; i += 2) { ++ printf (_("# %s has type '%s'\n"), fses[i], fses[i+1]); ++ ++ if (TEST_MOUNTABLE (fses[i+1])) ++ printf ("mount %s /sysroot\n", fses[i]); ++ ++ printf ("\n"); ++ } ++#undef TEST_MOUNTABLE ++} +-- +2.14.3 + diff --git a/SOURCES/0060-rescue-docs-It-is-no-longer-necessary-to-mount-files.patch b/SOURCES/0060-rescue-docs-It-is-no-longer-necessary-to-mount-files.patch new file mode 100644 index 0000000..34c658e --- /dev/null +++ b/SOURCES/0060-rescue-docs-It-is-no-longer-necessary-to-mount-files.patch @@ -0,0 +1,35 @@ +From 71b79b9aa2bdfa9a39fa1d81ab2d59331c386039 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 24 Mar 2017 22:51:06 +0000 +Subject: [PATCH] rescue: docs: It is no longer necessary to mount filesystems + by hand. + +Fix the manual page to reflect the new -i option. + +Fixes commit 33d2ae796119ae5dd38e2afcbf1ba4216bd99846. + +(cherry picked from commit c38b48409e067ba973d02bb10273350aa31b558e) +--- + rescue/virt-rescue.pod | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/rescue/virt-rescue.pod b/rescue/virt-rescue.pod +index bd6f954e9..dfa74e204 100644 +--- a/rescue/virt-rescue.pod ++++ b/rescue/virt-rescue.pod +@@ -35,9 +35,9 @@ For live VMs you I use the I<--ro> option. + When you run virt-rescue on a virtual machine or disk image, you are + placed in an interactive bash shell where you can use many ordinary + Linux commands. What you see in F (F, F etc) is the +-rescue appliance. You must mount the virtual machine's filesystems by +-hand. There is an empty directory called F where you can +-mount filesystems. ++rescue appliance. You must mount the virtual machine's filesystems. ++There is an empty directory called F where you can mount ++filesystems. + + To automatically mount the virtual machine's filesystems under + F use the I<-i> option. This uses libguestfs inspection to +-- +2.14.3 + diff --git a/SOURCES/0061-rescue-docs-Note-that-you-can-run-virt-rescue-on-dis.patch b/SOURCES/0061-rescue-docs-Note-that-you-can-run-virt-rescue-on-dis.patch new file mode 100644 index 0000000..bc9eddb --- /dev/null +++ b/SOURCES/0061-rescue-docs-Note-that-you-can-run-virt-rescue-on-dis.patch @@ -0,0 +1,27 @@ +From 2bcdb1d5a81d1591e7de4fa6f2333e99c02b3e5b Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 24 Mar 2017 22:52:02 +0000 +Subject: [PATCH] rescue: docs: Note that you can run virt-rescue on disks too. + +(cherry picked from commit 267569f7ad22ad14d9ef4fa27b038469ae115c45) +--- + rescue/virt-rescue.pod | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/rescue/virt-rescue.pod b/rescue/virt-rescue.pod +index dfa74e204..5cfbd6e1c 100644 +--- a/rescue/virt-rescue.pod ++++ b/rescue/virt-rescue.pod +@@ -69,7 +69,8 @@ Virt-rescue can be used on I disk image file or device, not just + a virtual machine. For example you can use it on a blank file if you + want to partition that file (although we would recommend using + L instead as it is more suitable for this purpose). You +-can even use virt-rescue on things like SD cards. ++can even use virt-rescue on things like USB drives, SD cards and hard ++disks. + + You can get virt-rescue to give you scratch disk(s) to play with. + This is useful for testing out Linux utilities (see I<--scratch>). +-- +2.14.3 + diff --git a/SOURCES/0062-rescue-Don-t-document-suggest-option-in-help-output.patch b/SOURCES/0062-rescue-Don-t-document-suggest-option-in-help-output.patch new file mode 100644 index 0000000..099b02e --- /dev/null +++ b/SOURCES/0062-rescue-Don-t-document-suggest-option-in-help-output.patch @@ -0,0 +1,41 @@ +From b8e5d0c7c03f7b96d6a60c505d227d9de3ba582d Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 25 Mar 2017 23:34:09 +0000 +Subject: [PATCH] rescue: Don't document --suggest option in --help output. + +Also fix the docs test to ignore it. + +Updates/fixes commit 33d2ae796119ae5dd38e2afcbf1ba4216bd99846. + +(cherry picked from commit aa7b7e26c3aa434f2b299055df63c52fb3a2f93f) +--- + rescue/rescue.c | 1 - + rescue/test-virt-rescue-docs.sh | 3 ++- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/rescue/rescue.c b/rescue/rescue.c +index a1aac53e4..6f9dcd733 100644 +--- a/rescue/rescue.c ++++ b/rescue/rescue.c +@@ -101,7 +101,6 @@ usage (int status) + " --scratch[=N] Add scratch disk(s)\n" + " --selinux For backwards compat only, does nothing\n" + " --smp N Enable SMP with N >= 2 virtual CPUs\n" +- " --suggest Suggest mount commands for this guest\n" + " -v|--verbose Verbose messages\n" + " -V|--version Display version and exit\n" + " -w|--rw Mount read-write\n" +diff --git a/rescue/test-virt-rescue-docs.sh b/rescue/test-virt-rescue-docs.sh +index 25f8f6095..e5fbf26f4 100755 +--- a/rescue/test-virt-rescue-docs.sh ++++ b/rescue/test-virt-rescue-docs.sh +@@ -21,4 +21,5 @@ set -e + $TEST_FUNCTIONS + skip_if_skipped + +-$top_srcdir/podcheck.pl virt-rescue.pod virt-rescue ++$top_srcdir/podcheck.pl virt-rescue.pod virt-rescue \ ++ --ignore=--suggest +-- +2.14.3 + diff --git a/SOURCES/0063-v2v-bootloaders-search-grub-config-for-all-distribut.patch b/SOURCES/0063-v2v-bootloaders-search-grub-config-for-all-distribut.patch new file mode 100644 index 0000000..22dfee6 --- /dev/null +++ b/SOURCES/0063-v2v-bootloaders-search-grub-config-for-all-distribut.patch @@ -0,0 +1,119 @@ +From 54c42d18d82ae4c5c0562600b47a7710a583ea07 Mon Sep 17 00:00:00 2001 +From: Pavel Butsykin +Date: Tue, 2 May 2017 15:35:06 +0300 +Subject: [PATCH] v2v: bootloaders: search grub config for all distributions + +This patch improves the search of grub config on EFI partition. This +means that the config will be found not only for rhel but also for +many other distributions. Tests were performed on the following +distributions: centos, fedora, ubuntu, suse. In all cases, the config +path was /boot/efi/EFI/*distname*/grub.cfg + +The main purpose of the patch is to improve support for converting of +vm with UEFI for most distributions. Unfortunately this patch does not +solve the problem for all distributions, for example Debian does not +store grub config on the EFI partition, therefore for such +distributions another solution is necessary. + +Signed-off-by: Pavel Butsykin +(cherry picked from commit a76e9040b20f97eb5c9accbefcbf55999554dc48) +--- + v2v/linux_bootloaders.ml | 76 ++++++++++++++++++++++++++++++------------------ + 1 file changed, 48 insertions(+), 28 deletions(-) + +diff --git a/v2v/linux_bootloaders.ml b/v2v/linux_bootloaders.ml +index c3fd09ca8..25dab02fe 100644 +--- a/v2v/linux_bootloaders.ml ++++ b/v2v/linux_bootloaders.ml +@@ -49,6 +49,13 @@ let remove_hd_prefix path = + + (* Grub1 (AKA grub-legacy) representation. *) + class bootloader_grub1 (g : G.guestfs) inspect grub_config = ++ let () = ++ (* Apply the "grub" lens if it is not handling the file ++ * already -- Augeas < 1.7.0 will error out otherwise. ++ *) ++ if g#aug_ls ("/files" ^ grub_config) = [||] then ++ g#aug_transform "grub" grub_config in ++ + (* Grub prefix? Usually "/boot". *) + let grub_prefix = + let mounts = g#inspect_get_mountpoints inspect.i_root in +@@ -345,33 +352,46 @@ object (self) + end + + let detect_bootloader (g : G.guestfs) inspect = +- let config_file, typ = +- let locations = [ +- "/boot/grub2/grub.cfg", Grub2; +- "/boot/grub/grub.cfg", Grub2; +- "/boot/grub/menu.lst", Grub1; +- "/boot/grub/grub.conf", Grub1; +- ] in +- let locations = +- match inspect.i_firmware with +- | I_UEFI _ -> +- [ +- "/boot/efi/EFI/redhat/grub.cfg", Grub2; +- "/boot/efi/EFI/redhat/grub.conf", Grub1; +- ] @ locations +- | I_BIOS -> locations in +- try +- List.find ( +- fun (config_file, _) -> g#is_file ~followsymlinks:true config_file +- ) locations +- with +- Not_found -> +- error (f_"no bootloader detected") in ++ (* Where to start searching for bootloaders. *) ++ let mp = ++ match inspect.i_firmware with ++ | I_BIOS -> "/boot" ++ | I_UEFI _ -> "/boot/efi/EFI" in + +- match typ with +- | Grub1 -> +- if config_file = "/boot/efi/EFI/redhat/grub.conf" then +- g#aug_transform "grub" "/boot/efi/EFI/redhat/grub.conf"; ++ (* Find all paths below the mountpoint, then filter them to find ++ * the grub config file. ++ *) ++ let paths = ++ try List.map ((^) mp) (Array.to_list (g#find mp)) ++ with G.Error msg -> ++ error (f_"could not find bootloader mount point (%s): %s") mp msg in + +- new bootloader_grub1 g inspect config_file +- | Grub2 -> new bootloader_grub2 g config_file ++ (* We can determine if the bootloader config file is grub 1 or ++ * grub 2 just by looking at the filename. ++ *) ++ let bootloader_type_of_filename path = ++ match last_part_of path '/' with ++ | Some "grub.cfg" -> Some Grub2 ++ | Some ("grub.conf" | "menu.lst") -> Some Grub1 ++ | Some _ ++ | None -> None ++ in ++ ++ let grub_config, typ = ++ let rec loop = function ++ | [] -> error (f_"no bootloader detected") ++ | path :: paths -> ++ match bootloader_type_of_filename path with ++ | None -> loop paths ++ | Some typ -> ++ if not (g#is_file ~followsymlinks:true path) then loop paths ++ else path, typ ++ in ++ loop paths in ++ ++ let bl = ++ (match typ with ++ | Grub1 -> new bootloader_grub1 g inspect grub_config ++ | Grub2 -> new bootloader_grub2 g grub_config) in ++ debug "detected bootloader %s at %s" bl#name grub_config; ++ bl +-- +2.14.3 + diff --git a/SOURCES/0064-rescue-fix-size-check.patch b/SOURCES/0064-rescue-fix-size-check.patch new file mode 100644 index 0000000..94e3233 --- /dev/null +++ b/SOURCES/0064-rescue-fix-size-check.patch @@ -0,0 +1,30 @@ +From ab6cefa227e23008eda69f8e7390d2eaed376d5c Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Mon, 23 Oct 2017 17:42:03 +0200 +Subject: [PATCH] rescue: fix size check + +Compare it to the right variable, not to the pointer itself. + +Fixes commit 3637c42f4e521eb647d7dfae7f48eb1689d0af54. + +(cherry picked from commit 0998e3f1cdf9eb441ea1f45e45860feac47fccd8) +--- + rescue/escape.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/rescue/escape.c b/rescue/escape.c +index f7f7d84c4..d6dc9d329 100644 +--- a/rescue/escape.c ++++ b/rescue/escape.c +@@ -49,7 +49,7 @@ parse_escape_key (const char *arg) + return 0; + + len = strlen (arg); +- if (arg == 0) ++ if (len == 0) + return -1; + + switch (arg[0]) { +-- +2.14.3 + diff --git a/SOURCES/0065-rescue-initialize-CLEANUP-pointer-variable.patch b/SOURCES/0065-rescue-initialize-CLEANUP-pointer-variable.patch new file mode 100644 index 0000000..2d24a3e --- /dev/null +++ b/SOURCES/0065-rescue-initialize-CLEANUP-pointer-variable.patch @@ -0,0 +1,31 @@ +From d4d3e90ad9c9e144171ece825f60cb804449f835 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Mon, 23 Oct 2017 17:44:23 +0200 +Subject: [PATCH] rescue: initialize CLEANUP pointer variable + +This way it will not try to free uninitialized memory when going out of +scope, and the inspector mode is not enabled. + +Fixes commit 3637c42f4e521eb647d7dfae7f48eb1689d0af54. + +(cherry picked from commit 0942241395b7faf02fd651a0d7b99628458febe4) +--- + rescue/escape.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/rescue/escape.c b/rescue/escape.c +index d6dc9d329..ae4919f69 100644 +--- a/rescue/escape.c ++++ b/rescue/escape.c +@@ -236,7 +236,7 @@ print_help (void) + static void + print_inspector (void) + { +- CLEANUP_FREE_STRING_LIST char **roots; ++ CLEANUP_FREE_STRING_LIST char **roots = NULL; + size_t i; + const char *root; + char *str; +-- +2.14.3 + diff --git a/SOURCES/0066-v2v-i-ova-parse-MAC-address-from-rasd-Address-RHBZ-1.patch b/SOURCES/0066-v2v-i-ova-parse-MAC-address-from-rasd-Address-RHBZ-1.patch new file mode 100644 index 0000000..d1dc45f --- /dev/null +++ b/SOURCES/0066-v2v-i-ova-parse-MAC-address-from-rasd-Address-RHBZ-1.patch @@ -0,0 +1,32 @@ +From 0ce5239605cf455e4891224b6594f33f24b7bd9a Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Thu, 2 Nov 2017 11:13:42 +0100 +Subject: [PATCH] v2v: -i ova: parse MAC address from + (RHBZ#1506572) + +Read the MAC address of the network interfaces from the +tag of the OVF. This seems to be one of the possible ways used in OVFs. + +(cherry picked from commit a1b008e2d138a90cbf2147d69d5d2d4d745b03cd) +--- + v2v/parse_ovf_from_ova.ml | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/v2v/parse_ovf_from_ova.ml b/v2v/parse_ovf_from_ova.ml +index 989483e2e..dba0ce585 100644 +--- a/v2v/parse_ovf_from_ova.ml ++++ b/v2v/parse_ovf_from_ova.ml +@@ -211,8 +211,9 @@ let parse_ovf_from_ova ovf_filename = + Xml.xpathctx_set_current_context xpathctx n; + let vnet = + xpath_string_default "rasd:ElementName/text()" (sprintf"eth%d" i) in ++ let mac = xpath_string "rasd:Address/text()" in + let nic = { +- s_mac = None; ++ s_mac = mac; + s_nic_model = None; + s_vnet = vnet; + s_vnet_orig = vnet; +-- +2.14.3 + diff --git a/SOURCES/0067-v2v-Fix-RPM-file-owned-test-RHBZ-1503958.patch b/SOURCES/0067-v2v-Fix-RPM-file-owned-test-RHBZ-1503958.patch new file mode 100644 index 0000000..7a63e5e --- /dev/null +++ b/SOURCES/0067-v2v-Fix-RPM-file-owned-test-RHBZ-1503958.patch @@ -0,0 +1,126 @@ +From 35372c4b210bc49969bf96e7a17897ec29ba4625 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 19 Oct 2017 12:05:43 +0100 +Subject: [PATCH] v2v: Fix RPM file owned test (RHBZ#1503958). + +Linux.file_owner is not used by any other function, so remove it. + +Linux.is_file_owned is only used when removing kmod-xenpv on old RHEL +releases, and so is only required to work for RPM. + +The old file_owner/is_file_owned functions were completely broken for +the RPM case. This replaces them with a simpler, working +implementation of is_file_owned only. + +Thanks: Ming Xie for finding and reporting the original bug. +(cherry picked from commit e6bc59a7d46707f5037afc8a73206d2773c3fccd) +--- + v2v/linux.ml | 61 ++++++++++++++++++++++++++--------------------------------- + v2v/linux.mli | 3 --- + 2 files changed, 27 insertions(+), 37 deletions(-) + +diff --git a/v2v/linux.ml b/v2v/linux.ml +index fad9b0c61..11b0e2cbf 100644 +--- a/v2v/linux.ml ++++ b/v2v/linux.ml +@@ -98,7 +98,7 @@ let file_list_of_package (g : Guestfs.guestfs) inspect app = + error (f_"don't know how to get list of files from package using %s") + format + +-let rec file_owner (g : G.guestfs) { i_package_format = package_format } path = ++let is_file_owned (g : G.guestfs) { i_package_format = package_format } path = + match package_format with + | "deb" -> + (* With dpkg usually the directories are owned by all the packages +@@ -108,48 +108,41 @@ let rec file_owner (g : G.guestfs) { i_package_format = package_format } path = + *) + let cmd = [| "dpkg"; "-S"; path |] in + debug "%s" (String.concat " " (Array.to_list cmd)); +- let lines = +- try g#command_lines cmd +- with Guestfs.Error msg as exn -> +- if String.find msg "no path found matching pattern" >= 0 then +- raise Not_found +- else +- raise exn in +- if Array.length lines = 0 then +- error (f_"internal error: file_owner: dpkg command returned no output"); +- let line = lines.(0) in +- let line = +- try String.sub line 0 (String.rindex line ':') +- with Invalid_argument _ -> +- error (f_"internal error: file_owner: invalid dpkg output: '%s'") +- line in +- fst (String.split "," line) +- +- | "rpm" -> +- (* Although it is possible in RPM for multiple packages to own +- * a file, this deliberately only returns one package. +- *) +- let cmd = [| "rpm"; "-qf"; "--qf"; "%{NAME}\\n"; path |] in +- debug "%s" (String.concat " " (Array.to_list cmd)); + (try +- let pkgs = g#command_lines cmd in +- pkgs.(0) ++ let lines = g#command_lines cmd in ++ if Array.length lines = 0 then ++ error (f_"internal error: is_file_owned: dpkg command returned no output"); ++ (* Just check the output looks something like "pkg: filename". *) ++ if String.find lines.(0) ": " >= 0 then ++ true ++ else ++ error (f_"internal error: is_file_owned: unexpected output from dpkg command: %s") ++ lines.(0) + with Guestfs.Error msg as exn -> +- if String.find msg "is not owned" >= 0 then +- raise Not_found ++ if String.find msg "no path found matching pattern" >= 0 then ++ false + else + raise exn +- | Invalid_argument _ (* pkgs.(0) raises index out of bounds *) -> +- error (f_"internal error: file_owner: rpm command returned no output") + ) + ++ | "rpm" -> ++ (* Run rpm -qf and print a magic string if the file is owned. ++ * If not owned, rpm will print "... is not owned by any package" ++ * and exit with an error. Unfortunately the string is sent to ++ * stdout, so here we ignore the exit status of rpm and just ++ * look for one of the two strings. ++ *) ++ let magic = "FILE_OWNED_TEST" in ++ let cmd = sprintf "rpm -qf --qf %s %s 2>&1 ||:" ++ (quote (magic ^ "\n")) (quote path) in ++ let r = g#sh cmd in ++ if String.find r magic >= 0 then true ++ else if String.find r "is not owned" >= 0 then false ++ else failwithf "RPM file owned test failed: %s" r ++ + | format -> + error (f_"don't know how to find file owner using %s") format + +-and is_file_owned g inspect path = +- try ignore (file_owner g inspect path); true +- with Not_found -> false +- + let is_package_manager_save_file filename = + (* Recognized suffixes of package managers. *) + let suffixes = [ ".dpkg-old"; ".dpkg-new"; ".rpmsave"; ".rpmnew"; ] in +diff --git a/v2v/linux.mli b/v2v/linux.mli +index 705073644..08146a460 100644 +--- a/v2v/linux.mli ++++ b/v2v/linux.mli +@@ -29,9 +29,6 @@ val remove : Guestfs.guestfs -> Types.inspect -> string list -> unit + val file_list_of_package : Guestfs.guestfs -> Types.inspect -> Guestfs.application2 -> string list + (** Return list of files owned by package. *) + +-val file_owner : Guestfs.guestfs -> Types.inspect -> string -> string +-(** Return the name of the package that owns a file. *) +- + val is_file_owned : Guestfs.guestfs -> Types.inspect -> string -> bool + (** Returns true if the file is owned by an installed package. *) + +-- +2.14.3 + diff --git a/SOURCES/0068-v2v-bootloaders-handle-no-default-grubby-kernel-RHBZ.patch b/SOURCES/0068-v2v-bootloaders-handle-no-default-grubby-kernel-RHBZ.patch new file mode 100644 index 0000000..28de6f3 --- /dev/null +++ b/SOURCES/0068-v2v-bootloaders-handle-no-default-grubby-kernel-RHBZ.patch @@ -0,0 +1,37 @@ +From 67b740a77543bc0f0c6b4d0f52c8855b8705822b Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Fri, 1 Dec 2017 14:46:13 +0100 +Subject: [PATCH] v2v: bootloaders: handle no default grubby kernel + (RHBZ#1519204) + +When using grubby to get the default kernel of a guest, do not fail +with a bogus error like: + +virt-v2v: error: libguestfs error: statns: statns_stub: path must start +with a / character + +in case there is no default kernel that can be determined (e.g. because +of a bogus configuration). +--- + v2v/linux_bootloaders.ml | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/v2v/linux_bootloaders.ml b/v2v/linux_bootloaders.ml +index 25dab02fe..e241d93c2 100644 +--- a/v2v/linux_bootloaders.ml ++++ b/v2v/linux_bootloaders.ml +@@ -281,7 +281,10 @@ object (self) + let res = + match get_default_method with + | MethodGrubby -> +- Some (g#command [| "grubby"; "--default-kernel" |]) ++ let res = g#command [| "grubby"; "--default-kernel" |] in ++ (match res with ++ | "" -> None ++ | _ -> Some res) + | MethodPerlBootloader -> + let cmd = + [| "/usr/bin/perl"; "-MBootloader::Tools"; "-e"; " +-- +2.14.3 + diff --git a/SOURCES/0069-lib-libvirt-stop-using-shareable-for-appliance-disk-.patch b/SOURCES/0069-lib-libvirt-stop-using-shareable-for-appliance-disk-.patch new file mode 100644 index 0000000..b39b9fe --- /dev/null +++ b/SOURCES/0069-lib-libvirt-stop-using-shareable-for-appliance-disk-.patch @@ -0,0 +1,47 @@ +From db196dc098d213638d7513bb98a72d1778658299 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Tue, 5 Dec 2017 15:36:34 +0100 +Subject: [PATCH] lib: libvirt: stop using for appliance disk + (RHBZ#1518517) + +Commit aa9e0057b19e29f76c9a81f9aebeeb1cb5bf1fdb made the libvirt backend +use for the disk of the appliance, since at that time all +the instances were using the disk directly. +OTOH, commit 3ad44c866042919374e2d840502e53da2ed8aef0 switched to +overlays for read-only disks, including the appliance, so effectively +protecting the appliance. + +Because of this, the libvirt backend does not need anymore. + +Thanks to: Daniel Berrange, Richard W.M. Jones, Peter Krempa. +--- + lib/launch-libvirt.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c +index d10c7cb40..05c398ba0 100644 +--- a/lib/launch-libvirt.c ++++ b/lib/launch-libvirt.c +@@ -969,10 +969,6 @@ static int construct_libvirt_xml_appliance (guestfs_h *g, const struct libvirt_x + } \ + } while (0) + +-/* */ +-#define empty_element(element) \ +- do { start_element(element) {} end_element (); } while (0) +- + /* key=value attribute of the current element. */ + #define attribute(key,value) \ + if (xmlTextWriterWriteAttribute (xo, BAD_CAST (key), BAD_CAST (value)) == -1){ \ +@@ -1758,8 +1754,6 @@ construct_libvirt_xml_appliance (guestfs_h *g, + == -1) + return -1; + +- empty_element ("shareable"); +- + } end_element (); + + return 0; +-- +2.14.3 + diff --git a/SOURCES/0070-v2v-vddk-Make-it-clearer-that-you-should-not-run-nbd.patch b/SOURCES/0070-v2v-vddk-Make-it-clearer-that-you-should-not-run-nbd.patch new file mode 100644 index 0000000..edc2498 --- /dev/null +++ b/SOURCES/0070-v2v-vddk-Make-it-clearer-that-you-should-not-run-nbd.patch @@ -0,0 +1,35 @@ +From be3d03e538592cff01d3e3693ada6e973df55abd Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 16 Oct 2017 10:06:54 +0100 +Subject: [PATCH] v2v: vddk: Make it clearer that you should not run nbdkit + 'make install'. + +(cherry picked from commit d81a2ee185599c23a128ab65be9d48b415abf461) +--- + v2v/virt-v2v.pod | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index 92ed147d7..4f7ea8da6 100644 +--- a/v2v/virt-v2v.pod ++++ b/v2v/virt-v2v.pod +@@ -1322,11 +1322,12 @@ L + + =item 3. + +-You can run nbdkit from its source directory without needing to +-install it. Set C<$PATH> to include the nbdkit top build directory +-(the directory containing a shell script called F): ++You do B need to run C. You can run nbdkit from ++its source directory. Set C<$PATH> to point to the nbdkit top build ++directory (that is, the directory containing a shell script called ++F), eg: + +- export PATH=/path/to/nbdkit:$PATH ++ export PATH=/path/to/nbdkit-1.1.x:$PATH + + =item 4. + +-- +2.14.3 + diff --git a/SOURCES/0071-podwrapper-nbdkit-man-pages-are-libguestfs-man-pages.patch b/SOURCES/0071-podwrapper-nbdkit-man-pages-are-libguestfs-man-pages.patch new file mode 100644 index 0000000..dac42e3 --- /dev/null +++ b/SOURCES/0071-podwrapper-nbdkit-man-pages-are-libguestfs-man-pages.patch @@ -0,0 +1,28 @@ +From 6b6ab3bf31cbca8e4920315bbd46badf6d532529 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 7 Nov 2017 10:03:54 +0000 +Subject: [PATCH] podwrapper: nbdkit-* man pages are libguestfs man pages. + +Don't use the external link for these. + +Thanks: Ming Xie. +(cherry picked from commit 441fa82ee0d878ed63b1c213d8197c1f0ffde2a0) +--- + podwrapper.pl.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/podwrapper.pl.in b/podwrapper.pl.in +index 619d3af2b..9b90d0faa 100755 +--- a/podwrapper.pl.in ++++ b/podwrapper.pl.in +@@ -552,6 +552,7 @@ SUBHTML: { + return 1 if /^guestunmount/; + return 1 if /^hivex/; + return 1 if /^supermin/; ++ return 1 if /^nbdkit/; + return 0; + } + +-- +2.14.3 + diff --git a/SOURCES/0072-v2v-vddk-Update-minimum-version-of-nbdkit-to-1.1.16.patch b/SOURCES/0072-v2v-vddk-Update-minimum-version-of-nbdkit-to-1.1.16.patch new file mode 100644 index 0000000..dbeaedb --- /dev/null +++ b/SOURCES/0072-v2v-vddk-Update-minimum-version-of-nbdkit-to-1.1.16.patch @@ -0,0 +1,56 @@ +From f49162600c5ed54341ebeba9bc773fefc6b8153d Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 7 Nov 2017 10:07:03 +0000 +Subject: [PATCH] v2v: vddk: Update minimum version of nbdkit to 1.1.16. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +While 1.1.14 will technically still work, 1.1.16 adds the +‘selinux=yes|no’ flag to ‘--dump-config’ output. It's also the more +widely available and tested version at the time of writing. + +Thanks: Ming Xie. +(cherry picked from commit 415e9d82e901647438f68e4748720d88153778aa) +--- + v2v/input_libvirt_vddk.ml | 5 +++-- + v2v/virt-v2v.pod | 2 +- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml +index 33b34bd2e..d1f2ae360 100644 +--- a/v2v/input_libvirt_vddk.ml ++++ b/v2v/input_libvirt_vddk.ml +@@ -61,13 +61,14 @@ class input_libvirt_vddk vddk_options password libvirt_uri parsed_uri guest = + + (* Check it's a new enough version. The latest features we + * require are ‘--exit-with-parent’ and ‘--selinux-label’, both +- * added in 1.1.14. ++ * added in 1.1.14. (We use 1.1.16 as the minimum here because ++ * it also adds the selinux=yes|no flag in --dump-config). + *) + let lines = external_command "nbdkit --help" in + let lines = String.concat " " lines in + if String.find lines "exit-with-parent" == -1 || + String.find lines "selinux-label" == -1 then +- error (f_"nbdkit is not new enough, you need to upgrade to nbdkit ≥ 1.1.14") ++ error (f_"nbdkit is not new enough, you need to upgrade to nbdkit ≥ 1.1.16") + in + + (* Check that the VDDK plugin is installed and working *) +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index 4f7ea8da6..48a20cccc 100644 +--- a/v2v/virt-v2v.pod ++++ b/v2v/virt-v2v.pod +@@ -1305,7 +1305,7 @@ library is permitted by the license. + =item 2. + + You must also compile nbdkit, enabling the VDDK plugin. At least +-nbdkit E 1.1.14 is required, but it is usually best to compile ++nbdkit E 1.1.16 is required, but it is usually best to compile + from the git tree. + + =over 4 +-- +2.14.3 + diff --git a/SOURCES/0073-v2v-vddk-Further-rework-documentation.patch b/SOURCES/0073-v2v-vddk-Further-rework-documentation.patch new file mode 100644 index 0000000..731cdb8 --- /dev/null +++ b/SOURCES/0073-v2v-vddk-Further-rework-documentation.patch @@ -0,0 +1,59 @@ +From 9e64238a389264b34af20b49da929d5bf6ccd436 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 7 Nov 2017 11:32:16 +0000 +Subject: [PATCH] v2v: vddk: Further rework documentation. + +Thanks for suggestions from Ming Xie. + +(cherry picked from commit 12d87361a4623587c53196e70157448158c02c7f) +--- + v2v/virt-v2v.pod | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index 48a20cccc..417c25331 100644 +--- a/v2v/virt-v2v.pod ++++ b/v2v/virt-v2v.pod +@@ -1304,6 +1304,10 @@ library is permitted by the license. + + =item 2. + ++VDDK E 6.5 is required. ++ ++=item 3. ++ + You must also compile nbdkit, enabling the VDDK plugin. At least + nbdkit E 1.1.16 is required, but it is usually best to compile + from the git tree. +@@ -1320,12 +1324,14 @@ L + + =back + +-=item 3. ++Compile nbdkit as described in the sources (see link above). + +-You do B need to run C. You can run nbdkit from +-its source directory. Set C<$PATH> to point to the nbdkit top build +-directory (that is, the directory containing a shell script called +-F), eg: ++You do B need to run C because you can run nbdkit ++from its source directory. The source directory has a shell script ++called F which runs the locally built copy of nbdkit and its ++plugins. So set C<$PATH> to point to the nbdkit top build directory ++(that is, the directory containing the shell script called F), ++eg: + + export PATH=/path/to/nbdkit-1.1.x:$PATH + +@@ -1333,7 +1339,7 @@ F), eg: + + You must find the SSL "thumbprint" of your VMware server. How to do + this is explained in L, also available at the +-link given in item 2 above. ++link above. + + =item 5. + +-- +2.14.3 + diff --git a/SOURCES/0074-v2v-docs-Remove-min-version-of-VDDK-recommend-nbdkit.patch b/SOURCES/0074-v2v-docs-Remove-min-version-of-VDDK-recommend-nbdkit.patch new file mode 100644 index 0000000..1fae654 --- /dev/null +++ b/SOURCES/0074-v2v-docs-Remove-min-version-of-VDDK-recommend-nbdkit.patch @@ -0,0 +1,57 @@ +From 5b64c3085942856f520823c12c871a4d96b75e35 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 6 Dec 2017 15:48:50 +0000 +Subject: [PATCH] v2v: docs: Remove min version of VDDK, recommend nbdkit >= + 1.1.25 (RHBZ#1513884). + +Requires -> recommends because older versions of nbdkit will likely +work also. + +See also: +https://bugzilla.redhat.com/show_bug.cgi?id=1513884#c3 + +(cherry picked from commit 5ac24b490ebcf2e16e4ee2284a7f59bcc47cc808) +--- + v2v/virt-v2v.pod | 14 +++++--------- + 1 file changed, 5 insertions(+), 9 deletions(-) + +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index 417c25331..13f021c6d 100644 +--- a/v2v/virt-v2v.pod ++++ b/v2v/virt-v2v.pod +@@ -1304,13 +1304,9 @@ library is permitted by the license. + + =item 2. + +-VDDK E 6.5 is required. +- +-=item 3. +- +-You must also compile nbdkit, enabling the VDDK plugin. At least +-nbdkit E 1.1.16 is required, but it is usually best to compile +-from the git tree. ++You must also compile nbdkit, enabling the VDDK plugin. nbdkit E ++1.1.25 is recommended, but it is usually best to compile from the git ++tree. + + =over 4 + +@@ -1335,13 +1331,13 @@ eg: + + export PATH=/path/to/nbdkit-1.1.x:$PATH + +-=item 4. ++=item 3. + + You must find the SSL "thumbprint" of your VMware server. How to do + this is explained in L, also available at the + link above. + +-=item 5. ++=item 4. + + VDDK imports require a feature added in libvirt E 3.7. + +-- +2.14.3 + diff --git a/SOURCES/0075-v2v-docs-State-that-vddk-thumbprint-is-only-required.patch b/SOURCES/0075-v2v-docs-State-that-vddk-thumbprint-is-only-required.patch new file mode 100644 index 0000000..3cd9e53 --- /dev/null +++ b/SOURCES/0075-v2v-docs-State-that-vddk-thumbprint-is-only-required.patch @@ -0,0 +1,33 @@ +From 8e556500316c8e53993f50fe9ecb56d9524f5cab Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 6 Dec 2017 15:53:41 +0000 +Subject: [PATCH] v2v: docs: State that --vddk-thumbprint is only required if + --vddk present (RHBZ#1513884). + +Thanks: Ming Xie, Pino Toscano. + +See also: +https://bugzilla.redhat.com/show_bug.cgi?id=1513884#c2 + +(cherry picked from commit 4b43697f9bc9b0fa33e26fbc2fce136ebaa89005) +--- + v2v/virt-v2v.pod | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index 13f021c6d..e798ad1e7 100644 +--- a/v2v/virt-v2v.pod ++++ b/v2v/virt-v2v.pod +@@ -528,7 +528,8 @@ See L below for details. + + When using VDDK mode, these options are passed unmodified to the + L VDDK plugin. Please refer to L. +-Only I<--vddk-thumbprint> is required, the others are optional. ++If I<--vddk> is present, I<--vddk-thumbprint> is also required, ++the rest are optional. + + =item B<--vdsm-compat=0.10> + +-- +2.14.3 + diff --git a/SOURCES/0076-v2v-vddk-Switch-to-using-it-vddk-to-specify-VDDK-as-.patch b/SOURCES/0076-v2v-vddk-Switch-to-using-it-vddk-to-specify-VDDK-as-.patch new file mode 100644 index 0000000..a437475 --- /dev/null +++ b/SOURCES/0076-v2v-vddk-Switch-to-using-it-vddk-to-specify-VDDK-as-.patch @@ -0,0 +1,518 @@ +From f8209cc000c28648efd4d73eeeec7bac3dd7c1dd Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 7 Dec 2017 14:41:32 +0000 +Subject: [PATCH] =?UTF-8?q?v2v:=20vddk:=20Switch=20to=20using=20=E2=80=98-?= + =?UTF-8?q?it=20vddk=E2=80=99=20to=20specify=20VDDK=20as=20input=20transpo?= + =?UTF-8?q?rt.?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Previously the presence of the ‘--vddk ’ option magically +enabled VDDK mode. However we want to introduce other transports for +VMware conversions so this wasn't a very clean choice. + +With this commit you must use ‘-it vddk’ to specify that you want VDDK +as a disk transport. The previous ‘--vddk ’ option has been +renamed to ‘--vddk-libdir ’ to be consistent with the other +passthrough options, and it is no longer required. + +A new command line looks like: + + $ export PATH=/path/to/nbdkit:$PATH + $ virt-v2v \ + -ic 'vpx://root@vcenter.example.com/Datacenter/esxi?no_verify=1' \ +| -it vddk \ +| --vddk-libdir /path/to/vmware-vix-disklib-distrib \ + --vddk-thumbprint xx:xx:xx:... \ + "Windows 2003" \ + -o local -os /var/tmp + +where only the two lines marked with ‘|’ have changed. + +(cherry picked from commit 6f347b4f802717d4557fdae90c90afa030b8a414) +--- + v2v/cmdline.ml | 69 +++++++++++++++++++++++++++++------------------ + v2v/input_libvirt.ml | 37 ++++++++++++------------- + v2v/input_libvirt.mli | 8 +++--- + v2v/input_libvirt_vddk.ml | 61 ++++++++++++++++++++++++++++------------- + v2v/test-v2v-docs.sh | 2 +- + v2v/types.ml | 2 +- + v2v/types.mli | 2 +- + v2v/virt-v2v.pod | 30 +++++++++++++++------ + 8 files changed, 131 insertions(+), 80 deletions(-) + +diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml +index dfbb776ab..81562d1f5 100644 +--- a/v2v/cmdline.ml ++++ b/v2v/cmdline.ml +@@ -56,15 +56,16 @@ let parse_cmdline () = + + let input_conn = ref None in + let input_format = ref None in ++ let input_transport = ref None in + let in_place = ref false in + let output_conn = ref None in + let output_format = ref None in + let output_name = ref None in + let output_storage = ref None in + let password_file = ref None in +- let vddk = ref None in + let vddk_config = ref None in + let vddk_cookie = ref None in ++ let vddk_libdir = ref None in + let vddk_nfchostport = ref None in + let vddk_port = ref None in + let vddk_snapshot = ref None in +@@ -186,6 +187,8 @@ let parse_cmdline () = + s_"Libvirt URI"; + [ M"if" ], Getopt.String ("format", set_string_option_once "-if" input_format), + s_"Input format (for -i disk)"; ++ [ M"it" ], Getopt.String ("transport", set_string_option_once "-it" input_transport), ++ s_"Input transport"; + [ L"in-place" ], Getopt.Set in_place, ""; + [ L"machine-readable" ], Getopt.Set machine_readable, s_"Make output machine readable"; + [ S 'n'; L"network" ], Getopt.String ("in:out", add_network), s_"Map network 'in' to 'out'"; +@@ -207,12 +210,12 @@ let parse_cmdline () = + s_"Use password from file"; + [ L"print-source" ], Getopt.Set print_source, s_"Print source and stop"; + [ L"root" ], Getopt.String ("ask|... ", set_root_choice), s_"How to choose root filesystem"; +- [ L"vddk" ], Getopt.String ("libpath", set_string_option_once "--vddk" vddk), +- s_"Use nbdkit VDDK plugin"; + [ L"vddk-config" ], Getopt.String ("filename", set_string_option_once "--vddk-config" vddk_config), + s_"Set VDDK config file"; + [ L"vddk-cookie" ], Getopt.String ("cookie", set_string_option_once "--vddk-cookie" vddk_cookie), + s_"Set VDDK cookie"; ++ [ L"vddk-libdir" ], Getopt.String ("libdir", set_string_option_once "--vddk-libdir" vddk_libdir), ++ s_"Set VDDK library parent directory"; + [ L"vddk-nfchostport" ], Getopt.String ("nfchostport", set_string_option_once "--vddk-nfchostport" vddk_nfchostport), + s_"Set VDDK nfchostport"; + [ L"vddk-port" ], Getopt.String ("port", set_string_option_once "--vddk-port" vddk_port), +@@ -270,6 +273,12 @@ read the man page virt-v2v(1). + let input_conn = !input_conn in + let input_format = !input_format in + let input_mode = !input_mode in ++ let input_transport = ++ match !input_transport with ++ | None -> None ++ | Some "vddk" -> Some `VDDK ++ | Some transport -> ++ error (f_"unknown input transport ‘-it %s’") transport in + let in_place = !in_place in + let machine_readable = !machine_readable in + let network_map = !network_map in +@@ -287,28 +296,15 @@ read the man page virt-v2v(1). + let qemu_boot = !qemu_boot in + let root_choice = !root_choice in + let vddk_options = +- match !vddk with +- | Some libdir -> +- Some { vddk_libdir = libdir; +- vddk_config = !vddk_config; +- vddk_cookie = !vddk_cookie; +- vddk_nfchostport = !vddk_nfchostport; +- vddk_port = !vddk_port; +- vddk_snapshot = !vddk_snapshot; +- vddk_thumbprint = !vddk_thumbprint; +- vddk_transports = !vddk_transports; +- vddk_vimapiver = !vddk_vimapiver } +- | None -> +- if !vddk_config <> None || +- !vddk_cookie <> None || +- !vddk_nfchostport <> None || +- !vddk_port <> None || +- !vddk_snapshot <> None || +- !vddk_thumbprint <> None || +- !vddk_transports <> None || +- !vddk_vimapiver <> None then +- error (f_"‘--vddk-*’ options should only be used when conversion via the nbdkit VDDK plugin has been enabled, ie. using ‘--vddk’."); +- None in ++ { vddk_config = !vddk_config; ++ vddk_cookie = !vddk_cookie; ++ vddk_libdir = !vddk_libdir; ++ vddk_nfchostport = !vddk_nfchostport; ++ vddk_port = !vddk_port; ++ vddk_snapshot = !vddk_snapshot; ++ vddk_thumbprint = !vddk_thumbprint; ++ vddk_transports = !vddk_transports; ++ vddk_vimapiver = !vddk_vimapiver } in + let vdsm_compat = !vdsm_compat in + let vdsm_image_uuids = List.rev !vdsm_image_uuids in + let vdsm_vol_uuids = List.rev !vdsm_vol_uuids in +@@ -341,6 +337,26 @@ read the man page virt-v2v(1). + let password = read_first_line_from_file filename in + Some password in + ++ (* Input transport affects whether some parameters should or ++ * should not be used. ++ *) ++ (match input_transport with ++ | None -> ++ if !vddk_config <> None || ++ !vddk_cookie <> None || ++ !vddk_libdir <> None || ++ !vddk_nfchostport <> None || ++ !vddk_port <> None || ++ !vddk_snapshot <> None || ++ !vddk_thumbprint <> None || ++ !vddk_transports <> None || ++ !vddk_vimapiver <> None then ++ error (f_"‘--vddk-*’ options should only be used when conversion via the nbdkit VDDK plugin has been enabled, ie. using ‘-it vddk’.") ++ | Some `VDDK -> ++ if !vddk_thumbprint = None then ++ error (f_"‘--vddk-thumbprint’ is required when using ‘-it vddk’.") ++ ); ++ + (* Parsing of the argument(s) depends on the input mode. *) + let input = + match input_mode with +@@ -363,7 +379,8 @@ read the man page virt-v2v(1). + | [guest] -> guest + | _ -> + error (f_"expecting a libvirt guest name on the command line") in +- Input_libvirt.input_libvirt vddk_options password input_conn guest ++ Input_libvirt.input_libvirt vddk_options password ++ input_conn input_transport guest + + | `LibvirtXML -> + (* -i libvirtxml: Expecting a filename (XML file). *) +diff --git a/v2v/input_libvirt.ml b/v2v/input_libvirt.ml +index f4a8114f0..16006dc0c 100644 +--- a/v2v/input_libvirt.ml ++++ b/v2v/input_libvirt.ml +@@ -27,7 +27,7 @@ open Types + open Utils + + (* Choose the right subclass based on the URI. *) +-let input_libvirt vddk_options password libvirt_uri guest = ++let input_libvirt vddk_options password libvirt_uri input_transport guest = + match libvirt_uri with + | None -> + Input_libvirt_other.input_libvirt_other password libvirt_uri guest +@@ -39,29 +39,26 @@ let input_libvirt vddk_options password libvirt_uri guest = + error (f_"could not parse '-ic %s'. Original error message was: %s") + orig_uri msg in + +- match server, scheme with +- | None, _ +- | Some "", _ (* Not a remote URI. *) ++ match server, scheme, input_transport with ++ | None, _, _ ++ | Some "", _, _ (* Not a remote URI. *) + +- | Some _, None (* No scheme? *) +- | Some _, Some "" -> ++ | Some _, None, _ (* No scheme? *) ++ | Some _, Some "", _ -> + Input_libvirt_other.input_libvirt_other password libvirt_uri guest + +- (* vCenter over https, or +- * vCenter or ESXi using nbdkit vddk plugin +- *) +- | Some server, Some ("esx"|"gsx"|"vpx" as scheme) -> +- (match vddk_options with +- | None -> +- Input_libvirt_vcenter_https.input_libvirt_vcenter_https +- password libvirt_uri parsed_uri scheme server guest +- | Some vddk_options -> +- Input_libvirt_vddk.input_libvirt_vddk vddk_options password +- libvirt_uri parsed_uri guest +- ) ++ (* vCenter over https. *) ++ | Some server, Some ("esx"|"gsx"|"vpx" as scheme), None -> ++ Input_libvirt_vcenter_https.input_libvirt_vcenter_https ++ password libvirt_uri parsed_uri scheme server guest ++ ++ (* vCenter or ESXi using nbdkit vddk plugin *) ++ | Some server, Some ("esx"|"gsx"|"vpx"), Some `VDDK -> ++ Input_libvirt_vddk.input_libvirt_vddk vddk_options password ++ libvirt_uri parsed_uri guest + + (* Xen over SSH *) +- | Some server, Some ("xen+ssh" as scheme) -> ++ | Some server, Some ("xen+ssh" as scheme), _ -> + Input_libvirt_xen_ssh.input_libvirt_xen_ssh + password libvirt_uri parsed_uri scheme server guest + +@@ -71,7 +68,7 @@ let input_libvirt vddk_options password libvirt_uri guest = + *) + + (* Unknown remote scheme. *) +- | Some _, Some _ -> ++ | Some _, Some _, _ -> + warning (f_"no support for remote libvirt connections to '-ic %s'. The conversion may fail when it tries to read the source disks.") + orig_uri; + Input_libvirt_other.input_libvirt_other password libvirt_uri guest +diff --git a/v2v/input_libvirt.mli b/v2v/input_libvirt.mli +index acf2ca417..eb3e48397 100644 +--- a/v2v/input_libvirt.mli ++++ b/v2v/input_libvirt.mli +@@ -18,7 +18,7 @@ + + (** [-i libvirt] source. *) + +-val input_libvirt : Types.vddk_options option -> string option -> string option -> string -> Types.input +-(** [input_libvirt vddk_options password libvirt_uri guest] creates +- and returns a new {!Types.input} object specialized for reading input +- from libvirt sources. *) ++val input_libvirt : Types.vddk_options -> string option -> string option -> [`VDDK] option -> string -> Types.input ++(** [input_libvirt vddk_options password libvirt_uri input_transport guest] ++ creates and returns a new {!Types.input} object specialized for reading ++ input from libvirt sources. *) +diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml +index d1f2ae360..2f2ac4214 100644 +--- a/v2v/input_libvirt_vddk.ml ++++ b/v2v/input_libvirt_vddk.ml +@@ -34,11 +34,19 @@ open Printf + + (* Subclass specialized for handling VMware via nbdkit vddk plugin. *) + class input_libvirt_vddk vddk_options password libvirt_uri parsed_uri guest = +- + (* The VDDK path. *) + let libdir = vddk_options.vddk_libdir in +- (* Compute the LD_LIBRARY_PATH that we must pass to nbdkit. *) +- let library_path = libdir // sprintf "lib%d" Sys.word_size in ++ ++ (* VDDK libraries are located under lib32/ or lib64/ relative to the ++ * libdir. Note this is unrelated to Linux multilib or multiarch. ++ *) ++ let libNN = sprintf "lib%d" Sys.word_size in ++ ++ (* Compute the LD_LIBRARY_PATH that we may have to pass to nbdkit. *) ++ let library_path = ++ match libdir with ++ | None -> None ++ | Some libdir -> Some (libdir // libNN) in + + (* Is SELinux enabled and enforcing on the host? *) + let have_selinux = +@@ -46,18 +54,25 @@ class input_libvirt_vddk vddk_options password libvirt_uri parsed_uri guest = + + (* Check that the VDDK path looks reasonable. *) + let error_unless_vddk_libdir () = +- if not (is_directory libdir) then +- error (f_"‘--vddk %s’ does not point to a directory. See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") libdir; ++ (match libdir with ++ | None -> () ++ | Some libdir -> ++ if not (is_directory libdir) then ++ error (f_"‘--vddk-libdir %s’ does not point to a directory. See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") libdir ++ ); + +- if not (is_directory library_path) then +- error (f_"VDDK library path %s not found or not a directory. See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") +- library_path ++ (match library_path with ++ | None -> () ++ | Some library_path -> ++ if not (is_directory library_path) then ++ error (f_"VDDK library path %s not found or not a directory. See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") library_path ++ ) + in + + (* Check that nbdkit is available and new enough. *) + let error_unless_nbdkit_working () = + if 0 <> Sys.command "nbdkit --version >/dev/null" then +- error (f_"nbdkit is not installed or not working. It is required to use ‘--vddk’. See \"INPUT FROM VDDK\" in the virt-v2v(1) manual."); ++ error (f_"nbdkit is not installed or not working. It is required to use ‘-it vddk’. See \"INPUT FROM VDDK\" in the virt-v2v(1) manual."); + + (* Check it's a new enough version. The latest features we + * require are ‘--exit-with-parent’ and ‘--selinux-label’, both +@@ -73,14 +88,20 @@ class input_libvirt_vddk vddk_options password libvirt_uri parsed_uri guest = + + (* Check that the VDDK plugin is installed and working *) + let error_unless_nbdkit_vddk_working () = ++ let set_ld_library_path = ++ match library_path with ++ | None -> "" ++ | Some library_path -> ++ sprintf "LD_LIBRARY_PATH=%s " (quote library_path) in ++ + let cmd = +- sprintf "LD_LIBRARY_PATH=%s nbdkit vddk --dump-plugin >/dev/null" +- (quote library_path) in ++ sprintf "%snbdkit vddk --dump-plugin >/dev/null" ++ set_ld_library_path in + if Sys.command cmd <> 0 then ( + (* See if we can diagnose why ... *) + let cmd = +- sprintf "LD_LIBRARY_PATH=%s LANG=C nbdkit vddk --dump-plugin 2>&1 | grep -sq libvixDiskLib.so" +- (quote library_path) in ++ sprintf "LANG=C %snbdkit vddk --dump-plugin 2>&1 | grep -sq libvixDiskLib.so" ++ set_ld_library_path in + let needs_library = Sys.command cmd = 0 in + if not needs_library then + error (f_"nbdkit VDDK plugin is not installed or not working. It is required if you want to use VDDK. +@@ -91,9 +112,9 @@ See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") + else + error (f_"nbdkit VDDK plugin is not installed or not working. It is required if you want to use VDDK. + +-It looks like you did not set the right path in the ‘--vddk’ option, or your copy of the VDDK directory is incomplete. There should be a library called ’%s/libvixDiskLib.so.?’. ++It looks like you did not set the right path in the ‘--vddk-libdir’ option, or your copy of the VDDK directory is incomplete. There should be a library called ’/%s/libvixDiskLib.so.?’. + +-See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") library_path ++See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") libNN + ) + in + +@@ -120,6 +141,7 @@ See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") library_path + let vddk_passthrus = + [ "config", (fun { vddk_config } -> vddk_config); + "cookie", (fun { vddk_cookie } -> vddk_cookie); ++ "libdir", (fun { vddk_libdir } -> vddk_libdir); + "nfchostport", (fun { vddk_nfchostport } -> vddk_nfchostport); + "port", (fun { vddk_port } -> vddk_port); + "snapshot", (fun { vddk_snapshot } -> vddk_snapshot); +@@ -140,9 +162,8 @@ object + | Some field -> sprintf " --vddk-%s %s" name field + ) vddk_passthrus + ) in +- sprintf "%s --vddk %s%s" ++ sprintf "%s -it vddk %s" + super#as_options (* superclass prints "-i libvirt etc" *) +- vddk_options.vddk_libdir + pt_options + + method source () = +@@ -249,7 +270,6 @@ object + add_arg (sprintf "user=%s" user); + add_arg password_param; + add_arg (sprintf "vm=moref=%s" moref); +- add_arg (sprintf "libdir=%s" libdir); + + (* The passthrough parameters. *) + List.iter ( +@@ -299,7 +319,10 @@ object + let pid = fork () in + if pid = 0 then ( + (* Child process (nbdkit). *) +- putenv "LD_LIBRARY_PATH" library_path; ++ (match library_path with ++ | None -> () ++ | Some x -> putenv "LD_LIBRARY_PATH" x ++ ); + execvp "nbdkit" args + ); + +diff --git a/v2v/test-v2v-docs.sh b/v2v/test-v2v-docs.sh +index 5e49d5240..c8ca193eb 100755 +--- a/v2v/test-v2v-docs.sh ++++ b/v2v/test-v2v-docs.sh +@@ -22,4 +22,4 @@ $TEST_FUNCTIONS + skip_if_skipped + + $top_srcdir/podcheck.pl virt-v2v.pod virt-v2v \ +- --ignore=--debug-overlay,--ic,--if,--in-place,--no-trim,--oa,--oc,--of,--on,--os,--vmtype ++ --ignore=--debug-overlay,--ic,--if,--in-place,--it,--no-trim,--oa,--oc,--of,--on,--os,--vmtype +diff --git a/v2v/types.ml b/v2v/types.ml +index 4f9205aa0..43bd28804 100644 +--- a/v2v/types.ml ++++ b/v2v/types.ml +@@ -473,9 +473,9 @@ type root_choice = AskRoot | SingleRoot | FirstRoot | RootDev of string + type output_allocation = Sparse | Preallocated + + type vddk_options = { +- vddk_libdir : string; + vddk_config : string option; + vddk_cookie : string option; ++ vddk_libdir : string option; + vddk_nfchostport : string option; + vddk_port : string option; + vddk_snapshot : string option; +diff --git a/v2v/types.mli b/v2v/types.mli +index 087a03702..fd944bebf 100644 +--- a/v2v/types.mli ++++ b/v2v/types.mli +@@ -329,9 +329,9 @@ type output_allocation = Sparse | Preallocated + (** Type of [-oa] (output allocation) option. *) + + type vddk_options = { +- vddk_libdir : string; + vddk_config : string option; + vddk_cookie : string option; ++ vddk_libdir : string option; + vddk_nfchostport : string option; + vddk_port : string option; + vddk_snapshot : string option; +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index e798ad1e7..7aca22b3c 100644 +--- a/v2v/virt-v2v.pod ++++ b/v2v/virt-v2v.pod +@@ -255,6 +255,13 @@ For I<-i disk> only, this specifies the format of the input disk + image. For other input methods you should specify the input + format in the metadata. + ++=item B<-it> B ++ ++Use VMware VDDK as a transport to copy the input disks. See ++L below. If you use this parameter then you may ++need to use other I<--vddk*> options to specify how to connect through ++VDDK. ++ + =item B<--keys-from-stdin> + + Read key or passphrase parameters from stdin. The default is +@@ -501,13 +508,20 @@ boot an operating system from the first VirtIO disk. Specifically, + F must be on the first VirtIO disk, and it cannot chainload an + OS which is not in the first VirtIO disk. + +-=item B<--vddk> LIBDIR ++=item B<--vddk-libdir> LIBDIR + +-Enable VDDK input from VMware vCenter or ESXi. C is the top +-directory of the VDDK library. This directory should I ++Set the VDDK library directory. This directory should I + subdirectories called F, F etc., but do not include + F actually in the parameter. + ++In most cases this parameter is required when using the I<-it vddk> ++(VDDK) transport. See L below for details. ++ ++=item B<--vddk-thumbprint> xx:xx:xx:... ++ ++Set the thumbprint of the remote VMware server. ++ ++This parameter is required when using the I<-it vddk> (VDDK) transport. + See L below for details. + + =item B<--vddk-config> FILENAME +@@ -520,16 +534,13 @@ See L below for details. + + =item B<--vddk-snapshot> SNAPSHOT-MOREF + +-=item B<--vddk-thumbprint> xx:xx:xx:... +- + =item B<--vddk-transports> MODE:MODE:... + + =item B<--vddk-vimapiver> APIVER + + When using VDDK mode, these options are passed unmodified to the + L VDDK plugin. Please refer to L. +-If I<--vddk> is present, I<--vddk-thumbprint> is also required, +-the rest are optional. ++These are all optional. + + =item B<--vdsm-compat=0.10> + +@@ -1390,6 +1401,8 @@ continuing. + + =head2 VDDK: IMPORTING A GUEST + ++The I<-it vddk> parameter selects VDDK as the input transport for disks. ++ + To import a particular guest from vCenter server or ESXi hypervisor, + use a command like the following, substituting the URI, guest name and + SSL thumbprint: +@@ -1397,7 +1410,8 @@ SSL thumbprint: + $ export PATH=/path/to/nbdkit:$PATH + $ virt-v2v \ + -ic 'vpx://root@vcenter.example.com/Datacenter/esxi?no_verify=1' \ +- --vddk /path/to/vmware-vix-disklib-distrib \ ++ -it vddk \ ++ --vddk-libdir /path/to/vmware-vix-disklib-distrib \ + --vddk-thumbprint xx:xx:xx:... \ + "Windows 2003" \ + -o local -os /var/tmp +-- +2.14.3 + diff --git a/SOURCES/0077-v2v-i-vmx-Enhance-VMX-support-with-ability-to-use-it.patch b/SOURCES/0077-v2v-i-vmx-Enhance-VMX-support-with-ability-to-use-it.patch new file mode 100644 index 0000000..77752e4 --- /dev/null +++ b/SOURCES/0077-v2v-i-vmx-Enhance-VMX-support-with-ability-to-use-it.patch @@ -0,0 +1,619 @@ +From d45c983b7181946323ebd93cccf1100b45b55470 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 8 Dec 2017 10:43:45 +0000 +Subject: [PATCH] =?UTF-8?q?v2v:=20-i=20vmx:=20Enhance=20VMX=20support=20wi?= + =?UTF-8?q?th=20ability=20to=20use=20=E2=80=98-it=20ssh=E2=80=99=20transpo?= + =?UTF-8?q?rt.?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This enhances the existing VMX input support allowing it to be +used over SSH to the ESXi server. + +The original command (for local .vmx files) was: + + $ virt-v2v -i vmx guest.vmx -o local -os /var/tmp + +Adding ‘-it ssh’ and using an SSH remote path gives the new syntax: + + $ virt-v2v \ + -i vmx -it ssh \ + "ssh://root@esxi.example.com/vmfs/volumes/datastore1/guest/guest.vmx" \ + -o local -os /var/tmp + +I anticipate that this input method will be widely used enough that it +deserves its own example at the top of the man page. + +(cherry picked from commit 1d38216d20141cef9ce83ca4ddbe9c79f5da4f39) +--- + v2v/cmdline.ml | 26 ++++-- + v2v/input_libvirt_other.ml | 9 --- + v2v/input_libvirt_other.mli | 1 - + v2v/input_vmx.ml | 193 +++++++++++++++++++++++++++++++++++++------- + v2v/input_vmx.mli | 5 +- + v2v/utils.ml | 9 +++ + v2v/utils.mli | 2 + + v2v/virt-v2v.pod | 106 ++++++++++++++++++++---- + 8 files changed, 290 insertions(+), 61 deletions(-) + +diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml +index 81562d1f5..dfcc77ecd 100644 +--- a/v2v/cmdline.ml ++++ b/v2v/cmdline.ml +@@ -276,6 +276,7 @@ read the man page virt-v2v(1). + let input_transport = + match !input_transport with + | None -> None ++ | Some "ssh" -> Some `SSH + | Some "vddk" -> Some `VDDK + | Some transport -> + error (f_"unknown input transport ‘-it %s’") transport in +@@ -341,7 +342,8 @@ read the man page virt-v2v(1). + * should not be used. + *) + (match input_transport with +- | None -> ++ | None ++ | Some `SSH -> + if !vddk_config <> None || + !vddk_cookie <> None || + !vddk_libdir <> None || +@@ -379,6 +381,12 @@ read the man page virt-v2v(1). + | [guest] -> guest + | _ -> + error (f_"expecting a libvirt guest name on the command line") in ++ let input_transport = ++ match input_transport with ++ | None -> None ++ | Some `VDDK -> Some `VDDK ++ | Some `SSH -> ++ error (f_"only ‘-it vddk’ can be used here") in + Input_libvirt.input_libvirt vddk_options password + input_conn input_transport guest + +@@ -401,13 +409,19 @@ read the man page virt-v2v(1). + Input_ova.input_ova filename + + | `VMX -> +- (* -i vmx: Expecting an vmx filename. *) +- let filename = ++ (* -i vmx: Expecting a vmx filename or SSH remote path. *) ++ let arg = + match args with +- | [filename] -> filename ++ | [arg] -> arg + | _ -> +- error (f_"expecting a VMX file name on the command line") in +- Input_vmx.input_vmx filename in ++ error (f_"expecting a single VMX file name or SSH remote path on the command line") in ++ let input_transport = ++ match input_transport with ++ | None -> None ++ | Some `SSH -> Some `SSH ++ | Some `VDDK -> ++ error (f_"only ‘-it ssh’ can be used here") in ++ Input_vmx.input_vmx input_transport arg in + + (* Prevent use of --in-place option in RHEL. *) + if in_place then +diff --git a/v2v/input_libvirt_other.ml b/v2v/input_libvirt_other.ml +index dc16cb11b..a487a2b76 100644 +--- a/v2v/input_libvirt_other.ml ++++ b/v2v/input_libvirt_other.ml +@@ -39,15 +39,6 @@ let error_if_libvirt_does_not_support_json_backingfile () = + Libvirt_utils.libvirt_get_version () < (2, 1, 0) then + error (f_"because of libvirt bug https://bugzilla.redhat.com/1134878 you must EITHER upgrade to libvirt >= 2.1.0 OR set this environment variable:\n\nexport LIBGUESTFS_BACKEND=direct\n\nand then rerun the virt-v2v command.") + +-(* xen+ssh URLs use the SSH driver in CURL. Currently this requires +- * ssh-agent authentication. Give a clear error if this hasn't been +- * set up (RHBZ#1139973). +- *) +-let error_if_no_ssh_agent () = +- try ignore (Sys.getenv "SSH_AUTH_SOCK") +- with Not_found -> +- error (f_"ssh-agent authentication has not been set up ($SSH_AUTH_SOCK is not set). Please read \"INPUT FROM RHEL 5 XEN\" in the virt-v2v(1) man page.") +- + (* Superclass. *) + class virtual input_libvirt (password : string option) libvirt_uri guest = + object +diff --git a/v2v/input_libvirt_other.mli b/v2v/input_libvirt_other.mli +index 494ca908a..8b1e8aa1d 100644 +--- a/v2v/input_libvirt_other.mli ++++ b/v2v/input_libvirt_other.mli +@@ -19,7 +19,6 @@ + (** [-i libvirt] source. *) + + val error_if_libvirt_does_not_support_json_backingfile : unit -> unit +-val error_if_no_ssh_agent : unit -> unit + + class virtual input_libvirt : string option -> string option -> string -> object + method precheck : unit -> unit +diff --git a/v2v/input_vmx.ml b/v2v/input_vmx.ml +index a4f77c2ab..092a7b70c 100644 +--- a/v2v/input_vmx.ml ++++ b/v2v/input_vmx.ml +@@ -19,6 +19,7 @@ + open Printf + open Scanf + ++open Unix_utils + open Common_gettext.Gettext + open Common_utils + +@@ -26,10 +27,86 @@ open Types + open Utils + open Name_from_disk + +-external identity : 'a -> 'a = "%identity" ++type vmx_source = ++ | File of string (* local file or NFS *) ++ | SSH of Xml.uri (* SSH URI *) + +-let rec find_disks vmx vmx_filename = +- find_scsi_disks vmx vmx_filename @ find_ide_disks vmx vmx_filename ++(* The single filename on the command line is intepreted either as ++ * a local file or a remote SSH URI (only if ‘-it ssh’). ++ *) ++let vmx_source_of_arg input_transport arg = ++ match input_transport, arg with ++ | None, arg -> File arg ++ | Some `SSH, arg -> ++ let uri = ++ try Xml.parse_uri arg ++ with Invalid_argument _ -> ++ error (f_"remote vmx ‘%s’ could not be parsed as a URI") arg in ++ if uri.Xml.uri_scheme <> None && uri.Xml.uri_scheme <> Some "ssh" then ++ error (f_"vmx URI start with ‘ssh://...’"); ++ if uri.Xml.uri_server = None then ++ error (f_"vmx URI remote server name omitted"); ++ if uri.Xml.uri_path = None || uri.Xml.uri_path = Some "/" then ++ error (f_"vmx URI path component looks incorrect"); ++ SSH uri ++ ++(* Return various fields from the URI. The checks in vmx_source_of_arg ++ * should ensure that none of these assertions fail. ++ *) ++let port_of_uri { Xml.uri_port } = ++ match uri_port with i when i <= 0 -> None | i -> Some i ++let server_of_uri { Xml.uri_server } = ++ match uri_server with None -> assert false | Some s -> s ++let path_of_uri { Xml.uri_path } = ++ match uri_path with None -> assert false | Some p -> p ++ ++(* 'scp' a remote file into a temporary local file, returning the path ++ * of the temporary local file. ++ *) ++let scp_from_remote_to_temporary uri tmpdir filename = ++ let localfile = tmpdir // filename in ++ ++ let cmd = ++ sprintf "scp%s%s %s%s:%s %s" ++ (if verbose () then "" else " -q") ++ (match port_of_uri uri with ++ | None -> "" ++ | Some port -> sprintf " -P %d" port) ++ (match uri.Xml.uri_user with ++ | None -> "" ++ | Some user -> quote user ^ "@") ++ (quote (server_of_uri uri)) ++ (* The double quoting of the path is counter-intuitive ++ * but correct, see: ++ * https://stackoverflow.com/questions/19858176/how-to-escape-spaces-in-path-during-scp-copy-in-linux ++ *) ++ (quote (quote (path_of_uri uri))) ++ (quote localfile) in ++ if verbose () then ++ eprintf "%s\n%!" cmd; ++ if Sys.command cmd <> 0 then ++ error (f_"could not copy the VMX file from the remote server, see earlier error messages"); ++ localfile ++ ++(* Test if [path] exists on the remote server. *) ++let remote_file_exists uri path = ++ let cmd = ++ sprintf "ssh%s %s%s test -f %s" ++ (match port_of_uri uri with ++ | None -> "" ++ | Some port -> sprintf " -p %d" port) ++ (match uri.Xml.uri_user with ++ | None -> "" ++ | Some user -> quote user ^ "@") ++ (quote (server_of_uri uri)) ++ (* Double quoting is necessary here, see above. *) ++ (quote (quote path)) in ++ if verbose () then ++ eprintf "%s\n%!" cmd; ++ Sys.command cmd = 0 ++ ++let rec find_disks vmx vmx_source = ++ find_scsi_disks vmx vmx_source @ find_ide_disks vmx vmx_source + + (* Find all SCSI hard disks. + * +@@ -39,7 +116,7 @@ let rec find_disks vmx vmx_filename = + * | omitted + * scsi0:0.fileName = "guest.vmdk" + *) +-and find_scsi_disks vmx vmx_filename = ++and find_scsi_disks vmx vmx_source = + let get_scsi_controller_target ns = + sscanf ns "scsi%d:%d" (fun c t -> c, t) + in +@@ -51,7 +128,7 @@ and find_scsi_disks vmx vmx_filename = + Some "scsi-harddisk"; None ] in + let scsi_controller = Source_SCSI in + +- find_hdds vmx vmx_filename ++ find_hdds vmx vmx_source + get_scsi_controller_target is_scsi_controller_target + scsi_device_types scsi_controller + +@@ -61,7 +138,7 @@ and find_scsi_disks vmx vmx_filename = + * ide0:0.deviceType = "ata-hardDisk" + * ide0:0.fileName = "guest.vmdk" + *) +-and find_ide_disks vmx vmx_filename = ++and find_ide_disks vmx vmx_source = + let get_ide_controller_target ns = + sscanf ns "ide%d:%d" (fun c t -> c, t) + in +@@ -72,11 +149,11 @@ and find_ide_disks vmx vmx_filename = + let ide_device_types = [ Some "ata-harddisk" ] in + let ide_controller = Source_IDE in + +- find_hdds vmx vmx_filename ++ find_hdds vmx vmx_source + get_ide_controller_target is_ide_controller_target + ide_device_types ide_controller + +-and find_hdds vmx vmx_filename ++and find_hdds vmx vmx_source + get_controller_target is_controller_target + device_types controller = + (* Find namespaces matching '(ide|scsi)X:Y' with suitable deviceType. *) +@@ -105,9 +182,9 @@ and find_hdds vmx vmx_filename + match path, v with + | [ns; "filename"], Some filename -> + let c, t = get_controller_target ns in ++ let uri, format = qemu_uri_of_filename vmx_source filename in + let s = { s_disk_id = (-1); +- s_qemu_uri = qemu_uri_of_filename vmx_filename filename; +- s_format = Some "vmdk"; ++ s_qemu_uri = uri; s_format = Some format; + s_controller = Some controller } in + Some (c, t, s) + | _ -> None +@@ -129,17 +206,54 @@ and find_hdds vmx vmx_filename + (* The filename can be an absolute path, but is more often a + * path relative to the location of the vmx file. + * +- * Note that we always end up with an absolute path, which is +- * also useful because it means we won't have any paths that +- * could be misinterpreted by qemu. ++ * This constructs a QEMU URI of the filename relative to the ++ * vmx file (which might be remote over SSH). + *) +-and qemu_uri_of_filename vmx_filename filename = +- if not (Filename.is_relative filename) then +- filename +- else ( +- let dir = Filename.dirname (absolute_path vmx_filename) in +- dir // filename +- ) ++and qemu_uri_of_filename vmx_source filename = ++ match vmx_source with ++ | File vmx_filename -> ++ (* Always ensure this returns an absolute path to avoid ++ * any confusion with filenames containing colons. ++ *) ++ absolute_path_from_other_file vmx_filename filename, "vmdk" ++ ++ | SSH uri -> ++ let vmx_path = path_of_uri uri in ++ let abs_path = absolute_path_from_other_file vmx_path filename in ++ let format = "vmdk" in ++ ++ (* XXX This is a hack to work around qemu / VMDK limitation ++ * "Cannot use relative extent paths with VMDK descriptor file" ++ * We can remove this if the above is fixed. ++ *) ++ let abs_path, format = ++ let flat_vmdk = ++ Str.replace_first (Str.regexp "\\.vmdk$") "-flat.vmdk" abs_path in ++ if remote_file_exists uri flat_vmdk then (flat_vmdk, "raw") ++ else (abs_path, format) in ++ ++ let json_params = [ ++ "file.driver", JSON.String "ssh"; ++ "file.path", JSON.String abs_path; ++ "file.host", JSON.String (server_of_uri uri); ++ "file.host_key_check", JSON.String "no"; ++ ] in ++ let json_params = ++ match uri.Xml.uri_user with ++ | None -> json_params ++ | Some user -> ++ ("file.user", JSON.String user) :: json_params in ++ let json_params = ++ match port_of_uri uri with ++ | None -> json_params ++ | Some port -> ++ ("file.port", JSON.Int port) :: json_params in ++ ++ "json:" ^ JSON.string_of_doc json_params, format ++ ++and absolute_path_from_other_file other_filename filename = ++ if not (Filename.is_relative filename) then filename ++ else (Filename.dirname (absolute_path other_filename)) // filename + + (* Find all removable disks. + * +@@ -272,21 +386,46 @@ and find_nics vmx = + let nics = List.map (fun (_, source) -> source) nics in + nics + +-class input_vmx vmx_filename = object ++class input_vmx input_transport arg = ++ let tmpdir = ++ let base_dir = (open_guestfs ())#get_cachedir () in ++ let t = Mkdtemp.temp_dir ~base_dir "vmx." in ++ rmdir_on_exit t; ++ t in ++object + inherit input + +- method as_options = "-i vmx " ^ vmx_filename ++ method as_options = "-i vmx " ^ arg ++ ++ method precheck () = ++ match input_transport with ++ | None -> () ++ | Some `SSH -> ++ if backend_is_libvirt () then ++ error (f_"because libvirtd doesn't pass the SSH_AUTH_SOCK environment variable to qemu you must set this environment variable:\n\nexport LIBGUESTFS_BACKEND=direct\n\nand then rerun the virt-v2v command."); ++ error_if_no_ssh_agent () + + method source () = +- (* Parse the VMX file. *) +- let vmx = Parse_vmx.parse_file vmx_filename in ++ let vmx_source = vmx_source_of_arg input_transport arg in ++ ++ (* If the transport is SSH, fetch the file from remote, else ++ * parse it from local. ++ *) ++ let vmx = ++ match vmx_source with ++ | File filename -> Parse_vmx.parse_file filename ++ | SSH uri -> ++ let filename = scp_from_remote_to_temporary uri tmpdir "source.vmx" in ++ Parse_vmx.parse_file filename in + + let name = + match Parse_vmx.get_string vmx ["displayName"] with ++ | Some s -> s + | None -> + warning (f_"no displayName key found in VMX file"); +- name_from_disk vmx_filename +- | Some s -> s in ++ match vmx_source with ++ | File filename -> name_from_disk filename ++ | SSH uri -> name_from_disk (path_of_uri uri) in + + let memory_mb = + match Parse_vmx.get_int64 vmx ["memSize"] with +@@ -325,7 +464,7 @@ class input_vmx vmx_filename = object + None + | None -> None in + +- let disks = find_disks vmx vmx_filename in ++ let disks = find_disks vmx vmx_source in + let removables = find_removables vmx in + let nics = find_nics vmx in + +diff --git a/v2v/input_vmx.mli b/v2v/input_vmx.mli +index f236f8716..34ec2a5c6 100644 +--- a/v2v/input_vmx.mli ++++ b/v2v/input_vmx.mli +@@ -18,5 +18,6 @@ + + (** [-i vmx] source. *) + +-val input_vmx : string -> Types.input +-(** [input_vmx filename] sets up an input from vmware vmx file. *) ++val input_vmx : [`SSH] option -> string -> Types.input ++(** [input_vmx input_transport arg] sets up an input ++ from vmware vmx file. *) +diff --git a/v2v/utils.ml b/v2v/utils.ml +index 2061eea61..158077bf6 100644 +--- a/v2v/utils.ml ++++ b/v2v/utils.ml +@@ -127,6 +127,15 @@ let backend_is_libvirt () = + let backend = fst (String.split ":" backend) in + backend = "libvirt" + ++(* When using the SSH driver in qemu (currently) this requires ++ * ssh-agent authentication. Give a clear error if this hasn't been ++ * set up (RHBZ#1139973). This might improve if we switch to libssh1. ++ *) ++let error_if_no_ssh_agent () = ++ try ignore (Sys.getenv "SSH_AUTH_SOCK") ++ with Not_found -> ++ error (f_"ssh-agent authentication has not been set up ($SSH_AUTH_SOCK is not set). This is required by qemu to do passwordless ssh access. See the virt-v2v(1) man page for more information.") ++ + let find_file_in_tar tar filename = + let lines = external_command (sprintf "tar tRvf %s" (Filename.quote tar)) in + let rec loop lines = +diff --git a/v2v/utils.mli b/v2v/utils.mli +index b2fd0be1b..042454565 100644 +--- a/v2v/utils.mli ++++ b/v2v/utils.mli +@@ -61,6 +61,8 @@ val qemu_img_supports_offset_and_size : unit -> bool + val backend_is_libvirt : unit -> bool + (** Return true iff the current backend is libvirt. *) + ++val error_if_no_ssh_agent : unit -> unit ++ + val find_file_in_tar : string -> string -> int64 * int64 + (** [find_file_in_tar tar filename] looks up file in [tar] archive and returns + a tuple containing at which byte it starts and how long the file is. +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index 7aca22b3c..d0387734a 100644 +--- a/v2v/virt-v2v.pod ++++ b/v2v/virt-v2v.pod +@@ -113,6 +113,23 @@ Note that after conversion, the guest will appear in the RHV-M Export + Storage Domain, from where you will need to import it using the RHV-M + user interface. (See L). + ++=head2 Convert from ESXi hypervisor over SSH to local libvirt ++ ++You have an ESXi hypervisor called C with SSH access ++enabled. You want to convert from VMFS storage on that server to ++a local file. ++ ++ virt-v2v \ ++ -i vmx -it ssh \ ++ "root@esxi.example.com/vmfs/volumes/datastore1/guest/guest.vmx" \ ++ -o local -os /var/tmp ++ ++The guest must not be running. Virt-v2v would I need to be run ++as root in this case. ++ ++For more information about converting from VMX files see ++L below. ++ + =head2 Convert disk image to OpenStack glance + + Given a disk image from another hypervisor that you want to convert to +@@ -233,9 +250,10 @@ L below + + Set the input method to I. + +-In this mode you can read a VMware vmx file directly. This is useful +-when VMware VMs are stored on an NFS server which you can mount +-directly. See L below ++In this mode you can read a VMware vmx file directly or over SSH. ++This is useful when VMware VMs are stored on an NFS server which you ++can mount directly, or where you have access by SSH to an ESXi ++hypervisor. See L below + + =item B<-ic> libvirtURI + +@@ -255,6 +273,11 @@ For I<-i disk> only, this specifies the format of the input disk + image. For other input methods you should specify the input + format in the metadata. + ++=item B<-it> B ++ ++When using I<-i vmx>, this enables the ssh transport. ++See L below. ++ + =item B<-it> B + + Use VMware VDDK as a transport to copy the input disks. See +@@ -1194,9 +1217,23 @@ directory containing the files: + + =head1 INPUT FROM VMWARE VMX + +-Virt-v2v is able to import guests from VMware’s vmx files. This is +-useful where VMware virtual machines are stored on a separate NFS +-server and you are able to mount the NFS storage directly. ++Virt-v2v is able to import guests from VMware’s vmx files. ++ ++This is useful in two cases: ++ ++=over 4 ++ ++=item 1. ++ ++VMware virtual machines are stored on a separate NFS server and you ++are able to mount the NFS storage directly. ++ ++=item 2. ++ ++You have enabled SSH access to the VMware ESXi hypervisor and there is ++a C folder containing the virtual machines. ++ ++=back + + If you find a folder of files called F.vmx>, + F.vmxf>, F.nvram> and one or more F<.vmdk> disk +@@ -1222,28 +1259,65 @@ With other methods, virt-v2v tries to prevent concurrent access, but + because the I<-i vmx> method works directly against the storage, + checking for concurrent access is not possible. + +-=head2 VMX: MOUNT THE NFS STORAGE ON THE CONVERSION SERVER ++=head2 VMX: ACCESS TO THE STORAGE CONTAINING THE VMX AND VMDK FILES + +-Virt-v2v must be able to access the F<.vmx> file and any local +-F<.vmdk> disks. Normally this means you must mount the NFS storage +-containing these files. ++If the vmx and vmdk files aren't available locally then you must ++I mount the NFS storage on the conversion server I enable ++passwordless SSH on the ESXi hypervisor. ++ ++=head3 VMX: Passwordless SSH using ssh-agent ++ ++You must also use ssh-agent, and add your ssh public key to ++F (on the ESXi hypervisor). ++ ++After doing this, you should check that passwordless access works from ++the virt-v2v server to the ESXi hypervisor. For example: ++ ++ $ ssh root@esxi.example.com ++ [ logs straight into the shell, no password is requested ] ++ ++Note that password-interactive and Kerberos access are B ++supported. You B to set up ssh access using ssh-agent and ++authorized_keys. ++ ++=head3 VMX: Construct the SSH URI ++ ++When using the SSH input transport you must specify a remote ++C URI pointing to the VMX file. A typical URI looks like: ++ ++ ssh://root@esxi.example.com/vmfs/volumes/datastore1/my%20guest/my%20guest.vmx ++ ++Any space must be escaped with C<%20> and other non-ASCII characters ++may also need to be URI-escaped. ++ ++The username is not required if it is the same as your local username. ++ ++You may optionally supply a port number after the hostname if the SSH ++server is not listening on the default port (22). + + =head2 VMX: IMPORTING A GUEST + +-To import a vmx file, do: ++To import a vmx file from a local file or NFS, do: + + $ virt-v2v -i vmx guest.vmx -o local -os /var/tmp + ++To import a vmx file over SSH, add I<-it ssh> to select the SSH ++transport and supply a remote SSH URI: ++ ++ $ virt-v2v \ ++ -i vmx -it ssh \ ++ "ssh://root@esxi.example.com/vmfs/volumes/datastore1/guest/guest.vmx" \ ++ -o local -os /var/tmp ++ + Virt-v2v processes the vmx file and uses it to find the location of + any vmdk disks. + + =head1 INPUT FROM VMWARE ESXi HYPERVISOR + +-Virt-v2v cannot access an ESXi hypervisor directly. You should use +-the OVA or VMX methods above (see L and/or +-L) if possible, as it is much faster and +-requires much less disk space than the method described in this +-section. ++You should use the OVA or VMX methods above (see L and/or L) if possible, as it is much ++faster and requires much less disk space than the method described in ++this section. + + You can use the L tool to copy the guest + off the hypervisor into a local file, and then convert it. +-- +2.14.3 + diff --git a/SOURCES/0078-builder-use-the-template-arch-when-caching-all-templ.patch b/SOURCES/0078-builder-use-the-template-arch-when-caching-all-templ.patch new file mode 100644 index 0000000..7349fbb --- /dev/null +++ b/SOURCES/0078-builder-use-the-template-arch-when-caching-all-templ.patch @@ -0,0 +1,153 @@ +From 244157fcea33dad2c99ca4b740b5483ed36e4238 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Wed, 29 Nov 2017 15:29:57 +0100 +Subject: [PATCH] builder: use the template arch when caching all templates + +When caching all the templates, use the architecture of each template, +instead of the architecture passed as --arch (or the host architecture, +as default). This way, the right destination filename will be used. + +Fixes commit b1cf6246f3c80762cf27dbdb24168589a34daf00. + +Thanks to: Erik Skultety. + +(cherry picked from commit b34f457cf2dd66626abf743c90881bfe6532ec9b) +--- + builder/Makefile.am | 2 + + builder/builder.ml | 4 +- + builder/test-virt-builder-cacheall.sh | 88 +++++++++++++++++++++++++++++++++++ + 3 files changed, 92 insertions(+), 2 deletions(-) + create mode 100755 builder/test-virt-builder-cacheall.sh + +diff --git a/builder/Makefile.am b/builder/Makefile.am +index 2bbf1247a..c260a327f 100644 +--- a/builder/Makefile.am ++++ b/builder/Makefile.am +@@ -28,6 +28,7 @@ EXTRA_DIST = \ + test-simplestreams/streams/v1/index.json \ + test-simplestreams/streams/v1/net.cirros-cloud_released_download.json \ + test-virt-builder.sh \ ++ test-virt-builder-cacheall.sh \ + test-virt-builder-docs.sh \ + test-virt-builder-list.sh \ + test-virt-builder-list-simplestreams.sh \ +@@ -236,6 +237,7 @@ yajl_tests_LINK = \ + $(yajl_tests_THEOBJECTS) -o $@ + + TESTS = \ ++ test-virt-builder-cacheall.sh \ + test-virt-builder-docs.sh \ + test-virt-builder-list.sh \ + test-virt-index-validate.sh \ +diff --git a/builder/builder.ml b/builder/builder.ml +index 213fd56a1..ce99e0339 100644 +--- a/builder/builder.ml ++++ b/builder/builder.ml +@@ -251,8 +251,8 @@ let main () = + List.iter ( + fun (name, + { Index.revision = revision; file_uri = file_uri; +- proxy = proxy }) -> +- let template = name, cmdline.arch, revision in ++ proxy = proxy; arch = arch }) -> ++ let template = name, arch, revision in + message (f_"Downloading: %s") file_uri; + let progress_bar = not (quiet ()) in + ignore (Downloader.download downloader ~template ~progress_bar +diff --git a/builder/test-virt-builder-cacheall.sh b/builder/test-virt-builder-cacheall.sh +new file mode 100755 +index 000000000..c80d9ecd2 +--- /dev/null ++++ b/builder/test-virt-builder-cacheall.sh +@@ -0,0 +1,88 @@ ++#!/bin/bash - ++# libguestfs virt-builder test script ++# Copyright (C) 2017 Red Hat Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ ++set -e ++ ++$TEST_FUNCTIONS ++skip_if_skipped ++ ++tmpdir="$(mktemp -d)" ++echo "tmpdir= $tmpdir" ++reposdir="$tmpdir/virt-builder/repos.d" ++repodir="$tmpdir/repo" ++indexfile="$repodir/index" ++cachedir="$tmpdir/cache" ++ ++mkdir -p "$reposdir" ++mkdir -p "$repodir" ++ ++# Create some fake images. ++img1_path="$repodir/img1.raw" ++img1_size=10485760 # 10G ++qemu-img create -f raw "$img1_path" $img1_size ++img1_csum=`do_sha256 "$img1_path"` ++ ++img2_path="$repodir/img2.qcow2" ++img2_size=5242880 # 5G ++qemu-img create -f qcow2 "$img2_path" $img2_size ++img2_csum=`do_sha256 "$img2_path"` ++ ++# Create an index for the images. ++cat > "$indexfile" < "$reposdir/repo1.conf" < +Date: Mon, 18 Dec 2017 10:29:11 +0000 +Subject: [PATCH] v2v: docs: Match the two instances of /path/to/nbdkit in the + documentation. + +Fixes commit d81a2ee185599c23a128ab65be9d48b415abf461. +See also: +https://bugzilla.redhat.com/show_bug.cgi?id=1513884#c5 + +(cherry picked from commit dab065a8eed6c6d8d9c53956393566812cfe6a2e) +--- + v2v/virt-v2v.pod | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod +index d0387734a..7d3923bda 100644 +--- a/v2v/virt-v2v.pod ++++ b/v2v/virt-v2v.pod +@@ -1481,7 +1481,7 @@ To import a particular guest from vCenter server or ESXi hypervisor, + use a command like the following, substituting the URI, guest name and + SSL thumbprint: + +- $ export PATH=/path/to/nbdkit:$PATH ++ $ export PATH=/path/to/nbdkit-1.1.x:$PATH + $ virt-v2v \ + -ic 'vpx://root@vcenter.example.com/Datacenter/esxi?no_verify=1' \ + -it vddk \ +-- +2.14.3 + diff --git a/SOURCES/0080-launch-direct-Omit-locking-option-for-non-file-disks.patch b/SOURCES/0080-launch-direct-Omit-locking-option-for-non-file-disks.patch new file mode 100644 index 0000000..a350111 --- /dev/null +++ b/SOURCES/0080-launch-direct-Omit-locking-option-for-non-file-disks.patch @@ -0,0 +1,33 @@ +From 05095797e4adf7c5afa807972c25dbe0998f5bcf Mon Sep 17 00:00:00 2001 +From: Lars Seipel +Date: Thu, 23 Nov 2017 06:15:28 +0100 +Subject: [PATCH] launch: direct: Omit locking option for non-file disks + (RHBZ#1516094) + +QEMU does not accept options unrecognized by the block driver +in use. Disable locking only for read-only disks that are +file-backed, as that's the only block driver it is supported +with. + +Signed-off-by: Lars Seipel +(cherry picked from commit 35320dd0edb94d09d231bcded57aa883a5e7c784) +--- + lib/launch-direct.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/launch-direct.c b/lib/launch-direct.c +index 0fef05927..4f31ac231 100644 +--- a/lib/launch-direct.c ++++ b/lib/launch-direct.c +@@ -534,7 +534,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) + escaped_file, + drv->disk_label ? ",serial=" : "", + drv->disk_label ? drv->disk_label : "", +- data->qemu_mandatory_locking ? ",file.backing.file.locking=off" : "", ++ data->qemu_mandatory_locking && drv->src.protocol == drive_protocol_file ? ",file.backing.file.locking=off" : "", + i); + } + +-- +2.14.3 + diff --git a/SOURCES/0081-launch-direct-Use-old-style-file-and-format-paramete.patch b/SOURCES/0081-launch-direct-Use-old-style-file-and-format-paramete.patch new file mode 100644 index 0000000..6f809ef --- /dev/null +++ b/SOURCES/0081-launch-direct-Use-old-style-file-and-format-paramete.patch @@ -0,0 +1,68 @@ +From 6db3412d15981d7624817d06999cb2ef4a03eed7 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 17 Jan 2018 10:11:53 +0000 +Subject: [PATCH] launch: direct: Use old-style file= and format= parameters + when not disabling locking (RHBZ#1503497). +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Ancient qemu 1.5 (in RHEL 7) does not understand the +file.file.filename= and file.driver= parameters. Go back to using the +old-style file= and format= parameters when we're not trying to set +the file.backing.file.locking=off parameter. + +Fixes commit 9fe592808ccfd9ed184b88ca9c6cad2e1798dee3. + +Thanks: Yongkui Guo, Václav Kadlčík. +(cherry picked from commit a30b51747fc6605f50a9d5d8095fd2b6d1473b1c) +--- + lib/launch-direct.c | 32 +++++++++++++++++++++++++------- + 1 file changed, 25 insertions(+), 7 deletions(-) + +diff --git a/lib/launch-direct.c b/lib/launch-direct.c +index 4f31ac231..3d6e72e78 100644 +--- a/lib/launch-direct.c ++++ b/lib/launch-direct.c +@@ -529,13 +529,31 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) + else { + /* Writable qcow2 overlay on top of read-only drive. */ + escaped_file = guestfs_int_qemu_escape_param (g, drv->overlay); +- param = safe_asprintf +- (g, "file.file.filename=%s,cache=unsafe,file.driver=qcow2%s%s%s,id=hd%zu", +- escaped_file, +- drv->disk_label ? ",serial=" : "", +- drv->disk_label ? drv->disk_label : "", +- data->qemu_mandatory_locking && drv->src.protocol == drive_protocol_file ? ",file.backing.file.locking=off" : "", +- i); ++ if (data->qemu_mandatory_locking && ++ /* Add the file-specific locking option only for files, as ++ * qemu won't accept options unknown to the block driver in ++ * use. ++ */ ++ drv->src.protocol == drive_protocol_file) { ++ param = safe_asprintf ++ (g, "file.file.filename=%s,file.driver=qcow2,file.backing.file.locking=off,cache=unsafe%s%s,id=hd%zu", ++ escaped_file, ++ drv->disk_label ? ",serial=" : "", ++ drv->disk_label ? drv->disk_label : "", ++ i); ++ } else { ++ /* Ancient qemu (esp. qemu 1.5 in RHEL 7) didn't understand the ++ * file.file.filename= parameter, so use the safer old-style ++ * form of parameters unless we actually want to specify the ++ * locking flag above. ++ */ ++ param = safe_asprintf ++ (g, "file=%s,format=qcow2,cache=unsafe%s%s,id=hd%zu", ++ escaped_file, ++ drv->disk_label ? ",serial=" : "", ++ drv->disk_label ? drv->disk_label : "", ++ i); ++ } + } + + /* If there's an explicit 'iface', use it. Otherwise default to +-- +2.14.3 + diff --git a/SOURCES/brew-overrides.sh b/SOURCES/brew-overrides.sh index 38baffe..ea91c18 100755 --- a/SOURCES/brew-overrides.sh +++ b/SOURCES/brew-overrides.sh @@ -8,30 +8,22 @@ set -x -# The kernel package doesn't install unless xfsprogs >= 4.3.0 -# is installed. -xfsprogs="$(brew -q latest-pkg rhel-7.4-candidate xfsprogs | - awk '{print $1}')" - -# linux-firmware is for virt-p2v, see RHBZ#1364419 -linux_firmware="$(brew -q latest-pkg rhel-7.4-candidate linux-firmware | - awk '{print $1}')" - pkgs=" - hivex-1.3.10-5.8.el7 - libvirt-3.1.0-2.el7 - libselinux-2.5-9.el7 - $linux_firmware - ocaml-findlib-1.3.3-7.el7 - policycoreutils-2.5-12.el7 - rdma-core-13-1.el7 - $xfsprogs + augeas-1.4.0-5.el7 + hivex-1.3.10-6.9.el7 + ocaml-4.05.0-6.el7 + ocaml-camlp4-4.05.0-0.4.gitfc12d8c7.el7 + ocaml-fileutils-0.4.4-9.el7 + ocaml-findlib-1.7.3-7.el7 + ocaml-gettext-0.3.7-1.el7 + ocaml-srpm-macros-5-2.el7 + supermin-5.1.19-1.el7 " for pkg in $pkgs ; do - brew tag-pkg rhel-7.4-temp-override $pkg + brew tag-pkg rhel-7.5-temp-override $pkg done for pkg in $pkgs ; do - brew wait-repo rhel-7.4-build --build=$pkg + brew wait-repo rhel-7.5-build --build=$pkg done diff --git a/SOURCES/copy-patches.sh b/SOURCES/copy-patches.sh index 48bf28f..55eeb97 100755 --- a/SOURCES/copy-patches.sh +++ b/SOURCES/copy-patches.sh @@ -6,7 +6,7 @@ set -e # directory. Use it like this: # ./copy-patches.sh -rhel_version=7.4 +rhel_version=7.5 # Check we're in the right directory. if [ ! -f libguestfs.spec ]; then diff --git a/SOURCES/libguestfs-1.36.10.tar.gz.sig b/SOURCES/libguestfs-1.36.10.tar.gz.sig new file mode 100644 index 0000000..844b0b5 --- /dev/null +++ b/SOURCES/libguestfs-1.36.10.tar.gz.sig @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIcBAABAgAGBQJZ6IBGAAoJEJFzj3Pht2igIyoQAKMmpv4f5kICU7LHte5uj7vi +HY26QAPwlHe1YLDgfd8rPp3EIClqOP+F75mDdL2OBE8wmd8GSD2zWZF7RXtS90x3 +Q5DsBWfDrKrJPGZ/UfjrlKhbFSUui1yK/V6fMfw2RyLZmNgh3ykwxwsx7RmdcqYz +/8ejIveqDHazvRdGHkCIXF8eAec+oYPMpmjufmoEMrkMTTcLQSUxZ0MvMC14L0z7 +K8lMp7UOa0P72GY3RYawgqIDKF1IbgTuNEeHb+7GXWjFELgqgRIyT/AQBduEdZEi +dDPWTJgsX1px7HLiTG43FsdDDs0hIpI3l89BrgPX6IB1JlqGig4fg4HovlpS9B3U +QMLSQORIjZUcViq2qHe2978ZaY1cV9R4oB0MYZxOVS/v7h8ED8aS5BmJTp+VBK8Y +D9uhyebmGaDeIkRvxeqdDwsQcQb+kS8ivdw9keWguEYozG+G67p9LYg8jl/8bHek +lktoJvIhrWdW0PrSIGrl++RJ4l/kv6jJsdpGwsySK2H4n7MeXangkxFtTluZpiWA +0UoF6C0xnV2KfOPGODwOtrkGiU/k+0BGANZOqpMbqofaLV8mS4FnVsRtDyiVUN0R +Q5RmrAvgfMt+vd0K57n55dr2+jxDtPtdGp/h2DD4g4uuacCe0jlUp1i+DYUi1H5/ +B3iWuIQHXwboqotBOtNQ +=KIqK +-----END PGP SIGNATURE----- diff --git a/SOURCES/libguestfs-1.36.3.tar.gz.sig b/SOURCES/libguestfs-1.36.3.tar.gz.sig deleted file mode 100644 index 10265fa..0000000 --- a/SOURCES/libguestfs-1.36.3.tar.gz.sig +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN PGP SIGNATURE----- - -iQIcBAABAgAGBQJY1YWwAAoJEJFzj3Pht2ign80QAK4985NZFaRJn6cgoWtQJflH -jjxSFkNokPUrA1LS3BFcHJyCaNldBn4FzMscdWYkVhVDe2K8HOq2wdWSt8tM1fFD -A9pDMIWfdL2/t3UPDGlvf/h43mxE1y86i9LrHfKsjHUR22AGSJBrb5IUHNHS30P4 -4/4pik7t99ExDlMPHiAS4F0+Mnz22ATbVTsquewpBjB3S1jPTN5JQILY7NqAXvht -Ua74xm6luDFNyr5XnKXRMW/oUxgsMY5cLXzwbGCREodjcvdWwBwdMjAHK0dXiOqC -Y0oNF4/91wbn1yapAhR09t205A10n6J0ZswNWwEqgYQledahu7XFjkH0PRt1iDnd -0Im29uuaEZP2PABrAIy95XLKiDBiKqBGFjIcqF3fmobPS3mLxVznLynmMOtQe2dJ -gAULb/IcqonGXesL5npltAC6JPnMj9l+hFcyij+jGjBHAFF53lyq32lSvZ2gZ6K8 -B/Y9gNz2L3I7QZZCUIUxa+9KqIRndg2pDbEyJU5NOc2TEtbgo9JsVMxLtSAvDCNz -UC6XZNZ4fh8qD4sLcgpWj2YLf+s1s+DSutcdMf6WR5Qae0rGx62z2ASJrIgPng79 -zU21SxdAOfL/h9VlCAVrLJ2vSf2WS91s1rf5WYAijS2tlz885wIUqZL91Nr1ivnf -ZPMqpz6AVJXrgzDn2iQE -=3M1c ------END PGP SIGNATURE----- diff --git a/SPECS/libguestfs.spec b/SPECS/libguestfs.spec index 4366c7a..6c0f1ab 100644 --- a/SPECS/libguestfs.spec +++ b/SPECS/libguestfs.spec @@ -13,8 +13,8 @@ Summary: Access and modify virtual machine disk images Name: libguestfs Epoch: 1 -Version: 1.36.3 -Release: 6%{?dist}.3 +Version: 1.36.10 +Release: 6%{?dist} License: LGPLv2+ # Source and patches. @@ -25,10 +25,10 @@ Source0: http://libguestfs.org/download/1.36-stable/%{name}-%{version}.tar Source1: http://libguestfs.org/download/1.36-stable/%{name}-%{version}.tar.gz.sig %endif -ExclusiveArch: x86_64 %{power64} aarch64 +ExclusiveArch: x86_64 %{power64} aarch64 s390x # RHEL 7 git repository is: -# https://github.com/libguestfs/libguestfs/tree/rhel-7.4 +# https://github.com/libguestfs/libguestfs/tree/rhel-7.5 # Use 'copy-patches.sh' to copy the patches from the git repo # to the current directory. @@ -56,27 +56,64 @@ Patch0020: 0020-RHEL-7-Revert-v2v-Add-a-support-matrix-to-the-manual.patch Patch0021: 0021-RHEL-7-All-qemu-kvm-in-RHEL-7-supports-discard-of-qc.patch Patch0022: 0022-RHEL-7-tests-Disable-daemon-tests-that-require-the-u.patch Patch0023: 0023-RHEL-7-v2v-Disable-the-virt-v2v-in-place-option.patch -Patch0024: 0024-RHEL-7-v2v-Remove-dcpath-option-RHBZ-1315237-RHBZ-14.patch -Patch0025: 0025-RHEL-7-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch -Patch0026: 0026-RHEL-7-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch -Patch0027: 0027-sysprep-Remove-DHCP_HOSTNAME-from-ifcfg-files-RHBZ-1.patch -Patch0028: 0028-p2v-v2v-Ensure-the-full-version-is-always-available-.patch -Patch0029: 0029-p2v-Run-fewer-scp-commands.patch -Patch0030: 0030-p2v-Fix-list-of-files-in-documentation.patch -Patch0031: 0031-p2v-tests-Fix-fake-scp-command-so-it-can-handle-mult.patch -Patch0032: 0032-v2v-windows-convert-fix-virtio-block-driver-installa.patch -Patch0033: 0033-v2v-o-qemu-Fix-creation-of-ICH6-sound-device.patch -Patch0034: 0034-ocaml-Add-Bytes.sub_string-function-to-Bytes-compat-.patch -Patch0035: 0035-mllib-Add-Char.hexdigit-function.patch -Patch0036: 0036-v2v-Implement-i-vmx-to-read-VMware-vmx-files-directl.patch -Patch0037: 0037-v2v-tests-Fix-i-vmx-test-so-it-is-more-stable.patch -Patch0038: 0038-v2v-o-rhv-Quote-parameter-to-rm-rf.patch -Patch0039: 0039-v2v-windows-Install-both-legacy-and-modern-virtio-ke.patch -Patch0040: 0040-v2v-o-rhv-Add-Windows-2016-Server-type-in-OVF-output.patch -Patch0041: 0041-daemon-lvm-Pass-yes-option-to-force-pvresize-RHBZ-14.patch -Patch0042: 0042-resize-make-sure-the-input-disk-is-read-only.patch -Patch0043: 0043-lib-libvirt-Pass-copyonread-flag-through-to-the-libv.patch -Patch0044: 0044-RHEL-7-v2v-disable-unconfig-of-manually-installed-VM.patch +Patch0024: 0024-RHEL-7-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch +Patch0025: 0025-RHEL-7-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch +Patch0026: 0026-sysprep-Remove-DHCP_HOSTNAME-from-ifcfg-files-RHBZ-1.patch +Patch0027: 0027-p2v-Run-fewer-scp-commands.patch +Patch0028: 0028-p2v-Fix-list-of-files-in-documentation.patch +Patch0029: 0029-p2v-tests-Fix-fake-scp-command-so-it-can-handle-mult.patch +Patch0030: 0030-v2v-Implement-i-vmx-to-read-VMware-vmx-files-directl.patch +Patch0031: 0031-v2v-tests-Fix-i-vmx-test-so-it-is-more-stable.patch +Patch0032: 0032-RHEL-7-v2v-disable-unconfig-of-manually-installed-VM.patch +Patch0033: 0033-v2v-i-ova-Prefer-pigz-or-pxz-for-uncompressing-OVA-f.patch +Patch0034: 0034-v2v-add-crypto-support-RHBZ-1451665.patch +Patch0035: 0035-v2v-Implement-input-from-nbdkit-vddk-plugin-RHBZ-147.patch +Patch0036: 0036-s390x-launch-libvirt-Use-console-device-sclp-for-app.patch +Patch0037: 0037-s390x-launch-direct-Use-sclp-as-serial-console-on-th.patch +Patch0038: 0038-s390x-appliance-Use-dev-ttysclp0-for-serial-console.patch +Patch0039: 0039-init-Add-comment-that-we-should-consider-using-proc-.patch +Patch0040: 0040-s390x-launch-direct-Use-virtio-ccw-on-this-architect.patch +Patch0041: 0041-s390x-tests-regressions-Skip-IDE-tests-on-S-390.patch +Patch0042: 0042-lib-Add-VIRTIO_DEVICE_NAME-macro-to-handle-virtio-mm.patch +Patch0043: 0043-v2v-i-vmx-Allow-deviceType-field-to-be-completely-om.patch +Patch0044: 0044-v2v-i-vmx-Add-a-test-case-which-lacks-scsi0-0.device.patch +Patch0045: 0045-v2v-vddk-Print-passthrough-options.patch +Patch0046: 0046-v2v-vddk-Check-if-nbdkit-supports-selinux-label-befo.patch +Patch0047: 0047-v2v-vddk-Force-source-format-to-raw.patch +Patch0048: 0048-v2v-Remove-dcpath-parameter-and-related-functionalit.patch +Patch0049: 0049-v2v-vCenter-Refactor-the-API-to-this-module.patch +Patch0050: 0050-v2v-vCenter-Split-up-get_session_cookie-function.patch +Patch0051: 0051-v2v-vCenter-Factor-out-get_https_url-code.patch +Patch0052: 0052-v2v-vCenter-Handle-disks-with-snapshots-RHBZ-1172425.patch +Patch0053: 0053-generator-Deprecate-direct-mode-guestfs_set_direct-g.patch +Patch0054: 0054-New-API-internal-get-console-socket-to-support-virt-.patch +Patch0055: 0055-lib-Return-EPIPE-for-appliance-closed-the-connection.patch +Patch0056: 0056-rescue-Modify-virt-rescue-so-it-doesn-t-use-direct-m.patch +Patch0057: 0057-rescue-Implement-m-and-i-options.patch +Patch0058: 0058-rescue-Implement-escape-sequences.patch +Patch0059: 0059-rescue-Move-suggest-code-to-separate-file.patch +Patch0060: 0060-rescue-docs-It-is-no-longer-necessary-to-mount-files.patch +Patch0061: 0061-rescue-docs-Note-that-you-can-run-virt-rescue-on-dis.patch +Patch0062: 0062-rescue-Don-t-document-suggest-option-in-help-output.patch +Patch0063: 0063-v2v-bootloaders-search-grub-config-for-all-distribut.patch +Patch0064: 0064-rescue-fix-size-check.patch +Patch0065: 0065-rescue-initialize-CLEANUP-pointer-variable.patch +Patch0066: 0066-v2v-i-ova-parse-MAC-address-from-rasd-Address-RHBZ-1.patch +Patch0067: 0067-v2v-Fix-RPM-file-owned-test-RHBZ-1503958.patch +Patch0068: 0068-v2v-bootloaders-handle-no-default-grubby-kernel-RHBZ.patch +Patch0069: 0069-lib-libvirt-stop-using-shareable-for-appliance-disk-.patch +Patch0070: 0070-v2v-vddk-Make-it-clearer-that-you-should-not-run-nbd.patch +Patch0071: 0071-podwrapper-nbdkit-man-pages-are-libguestfs-man-pages.patch +Patch0072: 0072-v2v-vddk-Update-minimum-version-of-nbdkit-to-1.1.16.patch +Patch0073: 0073-v2v-vddk-Further-rework-documentation.patch +Patch0074: 0074-v2v-docs-Remove-min-version-of-VDDK-recommend-nbdkit.patch +Patch0075: 0075-v2v-docs-State-that-vddk-thumbprint-is-only-required.patch +Patch0076: 0076-v2v-vddk-Switch-to-using-it-vddk-to-specify-VDDK-as-.patch +Patch0077: 0077-v2v-i-vmx-Enhance-VMX-support-with-ability-to-use-it.patch +Patch0078: 0078-builder-use-the-template-arch-when-caching-all-templ.patch +Patch0079: 0079-v2v-docs-Match-the-two-instances-of-path-to-nbdkit-i.patch +Patch0080: 0080-launch-direct-Omit-locking-option-for-non-file-disks.patch +Patch0081: 0081-launch-direct-Use-old-style-file-and-format-paramete.patch # Use git for patch management. BuildRequires: git @@ -141,7 +178,7 @@ BuildRequires: unzip BuildRequires: systemd-units BuildRequires: netpbm-progs BuildRequires: icoutils -%ifnarch aarch64 %{power64} +%ifnarch aarch64 %{power64} s390x # RHBZ#1177910 BuildRequires: libvirt-daemon-kvm %endif @@ -250,18 +287,10 @@ Requires: fuse Requires: /usr/bin/qemu-img # For libvirt backend. -%ifarch %{ix86} x86_64 %{arm} aarch64 %{power64} -Requires: libvirt-daemon-kvm >= 1.2.8-3 -%endif +# RHBZ#1500870, RHBZ#1501239 +Requires: libvirt-daemon-kvm >= 3.9.0-1 %ifarch aarch64 Requires: AAVMF -# RHBZ#1177910 -# RHBZ#1463646 -Requires: qemu-kvm -%endif -%ifarch %{power64} -# RHBZ#1177910 -Requires: qemu-kvm-rhev %endif # https://fedoraproject.org/wiki/Packaging:No_Bundled_Libraries#Packages_granted_exceptions @@ -555,7 +584,7 @@ diskimage-builder command. It is compatible with most diskimage-builder elements. -%ifnarch %{power64} +%ifnarch %{power64} s390x %package -n virt-v2v Summary: Convert a virtual machine to run on KVM License: GPLv2+ @@ -811,10 +840,7 @@ git commit -a -q -m "%{version} baseline" git am %{patches} # Patches affect Makefile.am and configure.ac, so rerun autotools. -autoreconf -autoconf - -mkdir -p daemon/m4 +autoreconf -fi # Replace developer-centric README that ships with libguestfs, with # our replacement file. @@ -842,7 +868,7 @@ fi # brew, and for that reason we have to hack things here. See: # https://bugzilla.redhat.com/show_bug.cgi?id=1125575#c18 # https://bugzilla.redhat.com/show_bug.cgi?id=1177910 -%ifarch aarch64 %{power64} +%ifarch aarch64 %{power64} s390x export vmchannel_test=no export QEMU=/usr/libexec/qemu-kvm %endif @@ -874,7 +900,7 @@ make V=1 INSTALLDIRS=vendor %{?_smp_mflags} # Can't test on aarch64 or ppc64/ppc64le yet because we don't have # a working qemu available in brew. -%ifnarch aarch64 %{power64} +%ifnarch aarch64 %{power64} s390x # Note that the major tests are done after the package has been built. # @@ -978,7 +1004,7 @@ mkdir -p $RPM_BUILD_ROOT%{_datadir}/virt-tools cp %{SOURCE96} $RPM_BUILD_ROOT%{_datadir}/virt-tools/rhsrvany.exe cp %{SOURCE97} $RPM_BUILD_ROOT%{_datadir}/virt-tools/rhev-apt.exe -%ifarch %{power64} +%ifarch %{power64} s390x # We don't ship virt-v2v on POWER (RHBZ#1287826). rm $RPM_BUILD_ROOT%{_bindir}/virt-p2v* rm $RPM_BUILD_ROOT%{_bindir}/virt-v2v* @@ -996,7 +1022,7 @@ rm -rf $RPM_BUILD_ROOT%{_libdir}/ocaml/v2v_test_harness rm -rf $RPM_BUILD_ROOT%{_libdir}/ocaml/stublibs/dllv2v_test_harness* rm -f $RPM_BUILD_ROOT%{_mandir}/man1/virt-v2v-test-harness.1* -%ifnarch %{power64} +%ifnarch %{power64} s390x # Delete kiwi tools. rm $RPM_BUILD_ROOT%{_bindir}/virt-p2v-make-kiwi rm $RPM_BUILD_ROOT%{_mandir}/man1/virt-p2v-make-kiwi.1* @@ -1166,7 +1192,7 @@ install -m 0644 utils/boot-benchmark/boot-benchmark.1 $RPM_BUILD_ROOT%{_mandir}/ %{_libdir}/guestfs/supermin.d/zz-packages-dib -%ifnarch %{power64} +%ifnarch %{power64} s390x %files -n virt-v2v %doc COPYING README v2v/TODO %{_bindir}/virt-v2v @@ -1292,17 +1318,65 @@ install -m 0644 utils/boot-benchmark/boot-benchmark.1 $RPM_BUILD_ROOT%{_mandir}/ %changelog -* Wed Aug 02 2017 Pino Toscano - 1:1.36.3-6.el7_4.3 -- v2v: disable unconfiguration of manually installed VMware tools. - resolves: rhbz#1480623 - -* Mon Jul 17 2017 Pino Toscano - 1:1.36.3-6.el7_4.2 -- Make sure kernel-rt is never used as Requires. - resolves: rhbz#1471829 - -* Wed Jul 12 2017 Pino Toscano - 1:1.36.3-6.el7_4.1 +* Mon Jan 22 2018 Pino Toscano - 1:1.36.10-6 +- Rebase to libguestfs 1.36.10 in RHEL 7.5. + resolves: rhbz#1472272 +- Build against OCaml 4.05 + resolves: rhbz#1447981 - Enable the copyonread flag when running the appliance using libvirt. - resolves: rhbz#1469902 + resolves: rhbz#1466563 +- Make sure kernel-rt is never used as Requires. + resolves: rhbz#1471651 +- v2v: disable unconfiguration of manually installed VMware tools. + resolves: rhbz#1477905 +- v2v: prefer pigz or pxz for uncompressing OVA files, if available + resolves: rhbz#1448739 +- resize: handle empty UUIDs for swap partitions + resolves: rhbz#1482737 +- v2v: remove mention of --dcpath in an error message + resolves: rhbz#1486197 +- Disables the QEMU image file locking when opening disks as read-only + resolves: rhbz#1417306 + resolves: rhbz#1503497 +- Briefly document the format used for URIs + resolves: rhbz#1450325 +- v2v: deal with grub2 configurations without a default set + resolves: rhbz#1472288 +- v2v: warn when a guest has passthrough devices + resolves: rhbz#1472719 +- v2v: fix three regular expressions + resolves: rhbz#1494555 +- v2v: enable conversion of full-disk LUKS-encrypted Linux guests + resolves: rhbz#1451665 +- v2v: new 'vddk' import method + resolves: rhbz#1477912 + resolves: rhbz#1513884 +- Enable libguestfs to work on z Systems + resolves: rhbz#1479526 +- p2v: fx check for sudo requiring a password + resolves: rhbz#1500673 +- v2v: handle disks with snapshots in vCenter + resolves: rhbz#1172425 +- rescue: backport improved version + resolves: rhbz#1438710 +- v2v: improve bootloader detection + resolves: rhbz#1508299 +- v2v: parse MAC address of network interfaces in OVF files + resolves: rhbz#1506572 +- Unconditionally depend on libvirt-daemon-kvm >= 3.9.0-1, which will always + pull the right qemu-kvm too, and thus remove the unversioned dependencies + on it + resolves: rhbz#1500870 +- v2v: fix RPM file owned test + resolves: rhbz#1503958 +- Do not open read-only disks using in the libvirt backend + resolves: rhbz#1518517 +- v2v: handle better when grubby does not report any default kernel + resolves: rhbz#1519204 +- v2v: enhance vmx import method to access via SSH + resolves: rhbz#1523767 +- builder: fix caching of templates when using --cache-all-templates + resolves: rhbz#1523650 * Thu Jun 22 2017 Pino Toscano - 1:1.36.3-6 - Rebase to libguestfs 1.36 in RHEL 7.4.