From de0be4d153465fd25916144518c20a73a02c4021 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Wed, 7 May 2025 13:14:18 +0100 Subject: [PATCH] New tool: virt-v2v-open resolves: RHEL-88985 --- ...pector-Simplify-input-bandwidth-code.patch | 40 + 0051-docs-Rearrange-root-titles.patch | 49 + ...ocs-Clarify-root-first-documentation.patch | 39 + ...ve-old-paragraph-about-a-bug-in-Grub.patch | 30 + 0054-Add-new-virt-v2v-open-tool.patch | 1016 +++++++++++++++++ virt-v2v.spec | 13 +- 6 files changed, 1185 insertions(+), 2 deletions(-) create mode 100644 0050-inspector-Simplify-input-bandwidth-code.patch create mode 100644 0051-docs-Rearrange-root-titles.patch create mode 100644 0052-docs-Clarify-root-first-documentation.patch create mode 100644 0053-docs-Remove-old-paragraph-about-a-bug-in-Grub.patch create mode 100644 0054-Add-new-virt-v2v-open-tool.patch diff --git a/0050-inspector-Simplify-input-bandwidth-code.patch b/0050-inspector-Simplify-input-bandwidth-code.patch new file mode 100644 index 0000000..efb8d3a --- /dev/null +++ b/0050-inspector-Simplify-input-bandwidth-code.patch @@ -0,0 +1,40 @@ +From 8e3d1747271cdf112d05e099302de7520f7f8111 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 30 Apr 2025 13:26:54 +0100 +Subject: [PATCH] inspector: Simplify input bandwidth code + +We dropped the virt-v2v --bandwidth parameters from +virt-v2v-inspector, but left some dead code around. Simplify that +code. + +(cherry picked from commit 7a96d82fb6a6330bc7e667677f62dea64a957188) +--- + inspector/inspector.ml | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/inspector/inspector.ml b/inspector/inspector.ml +index ac26146f..16300d45 100644 +--- a/inspector/inspector.ml ++++ b/inspector/inspector.ml +@@ -48,8 +48,6 @@ let rec main () = + else output_file := Some filename + in + +- let bandwidth = ref None in +- let bandwidth_file = ref None in + let input_conn = ref None in + let input_format = ref None in + let input_password = ref None in +@@ -313,11 +311,7 @@ read the man page virt-v2v-inspector(1). + (module Input_libvirt.Libvirt_) in + + let input_options = { +- Input.bandwidth = +- (match !bandwidth, !bandwidth_file with +- | None, None -> None +- | Some rate, None -> Some (StaticBandwidth rate) +- | rate, Some filename -> Some (DynamicBandwidth (rate, filename))); ++ Input.bandwidth = None; + input_conn = input_conn; + input_format = !input_format; + input_options = !input_options; diff --git a/0051-docs-Rearrange-root-titles.patch b/0051-docs-Rearrange-root-titles.patch new file mode 100644 index 0000000..bdc223b --- /dev/null +++ b/0051-docs-Rearrange-root-titles.patch @@ -0,0 +1,49 @@ +From e1b9a34aa4e140d3fafea4d0883d0c29fcc204bb Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 11 Apr 2025 10:01:13 +0100 +Subject: [PATCH] docs: Rearrange --root titles + +Makes the documentation easier to read instead of having a big block +of text. + +(cherry picked from commit c1d8ed9bac616c3ba8a807da350f24c7fa54e56a) +--- + docs/virt-v2v.pod | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index 57714022..1746afa7 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -774,12 +774,6 @@ This disables progress bars and other unnecessary output. + + =item B<--root single> + +-=item B<--root first> +- +-=item B<--root> /dev/sdX +- +-=item B<--root> /dev/VG/LV +- + Choose the root filesystem to be converted. + + In the case where the virtual machine is dual-boot or multi-boot, or +@@ -798,11 +792,17 @@ VM is found to be multi-boot, then virt-v2v will stop and list the + possible root filesystems and ask the user which to use. This + requires that virt-v2v is run interactively. + ++=item B<--root first> ++ + S> means to choose the first root device in the case + of a multi-boot operating system. Since this is a heuristic, it may + sometimes choose the wrong one. + +-You can also name a specific root device, eg. S> ++=item B<--root> /dev/sdX ++ ++=item B<--root> /dev/VG/LV ++ ++Name a specific root device to convert, eg. S> + would mean to use the second partition on the first hard drive. If + the named root device does not exist or was not detected as a root + device, then virt-v2v will fail. diff --git a/0052-docs-Clarify-root-first-documentation.patch b/0052-docs-Clarify-root-first-documentation.patch new file mode 100644 index 0000000..c774bac --- /dev/null +++ b/0052-docs-Clarify-root-first-documentation.patch @@ -0,0 +1,39 @@ +From bd20b2429f04d8c7b37fbcce243687413dbe434f Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 11 Apr 2025 09:49:06 +0100 +Subject: [PATCH] docs: Clarify --root first documentation + +Clarify that we don't necessarily choose the default bootloader option +(since we don't collect that information). It's just the first in the +list of roots returned by libguestfs. + +What is intentionally not documented here is that libguestfs doesn't +necessarily return the roots in any particular order (eg. it's not +sorted alphabetically). If we fix that in future, we might break how +this option works, so don't document any expectations. + +(cherry picked from commit bc936379e20e1aab5f569a577663082411f56dc2) +--- + docs/virt-v2v.pod | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index 1746afa7..84a7d6ac 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -794,9 +794,12 @@ requires that virt-v2v is run interactively. + + =item B<--root first> + +-S> means to choose the first root device in the case +-of a multi-boot operating system. Since this is a heuristic, it may +-sometimes choose the wrong one. ++Choose the first root device in the case of a multi-boot operating ++system. Since this is a heuristic, it may sometimes choose the wrong ++one, and it may not choose the default option from the guest ++bootloader. For predictable results it is better to use ++L to inspect the guest and then specify which ++root you want to convert. + + =item B<--root> /dev/sdX + diff --git a/0053-docs-Remove-old-paragraph-about-a-bug-in-Grub.patch b/0053-docs-Remove-old-paragraph-about-a-bug-in-Grub.patch new file mode 100644 index 0000000..8a1a7ff --- /dev/null +++ b/0053-docs-Remove-old-paragraph-about-a-bug-in-Grub.patch @@ -0,0 +1,30 @@ +From 26d2ba8c21fefb14b6ad2efb380ef08bff0b3b46 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 11 Apr 2025 10:07:20 +0100 +Subject: [PATCH] docs: Remove old paragraph about a bug in Grub + +This paragraph dates back to 2011 and is unlikely to be relevant now: + +https://github.com/rwmjones/old-virt-v2v/commit/36cc57baf395c5b05cc2174d1c04b386b94aaefd +(cherry picked from commit 3019f70565727fb7f03d475be154b1578ea2c51f) +--- + docs/virt-v2v.pod | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index 84a7d6ac..d65e13ed 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -810,12 +810,6 @@ would mean to use the second partition on the first hard drive. If + the named root device does not exist or was not detected as a root + device, then virt-v2v will fail. + +-Note that there is a bug in grub which prevents it from successfully +-booting a multiboot system if virtio is enabled. Grub is only able to +-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<-v> + + =item B<--verbose> diff --git a/0054-Add-new-virt-v2v-open-tool.patch b/0054-Add-new-virt-v2v-open-tool.patch new file mode 100644 index 0000000..cbda6ff --- /dev/null +++ b/0054-Add-new-virt-v2v-open-tool.patch @@ -0,0 +1,1016 @@ +From 99e27f9670f7e0e6416bf76074ebd84bd3315c6b Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 30 Apr 2025 12:47:30 +0100 +Subject: [PATCH] Add new virt-v2v-open tool + +This can be used to open the virt-v2v input method and run an almost +arbitrary program on it. For example you can run virt-inspector to +inspect the input (eg. to find root devices and other information for +the virt-v2v --root option), or guestfish. + +Currently this only opens the input read-only, although read-write +access might be added in future. + +Suggested-by: Martin Necas +Fixes: https://issues.redhat.com/browse/RHEL-88985 +(cherry picked from commit cb7d1cd1cf1e6e29e9945227aff3162e3cc9fb6a) +--- + .gitignore | 3 + + Makefile.am | 4 +- + configure.ac | 1 + + docs/Makefile.am | 15 ++ + docs/virt-v2v-open.pod | 183 +++++++++++++++++++++ + docs/virt-v2v.pod | 9 +- + open/Makefile.am | 126 +++++++++++++++ + open/dummy.c | 2 + + open/open.ml | 298 +++++++++++++++++++++++++++++++++++ + open/open.mli | 19 +++ + run.in | 1 + + tests/Makefile.am | 4 + + tests/test-open-encrypted.sh | 56 +++++++ + tests/test-open.sh | 77 +++++++++ + 14 files changed, 795 insertions(+), 3 deletions(-) + create mode 100644 docs/virt-v2v-open.pod + create mode 100644 open/Makefile.am + create mode 100644 open/dummy.c + create mode 100644 open/open.ml + create mode 100644 open/open.mli + create mode 100755 tests/test-open-encrypted.sh + create mode 100755 tests/test-open.sh + +diff --git a/.gitignore b/.gitignore +index 9dcd4611..f86caaee 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -52,6 +52,7 @@ Makefile.in + /docs/virt-v2v-input-vmware.1 + /docs/virt-v2v-input-xen.1 + /docs/virt-v2v-inspector.1 ++/docs/virt-v2v-open.1 + /docs/virt-v2v-output-local.1 + /docs/virt-v2v-output-openstack.1 + /docs/virt-v2v-output-rhv.1 +@@ -84,6 +85,8 @@ Makefile.in + /missing + /ocaml-dep.sh + /ocaml-link.sh ++/open/.depend ++/open/virt-v2v-open + /output/.depend + /output/oUnit-anon.cache + /output/output_rhv_upload_*_source.ml +diff --git a/Makefile.am b/Makefile.am +index 4cc87324..dcbde1b5 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -44,6 +44,7 @@ SUBDIRS += convert + SUBDIRS += v2v + SUBDIRS += inspector + SUBDIRS += in-place ++SUBDIRS += open + + SUBDIRS += tests + +@@ -112,7 +113,8 @@ po/POTFILES: configure.ac + po/POTFILES-ml: configure.ac + rm -f $@ $@-t + cd $(srcdir); \ +- find common/ml* lib in-place input inspector output v2v -name '*.ml' | \ ++ find common/ml* lib in-place input inspector open output v2v \ ++ -name '*.ml' | \ + grep -v '^common/mlprogress/' | \ + grep -v '^common/mlvisit/' | \ + grep -v '^lib/config.ml$$' | \ +diff --git a/configure.ac b/configure.ac +index a99bcb75..e1e01742 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -145,6 +145,7 @@ AC_CONFIG_FILES([Makefile + inspector/Makefile + lib/Makefile + lib/config.ml ++ open/Makefile + output/Makefile + po-docs/Makefile + po-docs/ja/Makefile +diff --git a/docs/Makefile.am b/docs/Makefile.am +index d86349f4..d3547b4d 100644 +--- a/docs/Makefile.am ++++ b/docs/Makefile.am +@@ -25,6 +25,7 @@ EXTRA_DIST = \ + virt-v2v-input-vmware.pod \ + virt-v2v-input-xen.pod \ + virt-v2v-inspector.pod \ ++ virt-v2v-open.pod \ + virt-v2v-output-local.pod \ + virt-v2v-output-openstack.pod \ + virt-v2v-output-rhv.pod \ +@@ -45,6 +46,7 @@ man_MANS = \ + virt-v2v-input-vmware.1 \ + virt-v2v-input-xen.1 \ + virt-v2v-inspector.1 \ ++ virt-v2v-open.1 \ + virt-v2v-output-local.1 \ + virt-v2v-output-openstack.1 \ + virt-v2v-output-rhv.1 \ +@@ -62,6 +64,7 @@ noinst_DATA = \ + $(top_builddir)/website/virt-v2v-input-vmware.1.html \ + $(top_builddir)/website/virt-v2v-input-xen.1.html \ + $(top_builddir)/website/virt-v2v-inspector.1.html \ ++ $(top_builddir)/website/virt-v2v-open.1.html \ + $(top_builddir)/website/virt-v2v-output-local.1.html \ + $(top_builddir)/website/virt-v2v-output-openstack.1.html \ + $(top_builddir)/website/virt-v2v-output-rhv.1.html \ +@@ -142,6 +145,18 @@ stamp-virt-v2v-inspector.pod: virt-v2v-inspector.pod + $< + touch $@ + ++virt-v2v-open.1 $(top_builddir)/website/virt-v2v-open.1.html: stamp-virt-v2v-open.pod ++ ++stamp-virt-v2v-open.pod: virt-v2v-open.pod ++ $(PODWRAPPER) \ ++ --man virt-v2v-open.1 \ ++ --html $(top_builddir)/website/virt-v2v-open.1.html \ ++ --path $(top_srcdir)/common/options \ ++ --license GPLv2+ \ ++ --warning safe \ ++ $< ++ touch $@ ++ + virt-v2v-output-local.1 $(top_builddir)/website/virt-v2v-output-local.1.html: stamp-virt-v2v-output-local.pod + + stamp-virt-v2v-output-local.pod: virt-v2v-output-local.pod +diff --git a/docs/virt-v2v-open.pod b/docs/virt-v2v-open.pod +new file mode 100644 +index 00000000..660ac83e +--- /dev/null ++++ b/docs/virt-v2v-open.pod +@@ -0,0 +1,183 @@ ++=head1 NAME ++ ++virt-v2v-open - Open the virt-v2v input and run a program on it ++ ++=head1 SYNOPSIS ++ ++ virt-v2v-open [-i* options] guest --run 'program [--options] @@' ++ ++ virt-v2v-open -i disk guest.img --run 'virt-inspector --format=raw @@' ++ ++ virt-v2v-open -i disk guest.img --run 'guestfish --ro --format=raw @@ -i' ++ ++=head1 DESCRIPTION ++ ++Virt-v2v-open is a companion tool for L and ++L which can be used before conversion to open ++the input side of virt-v2v and run a program. ++ ++Some uses for this include running L directly on ++the source guest to find source operating systems (to use with the ++virt-v2v I<--root> option). Or running guestfish to take a look ++inside the source guest before conversion. You can follow that by ++running L to estimate how much space would be ++needed to convert that guest, and if conversion of the guest is ++possible. ++ ++This manual page only documents the program options, not all of the ++I<-i*> options which are the same as virt-v2v. You should read ++L first. ++ ++Notes: ++ ++=over 4 ++ ++=item * ++ ++The source guest is always opened read-only. You will not be able to ++make persistent changes. ++ ++=item * ++ ++L can be used directly on local disk images. ++ ++=back ++ ++=head2 Selecting the input guest ++ ++You can run virt-v2v-open with the same I<-i*> options as virt-v2v. ++(Don't use any I<-o*> options). This will select the guest that you ++want to open. ++ ++=head2 Running the program ++ ++On the command line, put the program that you want to run on the ++source guest and any other parameters that program needs into the ++I<--run> parameter. C<@@> in the parameter is substituted with ++I<-a DISK ...> for each source disk, in a way which is compatible with ++L and L. ++ ++ virt-v2v-open [-i ...] guest \ ++ --run 'virt-inspector --format=raw @@ > output.xml' ++ ++ virt-v2v-open [-i ...] guest \ ++ --run 'guestfish --ro --format=raw @@ -i' ++ ++ virt-v2v-open [-i ...] guest \ ++ --run 'guestfish --ro --format=raw @@ run : list-filesystems' ++ ++=head1 OPTIONS ++ ++=over 4 ++ ++=item B<--help> ++ ++Display help. ++ ++=item B<-v> ++ ++=item B<--verbose> ++ ++Enable verbose messages for debugging. ++ ++=item B<-V> ++ ++=item B<--version> ++ ++Display version number and exit. ++ ++=item B<-x> ++ ++Enable tracing of libguestfs API calls. ++ ++=item B<-i> ... ++ ++=item B<-ic> ... ++ ++=item B<-if> ... ++ ++=item B<-io> ... ++ ++=item B<-ip> ... ++ ++=item B<-it> ... ++ ++All of the I<-i*> options supported by virt-v2v are also supported by ++virt-v2v-open. ++ ++=item B<--colors> ++ ++=item B<--colours> ++ ++=item B<--machine-readable> ++ ++=item B<--machine-readable>=format ++ ++=item B<-q> ++ ++=item B<--quiet> ++ ++=item B<--wrap> ++ ++These options work in the same way as the equivalent virt-v2v options. ++ ++=item B<--run> COMMAND ++ ++The command that you want to run on the source guest. C<@@> in the ++command is substituted with a list of I<-a DISK> options that is ++compatible with virt-inspector and guestfish. ++ ++=back ++ ++=head1 FILES ++ ++Files used are the same as for virt-v2v. See L. ++ ++=head1 ENVIRONMENT VARIABLES ++ ++Environment variables used are the same as for virt-v2v. See ++L. ++ ++=head1 SEE ALSO ++ ++L, ++L, ++L, ++L, ++L, ++L, ++L, ++L, ++L. ++ ++=head1 AUTHORS ++ ++Matthew Booth ++ ++Cédric Bosdonnat ++ ++Laszlo Ersek ++ ++Tomáš Golembiovský ++ ++Shahar Havivi ++ ++Richard W.M. Jones ++ ++Roman Kagan ++ ++Mike Latimer ++ ++Nir Soffer ++ ++Pino Toscano ++ ++Xiaodai Wang ++ ++Ming Xie ++ ++Tingting Zheng ++ ++=head1 COPYRIGHT ++ ++Copyright (C) 2009-2025 Red Hat Inc. +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index d65e13ed..b946758c 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -784,6 +784,9 @@ Windows Recovery Console, certain attached DVD drives, and bugs in + libguestfs inspection heuristics, can make a guest look like a + multi-boot operating system. + ++Either L or L can be used to list ++the roots for a dual-boot or multi-boot VM. ++ + The default in virt-v2v E 0.7.1 was S>, which + causes virt-v2v to die if a multi-boot operating system is found. + +@@ -798,8 +801,8 @@ Choose the first root device in the case of a multi-boot operating + system. Since this is a heuristic, it may sometimes choose the wrong + one, and it may not choose the default option from the guest + bootloader. For predictable results it is better to use +-L to inspect the guest and then specify which +-root you want to convert. ++L and L to inspect the guest and ++then specify which root you want to convert. + + =item B<--root> /dev/sdX + +@@ -1670,9 +1673,11 @@ L, + L, ++L, + L, + L, + L, ++L, + L, + L, + L, +diff --git a/open/Makefile.am b/open/Makefile.am +new file mode 100644 +index 00000000..e904eec9 +--- /dev/null ++++ b/open/Makefile.am +@@ -0,0 +1,126 @@ ++# libguestfs virt-v2v-open tool ++# Copyright (C) 2009-2025 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 $(top_srcdir)/subdir-rules.mk ++ ++EXTRA_DIST = \ ++ $(SOURCES_MLI) \ ++ $(SOURCES_ML) \ ++ $(SOURCES_C) ++ ++SOURCES_MLI = \ ++ open.mli ++ ++SOURCES_ML = \ ++ open.ml ++ ++SOURCES_C = \ ++ dummy.c ++ ++bin_PROGRAMS = virt-v2v-open ++ ++virt_v2v_open_SOURCES = $(SOURCES_C) ++virt_v2v_open_CPPFLAGS = \ ++ -DCAML_NAME_SPACE \ ++ -I. \ ++ -I$(top_builddir) \ ++ -I$(shell $(OCAMLC) -where) \ ++ -I$(top_srcdir)/lib ++virt_v2v_open_CFLAGS = \ ++ -pthread \ ++ $(WARN_CFLAGS) $(WERROR_CFLAGS) \ ++ $(LIBGUESTFS_CFLAGS) \ ++ $(LIBVIRT_CFLAGS) ++ ++BOBJECTS = $(SOURCES_ML:.ml=.cmo) ++XOBJECTS = $(BOBJECTS:.cmo=.cmx) ++ ++OCAMLPACKAGES = \ ++ -package str,unix,guestfs,libvirt,nbd \ ++ -I $(top_builddir)/common/utils/.libs \ ++ -I $(top_builddir)/common/qemuopts/.libs \ ++ -I $(top_builddir)/gnulib/lib/.libs \ ++ -I $(top_builddir)/lib \ ++ -I $(top_builddir)/input \ ++ -I $(top_builddir)/common/mlstdutils \ ++ -I $(top_builddir)/common/mlutils \ ++ -I $(top_builddir)/common/mlgettext \ ++ -I $(top_builddir)/common/mlpcre \ ++ -I $(top_builddir)/common/mlxml \ ++ -I $(top_builddir)/common/mltools \ ++ -I $(top_builddir)/common/mlcustomize \ ++ -I $(top_builddir)/common/mldrivers ++if HAVE_OCAML_PKG_GETTEXT ++OCAMLPACKAGES += -package gettext-stub ++endif ++ ++OCAMLCLIBS = \ ++ -pthread \ ++ -lqemuopts \ ++ $(LIBGUESTFS_LIBS) \ ++ $(LIBVIRT_LIBS) \ ++ $(LIBCRYPT_LIBS) \ ++ $(LIBXML2_LIBS) \ ++ $(JSON_C_LIBS) \ ++ $(LIBOSINFO_LIBS) \ ++ $(LIBINTL) \ ++ $(LIBNBD_LIBS) \ ++ -lgnu ++ ++OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)' ++ ++if !HAVE_OCAMLOPT ++OBJECTS = $(BOBJECTS) ++else ++OBJECTS = $(XOBJECTS) ++endif ++ ++OCAMLLINKFLAGS = \ ++ mlstdutils.$(MLARCHIVE) \ ++ mlgettext.$(MLARCHIVE) \ ++ mlpcre.$(MLARCHIVE) \ ++ mlxml.$(MLARCHIVE) \ ++ mlcutils.$(MLARCHIVE) \ ++ mltools.$(MLARCHIVE) \ ++ mllibvirt.$(MLARCHIVE) \ ++ mlcustomize.$(MLARCHIVE) \ ++ mldrivers.$(MLARCHIVE) \ ++ mlv2vlib.$(MLARCHIVE) \ ++ mlinput.$(MLARCHIVE) \ ++ $(LINK_CUSTOM_OCAMLC_ONLY) ++ ++virt_v2v_open_DEPENDENCIES = \ ++ $(OBJECTS) \ ++ $(top_builddir)/input/mlinput.$(MLARCHIVE) \ ++ $(top_builddir)/lib/mlv2vlib.$(MLARCHIVE) \ ++ $(top_srcdir)/ocaml-link.sh ++virt_v2v_open_LINK = \ ++ $(top_srcdir)/ocaml-link.sh -cclib '$(OCAMLCLIBS)' -- \ ++ $(OCAMLFIND) $(BEST) $(OCAMLFLAGS) $(OCAMLPACKAGES) $(OCAMLLINKFLAGS) \ ++ $(OBJECTS) -o $@ ++ ++# Data directory. ++ ++virttoolsdatadir = $(datadir)/virt-tools ++ ++# Dependencies. ++.depend: \ ++ $(srcdir)/*.mli \ ++ $(srcdir)/*.ml \ ++ $(filter %.ml,$(BUILT_SOURCES)) ++ $(top_builddir)/ocaml-dep.sh $^ ++-include .depend +diff --git a/open/dummy.c b/open/dummy.c +new file mode 100644 +index 00000000..ebab6198 +--- /dev/null ++++ b/open/dummy.c +@@ -0,0 +1,2 @@ ++/* Dummy source, to be used for OCaml-based tools with no C sources. */ ++enum { foo = 1 }; +diff --git a/open/open.ml b/open/open.ml +new file mode 100644 +index 00000000..8a82b13e +--- /dev/null ++++ b/open/open.ml +@@ -0,0 +1,298 @@ ++(* virt-v2v-open ++ * Copyright (C) 2009-2025 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 Unix ++ ++open Std_utils ++open Tools_utils ++open Unix_utils ++open Common_gettext.Gettext ++open Getopt.OptionName ++ ++open Types ++open Utils ++ ++let template_rex = PCRE.compile "@@" ++ ++module G = Guestfs ++ ++let rec main () = ++ let set_string_option_once optname optref arg = ++ match !optref with ++ | Some _ -> ++ error (f_"%s option used more than once on the command line") optname ++ | None -> ++ optref := Some arg ++ in ++ ++ let input_conn = ref None in ++ let input_format = ref None in ++ let input_password = ref None in ++ let input_transport = ref None in ++ let input_options = ref [] in ++ let io_query = ref false in ++ let set_input_option_compat k v = ++ List.push_back input_options (k, v) ++ in ++ let set_input_option option = ++ if option = "?" then io_query := true ++ else ( ++ let k, v = String.split "=" option in ++ set_input_option_compat k v ++ ) ++ in ++ ++ let input_mode = ref `Not_set in ++ let set_input_mode mode = ++ if !input_mode <> `Not_set then ++ error (f_"%s option used more than once on the command line") "-i"; ++ match mode with ++ | "disk" | "local" -> input_mode := `Disk ++ | "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 ++ ++ let command_template = ref None in ++ ++ let argspec = [ ++ [ S 'i' ], Getopt.String ("disk|libvirt|libvirtxml|ova|vmx", set_input_mode), ++ s_"Set input mode (default: libvirt)"; ++ [ M"ic" ], Getopt.String ("uri", set_string_option_once "-ic" input_conn), ++ s_"Libvirt URI"; ++ [ M"if" ], Getopt.String ("format", set_string_option_once "-if" input_format), ++ s_"Input format"; ++ [ M"io" ], Getopt.String ("option[=value]", set_input_option), ++ s_"Set option for input mode"; ++ [ M"ip" ], Getopt.String ("filename", set_string_option_once "-ip" input_password), ++ s_"Use password from file to connect to input hypervisor"; ++ [ M"it" ], Getopt.String ("transport", set_string_option_once "-it" input_transport), ++ s_"Input transport"; ++ [ L"run" ], Getopt.String ("COMMAND", set_string_option_once "--run" command_template), ++ s_"External command to run"; ++ ] in ++ ++ let args = ref [] in ++ let anon_fun s = List.push_front s args in ++ let usage_msg = ++ sprintf (f_"\ ++%s: open the virt-v2v input and run a program on it ++ ++virt-v2v-open -i disk disk.img --run 'virt-inspector --format=raw @@' ++ ++A short summary of the options is given below. For detailed help please ++read the man page virt-v2v-open(1). ++") ++ prog in ++ ++ let opthandle = create_standard_options argspec ~anon_fun ~key_opts:false ++ ~machine_readable:true usage_msg in ++ Getopt.parse opthandle.getopt; ++ ++ (* Print the version, easier than asking users to tell us. *) ++ debug "info: %s: %s %s (%s)" ++ prog Config.package_name Config.package_version_full ++ Config.host_cpu; ++ ++ (* Print the libvirt version if debugging. *) ++ if verbose () then ( ++ let major, minor, release = Libvirt_utils.libvirt_get_version () in ++ debug "info: libvirt version: %d.%d.%d" major minor release ++ ); ++ ++ (* Create the v2v directory to control conversion. *) ++ let v2vdir = create_v2v_directory () in ++ ++ (* Dereference the arguments. *) ++ let args = List.rev !args in ++ let input_conn = !input_conn in ++ let input_mode = !input_mode in ++ 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 ++ ++ let command_template = ++ match !command_template with ++ | None -> error (f_"you must supply the --run parameter") ++ | Some c -> c in ++ ++ (* No arguments and machine-readable mode? Print out some facts ++ * about what this binary supports. ++ *) ++ (match args, machine_readable () with ++ | [], Some { pr } -> ++ pr "virt-v2v-open\n"; ++ pr "libguestfs-rewrite\n"; ++ pr "colours-option\n"; ++ pr "io\n"; ++ pr "input:disk\n"; ++ pr "input:libvirt\n"; ++ pr "input:libvirtxml\n"; ++ pr "input:ova\n"; ++ pr "input:vmx\n"; ++ exit 0 ++ | _, _ -> () ++ ); ++ ++ (* Get the input module. *) ++ let (module Input_module) = ++ match input_mode with ++ | `Disk -> (module Input_disk.Disk : Input.INPUT) ++ | `LibvirtXML -> (module Input_libvirt.LibvirtXML) ++ | `OVA -> (module Input_ova.OVA) ++ | `VMX -> (module Input_vmx.VMX) ++ | `Not_set | `Libvirt -> ++ match input_conn with ++ | None -> (module Input_libvirt.Libvirt_) ++ | Some orig_uri -> ++ let { Xml.uri_server = server; uri_scheme = scheme } = ++ try Xml.parse_uri orig_uri ++ with Invalid_argument msg -> ++ error (f_"could not parse '-ic %s'. \ ++ Original error message was: %s") ++ orig_uri msg in ++ ++ match server, scheme, input_transport with ++ | None, _, _ ++ | Some "", _, _ (* Not a remote URI. *) ++ ++ | Some _, None, _ (* No scheme? *) ++ | Some _, Some "", _ -> ++ (module Input_libvirt.Libvirt_) ++ ++ (* vCenter over https. *) ++ | Some server, Some ("esx"|"gsx"|"vpx"), None -> ++ (module Input_vcenter_https.VCenterHTTPS) ++ ++ (* vCenter or ESXi using nbdkit vddk plugin *) ++ | Some server, Some ("esx"|"gsx"|"vpx"), Some `VDDK -> ++ (module Input_vddk.VDDK) ++ ++ (* Xen over SSH *) ++ | Some server, Some "xen+ssh", _ -> ++ (module Input_xen_ssh.XenSSH) ++ ++ (* Old virt-v2v also supported qemu+ssh://. However I am ++ * deliberately not supporting this in new virt-v2v. Don't ++ * use virt-v2v if a guest already runs on KVM. ++ *) ++ ++ (* Unknown remote scheme. *) ++ | 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; ++ (module Input_libvirt.Libvirt_) in ++ ++ let input_options = { ++ Input.bandwidth = None; ++ input_conn = input_conn; ++ input_format = !input_format; ++ input_options = !input_options; ++ input_password = !input_password; ++ input_transport = input_transport; ++ (* This must always be true so that we do not modify the ++ * source. This is set to [false] by in-place mode. ++ *) ++ read_only = true; ++ } in ++ ++ (* If -io ? then we want to query input options supported in this mode. *) ++ if !io_query then ( ++ Input_module.query_input_options (); ++ exit 0 ++ ); ++ ++ (* Before starting the input module, check there is sufficient ++ * free space in the temporary directory on the host. ++ *) ++ check_host_free_space (); ++ ++ (* Start the input module (runs an NBD server in the background). *) ++ message (f_"Setting up the source: %s") ++ (Input_module.to_string input_options args); ++ let source = Input_module.setup v2vdir input_options args in ++ ++ message (f_"Running external command"); ++ ++ (* We're not really doing a conversion here, but write the 'convert' ++ * file around this to tune the input module correctly. ++ *) ++ with_open_out (v2vdir // "convert") (fun _ -> ()); ++ ++ (* Get the list of input sockets (NBD endpoints), formatted as ++ * a shell-quoted list of [-a] options. ++ *) ++ let add_params = ++ List.map ( ++ fun { s_disk_id = i } -> ++ let socket = sprintf "nbd+unix://?socket=%s/in%d" v2vdir i in ++ sprintf "-a %s" (quote socket) ++ ) source.s_disks ++ |> String.concat " " in ++ ++ (* Run external program. *) ++ debug "command template: %S" command_template; ++ let cmd = PCRE.replace template_rex add_params command_template in ++ let r = shell_command cmd in ++ if r <> 0 then exit r; ++ ++ unlink (v2vdir // "convert"); ++ ++ (* Debug the v2vdir. *) ++ if verbose () then ( ++ let cmd = sprintf "ls -alZ %s 1>&2" (quote v2vdir) in ++ ignore (Sys.command cmd) ++ ); ++ ++ message (f_"Finishing off"); ++ (* As the last thing, write a file indicating success before ++ * we exit (so before we kill the helpers). The helpers may ++ * use the presence or absence of the file to determine if ++ * on-success or on-fail cleanup is required. ++ *) ++ with_open_out (v2vdir // "done") (fun _ -> ()) ++ ++(* Some input modules use large_tmpdir to unpack OVAs or store qcow2 ++ * overlays and some output modules use it to store temporary files. ++ * In addition the 500 MB guestfs appliance may be created there. ++ * (RHBZ#1316479, RHBZ#2051394) ++ *) ++and check_host_free_space () = ++ let free_space = StatVFS.free_space (StatVFS.statvfs large_tmpdir) in ++ debug "check_host_free_space: large_tmpdir=%s free_space=%Ld" ++ large_tmpdir free_space; ++ if free_space < 1_073_741_824L then ++ error (f_"insufficient free space in the conversion server \ ++ temporary directory %s (%s).\n\nEither free up space \ ++ in that directory, or set the LIBGUESTFS_CACHEDIR \ ++ environment variable to point to another directory \ ++ with more than 1GB of free space.\n\nSee also the \ ++ virt-v2v(1) manual, section \ ++ \"Minimum free space check in the host\".") ++ large_tmpdir (human_size free_space) ++ ++let () = run_main_and_handle_errors main +diff --git a/open/open.mli b/open/open.mli +new file mode 100644 +index 00000000..9fd556f6 +--- /dev/null ++++ b/open/open.mli +@@ -0,0 +1,19 @@ ++(* virt-v2v-open ++ * Copyright (C) 2009-2025 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. ++ *) ++ ++(* Nothing is exported. *) +diff --git a/run.in b/run.in +index c75e4e0f..93a0f20f 100755 +--- a/run.in ++++ b/run.in +@@ -71,6 +71,7 @@ chcon --reference=/tmp "$b/tmp" 2>/dev/null ||: + prepend PATH "$b/v2v" + prepend PATH "$b/in-place" + prepend PATH "$b/inspector" ++prepend PATH "$b/open" + export PATH + + # This is a cheap way to find some use-after-free and uninitialized +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 4d46daf9..97393d02 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -105,6 +105,8 @@ TESTS = \ + test-oa-option-raw.sh \ + test-of-option.sh \ + test-on-option.sh \ ++ test-open.sh \ ++ test-open-encrypted.sh \ + test-print-source.sh \ + test-rhbz1232192.sh \ + test-sound.sh \ +@@ -278,6 +280,8 @@ EXTRA_DIST += \ + test-oa-option-raw.sh \ + test-of-option.sh \ + test-on-option.sh \ ++ test-open.sh \ ++ test-open-encrypted.sh \ + test-print-source.expected \ + test-print-source.sh \ + test-rhbz1232192.sh \ +diff --git a/tests/test-open-encrypted.sh b/tests/test-open-encrypted.sh +new file mode 100755 +index 00000000..1ff14c31 +--- /dev/null ++++ b/tests/test-open-encrypted.sh +@@ -0,0 +1,56 @@ ++#!/bin/bash - ++# libguestfs virt-v2v test script ++# Copyright (C) 2014-2025 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 virt-v2v-show-roots with an encrypted guest. ++ ++unset CDPATH ++export LANG=C ++set -e ++ ++source ./functions.sh ++set -e ++set -x ++ ++skip_if_skipped ++f=../test-data/phony-guests/fedora-luks-on-lvm.img ++requires test -f $f ++ ++requires virt-inspector --version ++ ++d=$PWD/test-open-encrypted.d ++rm -rf $d ++cleanup_fn rm -r $d ++mkdir $d ++ ++out="$d/out" ++ ++keys="--key /dev/Volume-Group/Root:key:FEDORA-Root \ ++ --key /dev/Volume-Group/Logical-Volume-1:key:FEDORA-LV1 \ ++ --key /dev/Volume-Group/Logical-Volume-2:key:FEDORA-LV2 \ ++ --key /dev/Volume-Group/Logical-Volume-3:key:FEDORA-LV3" ++ ++$VG virt-v2v-open --debug-gc -i disk $f \ ++ --run "virt-inspector --format=raw @@ $keys > $out" ++cat $out ++ ++# Expect certain elements to be present. ++grep '^' $out ++grep '' $out ++grep '/dev/mapper/luks-' $out ++grep 'fedora' $out ++grep 'fedora14' $out +diff --git a/tests/test-open.sh b/tests/test-open.sh +new file mode 100755 +index 00000000..9eddfbc7 +--- /dev/null ++++ b/tests/test-open.sh +@@ -0,0 +1,77 @@ ++#!/bin/bash - ++# libguestfs virt-v2v test script ++# Copyright (C) 2014-2025 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 virt-v2v-open + virt-inspector. ++ ++unset CDPATH ++export LANG=C ++set -e ++ ++source ./functions.sh ++set -e ++set -x ++ ++skip_if_skipped ++img="$abs_top_builddir/test-data/phony-guests/windows.img" ++requires test -s $img ++ ++requires virt-inspector --version ++ ++export VIRT_TOOLS_DATA_DIR="$srcdir/../test-data/fake-virt-tools" ++export VIRTIO_WIN="$srcdir/../test-data/fake-virtio-win/drivers" ++ ++d=$PWD/test-open.d ++rm -rf $d ++cleanup_fn rm -r $d ++mkdir $d ++ ++out="$d/out" ++ ++libvirt_xml="$d/test.xml" ++rm -f $libvirt_xml ++n=windows ++cat > $libvirt_xml < ++ ++ $n ++ 1048576 ++ ++ hvm ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++EOF ++ ++$VG virt-v2v-open --debug-gc -i libvirt -ic "test://$libvirt_xml" $n \ ++ --run "virt-inspector --format=raw @@ > $out" ++cat $out ++ ++# Expect certain elements to be present. ++grep '^' $out ++grep '' $out ++grep '/dev/sda2' $out ++grep 'windows' $out ++grep 'win2k22' $out diff --git a/virt-v2v.spec b/virt-v2v.spec index d4b5af2..ef8a5b7 100644 --- a/virt-v2v.spec +++ b/virt-v2v.spec @@ -8,7 +8,7 @@ Name: virt-v2v Epoch: 1 Version: 2.7.1 -Release: 10%{?dist} +Release: 11%{?dist} Summary: Convert a virtual machine to run on KVM License: GPL-2.0-or-later AND LGPL-2.0-or-later @@ -77,6 +77,11 @@ Patch0046: 0046-v2v-Remove-no-trim-and-vmtype-options.patch Patch0047: 0047-v2v-Remove-password-file-option.patch Patch0048: 0048-input-nbdkit_vddk.ml-Rename-path-parameter-to-file.patch Patch0049: 0049-input-Add-io-vddk-file-.-option.patch +Patch0050: 0050-inspector-Simplify-input-bandwidth-code.patch +Patch0051: 0051-docs-Rearrange-root-titles.patch +Patch0052: 0052-docs-Clarify-root-first-documentation.patch +Patch0053: 0053-docs-Remove-old-paragraph-about-a-bug-in-Grub.patch +Patch0054: 0054-Add-new-virt-v2v-open-tool.patch %if !0%{?rhel} # libguestfs hasn't been built on i686 for a while since there is no @@ -345,6 +350,7 @@ make -C tests TESTS=test-fedora-luks-on-lvm-conversion.sh check %{_libexecdir}/virt-v2v-in-place %endif %{_bindir}/virt-v2v-inspector +%{_bindir}/virt-v2v-open %{_mandir}/man1/virt-v2v.1* %{_mandir}/man1/virt-v2v-hacking.1* %{_mandir}/man1/virt-v2v-input-vmware.1* @@ -353,6 +359,7 @@ make -C tests TESTS=test-fedora-luks-on-lvm-conversion.sh check %{_mandir}/man1/virt-v2v-in-place.1* %endif %{_mandir}/man1/virt-v2v-inspector.1* +%{_mandir}/man1/virt-v2v-open.1* %{_mandir}/man1/virt-v2v-output-local.1* %{_mandir}/man1/virt-v2v-output-openstack.1* %{_mandir}/man1/virt-v2v-output-rhv.1* @@ -378,7 +385,7 @@ make -C tests TESTS=test-fedora-luks-on-lvm-conversion.sh check %changelog -* Tue Apr 29 2025 Richard W.M. Jones - 1:2.7.1-10 +* Wed May 07 2025 Richard W.M. Jones - 1:2.7.1-11 - mlcustomize: Remove dnf --verbose option resolves: RHEL-83289 - Print blkhash of converted image in virt-v2v debugging output @@ -395,6 +402,8 @@ make -C tests TESTS=test-fedora-luks-on-lvm-conversion.sh check resolves: RHEL-88863 - Remove several ancient, deprecated options resolves: RHEL-88866 +- New tool: virt-v2v-open + resolves: RHEL-88985 * Tue Feb 25 2025 Richard W.M. Jones - 1:2.7.1-5 - Rebase to upstream development version 2.7.1