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