From d1145f20cbba96dab728b04e50a4cb074193ee89 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 23 Sep 2014 12:22:26 +0100 Subject: [PATCH] v2v: Add -o qemu output mode and --qemu-boot flag. This lets you write a shell script that runs the guest under qemu. Specifying the --qemu-boot flag also boots the guest after conversion. --- po/POTFILES-ml | 1 + v2v/Makefile.am | 3 ++ v2v/cmdline.ml | 22 +++++++++ v2v/output_qemu.ml | 103 +++++++++++++++++++++++++++++++++++++++++ v2v/output_qemu.mli | 24 ++++++++++ v2v/test-v2v-o-qemu.sh | 64 +++++++++++++++++++++++++ v2v/virt-v2v.pod | 42 +++++++++++++---- 7 files changed, 251 insertions(+), 8 deletions(-) create mode 100644 v2v/output_qemu.ml create mode 100644 v2v/output_qemu.mli create mode 100755 v2v/test-v2v-o-qemu.sh diff --git a/po/POTFILES-ml b/po/POTFILES-ml index de37bf7dd..8fd0f86bc 100644 --- a/po/POTFILES-ml +++ b/po/POTFILES-ml @@ -102,6 +102,7 @@ v2v/output_glance.ml v2v/output_libvirt.ml v2v/output_local.ml v2v/output_null.ml +v2v/output_qemu.ml v2v/output_rhev.ml v2v/output_vdsm.ml v2v/stringMap.ml diff --git a/v2v/Makefile.am b/v2v/Makefile.am index 4b57acabd..e9620bd0e 100644 --- a/v2v/Makefile.am +++ b/v2v/Makefile.am @@ -47,6 +47,7 @@ SOURCES_MLI = \ output_libvirt.mli \ output_local.mli \ output_null.mli \ + output_qemu.mli \ output_rhev.mli \ output_vdsm.mli \ stringMap.mli \ @@ -77,6 +78,7 @@ SOURCES_ML = \ output_glance.ml \ output_libvirt.ml \ output_local.ml \ + output_qemu.ml \ output_rhev.ml \ output_vdsm.ml \ cmdline.ml \ @@ -222,6 +224,7 @@ TESTS = \ test-v2v-o-glance.sh \ test-v2v-o-libvirt.sh \ test-v2v-o-null.sh \ + test-v2v-o-qemu.sh \ test-v2v-o-rhev.sh \ test-v2v-o-vdsm-options.sh \ test-v2v-of-option.sh \ diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml index 67927a105..1e059fce9 100644 --- a/v2v/cmdline.ml +++ b/v2v/cmdline.ml @@ -42,6 +42,7 @@ let parse_cmdline () = let output_name = ref "" in let output_storage = ref "" in let print_source = ref false in + let qemu_boot = ref false in let quiet = ref false in let vdsm_image_uuid = ref "" in let vdsm_vm_uuid = ref "" in @@ -85,6 +86,7 @@ let parse_cmdline () = | "disk" | "local" -> output_mode := `Local | "null" -> output_mode := `Null | "ovirt" | "rhev" -> output_mode := `RHEV + | "qemu" -> output_mode := `QEmu | "vdsm" -> output_mode := `VDSM | s -> error (f_"unknown -o option: %s") s @@ -135,6 +137,7 @@ let parse_cmdline () = "-on", Arg.Set_string output_name, "name " ^ s_"Rename guest when converting"; "-os", Arg.Set_string output_storage, "storage " ^ s_"Set output storage location"; "--print-source", Arg.Set print_source, " " ^ s_"Print source and stop"; + "--qemu-boot", Arg.Set qemu_boot, " " ^ s_"Boot in qemu (-o qemu only)"; "-q", Arg.Set quiet, " " ^ s_"Quiet output"; "--quiet", Arg.Set quiet, ditto; "--root", Arg.String set_root_choice,"ask|... " ^ s_"How to choose root filesystem"; @@ -194,6 +197,7 @@ read the man page virt-v2v(1). let output_name = match !output_name with "" -> None | s -> Some s in let output_storage = !output_storage in let print_source = !print_source in + let qemu_boot = !qemu_boot in let quiet = !quiet in let root_choice = !root_choice in let vdsm_image_uuid = !vdsm_image_uuid in @@ -271,6 +275,8 @@ read the man page virt-v2v(1). error (f_"-o glance: -oc option cannot be used in this output mode"); if output_storage <> "" then error (f_"-o glance: -os option cannot be used in this output mode"); + if qemu_boot then + error (f_"-o glance: --qemu-boot option cannot be used in this output mode"); if vmtype <> None then error (f_"--vmtype option cannot be used with '-o glance'"); if not do_copy then @@ -281,6 +287,8 @@ read the man page virt-v2v(1). | `Libvirt -> let output_storage = if output_storage = "" then "default" else output_storage in + if qemu_boot then + error (f_"-o libvirt: --qemu-boot option cannot be used in this output mode"); if vmtype <> None then error (f_"--vmtype option cannot be used with '-o libvirt'"); if not do_copy then @@ -293,6 +301,8 @@ read the man page virt-v2v(1). if not (is_directory output_storage) then error (f_"-os %s: output directory does not exist or is not a directory") output_storage; + if qemu_boot then + error (f_"-o local: --qemu-boot option cannot be used in this output mode"); if vmtype <> None then error (f_"--vmtype option cannot be used with '-o local'"); Output_local.output_local verbose output_storage @@ -302,18 +312,30 @@ read the man page virt-v2v(1). error (f_"-o null: -oc option cannot be used in this output mode"); if output_storage <> "" then error (f_"-o null: -os option cannot be used in this output mode"); + if qemu_boot then + error (f_"-o null: --qemu-boot option cannot be used in this output mode"); if vmtype <> None then error (f_"--vmtype option cannot be used with '-o null'"); Output_null.output_null verbose + | `QEmu -> + if not (is_directory output_storage) then + error (f_"-os %s: output directory does not exist or is not a directory") + output_storage; + Output_qemu.output_qemu verbose output_storage qemu_boot + | `RHEV -> if output_storage = "" then error (f_"-o rhev: output storage was not specified, use '-os'"); + if qemu_boot then + error (f_"-o rhev: --qemu-boot option cannot be used in this output mode"); Output_rhev.output_rhev verbose output_storage vmtype output_alloc | `VDSM -> if output_storage = "" then error (f_"-o vdsm: output storage was not specified, use '-os'"); + if qemu_boot then + error (f_"-o vdsm: --qemu-boot option cannot be used in this output mode"); if vdsm_image_uuid = "" || vdsm_vm_uuid = "" then error (f_"-o vdsm: either --vdsm-image-uuid or --vdsm-vm-uuid was not specified"); let vdsm_params = { diff --git a/v2v/output_qemu.ml b/v2v/output_qemu.ml new file mode 100644 index 000000000..fafc9b825 --- /dev/null +++ b/v2v/output_qemu.ml @@ -0,0 +1,103 @@ +(* virt-v2v + * Copyright (C) 2009-2014 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_gettext.Gettext +open Common_utils + +open Types +open Utils + +class output_qemu verbose dir qemu_boot = +object + inherit output verbose + + method as_options = + sprintf "-o qemu -os %s%s" dir (if qemu_boot then " --qemu-boot" else "") + + method prepare_targets source targets = + List.map ( + fun t -> + let target_file = dir // source.s_name ^ "-" ^ t.target_overlay.ov_sd in + { t with target_file = target_file } + ) targets + + method create_metadata source targets guestcaps _ = + let name = source.s_name in + let file = dir // name ^ ".sh" in + + let chan = open_out file in + + let fpf fs = fprintf chan fs in + fpf "#!/bin/sh -\n"; + fpf "\n"; + fpf "qemu-system-%s \\\n" guestcaps.gcaps_arch; + fpf "\t-no-user-config -nodefaults \\\n"; + fpf "\t-name %s \\\n" (quote source.s_name); + fpf "\t-machine accel=kvm:tcg \\\n"; + fpf "\t-m %Ld \\\n" (source.s_memory /^ 1024L /^ 1024L); + if source.s_vcpu > 1 then + fpf "\t-smp %d \\\n" source.s_vcpu; + + let block_bus = + match guestcaps.gcaps_block_bus with + | Virtio_blk -> "virtio" + | IDE -> "ide" in + List.iter ( + fun t -> + let qemu_quoted_filename = replace_str t.target_file "," ",," in + let drive_param = + sprintf "file=%s,format=%s,if=%s" + qemu_quoted_filename t.target_format block_bus in + fpf "\t-drive %s\\\n" (quote drive_param) + ) targets; + + let net_bus = + match guestcaps.gcaps_net_bus with + | Virtio_net -> "virtio-net-pci" + | E1000 -> "e1000" + | RTL8139 -> "rtl8139" in + List.iteri ( + fun i nic -> + fpf "\t-netdev user,id=net%d \\\n" i; + fpf "\t-device %s,netdev=net%d%s \\\n" + net_bus i (match nic.s_mac with None -> "" | Some mac -> ",mac=" ^ mac) + ) source.s_nics; + + (* Add a serial console. *) + fpf "\t-serial stdio\n"; + + (* XXX Missing: + * - removable devices + * - display + *) + + close_out chan; + + Unix.chmod file 0o755; + + (* If --qemu-boot option was specified then we should boot the guest. *) + if qemu_boot then ( + let cmd = sprintf "%s &" (quote file) in + ignore (Sys.command cmd) + ) +end + +let output_qemu = new output_qemu +let () = Modules_list.register_output_module "qemu" diff --git a/v2v/output_qemu.mli b/v2v/output_qemu.mli new file mode 100644 index 000000000..91c37c5bd --- /dev/null +++ b/v2v/output_qemu.mli @@ -0,0 +1,24 @@ +(* virt-v2v + * Copyright (C) 2009-2014 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. + *) + +(** [-o qemu] target. *) + +val output_qemu : bool -> string -> bool -> Types.output +(** [output_qemu verbose filename qemu_boot] creates and returns a new + {!Types.output} object specialized for writing output to local + files with a qemu script to start the guest locally. *) diff --git a/v2v/test-v2v-o-qemu.sh b/v2v/test-v2v-o-qemu.sh new file mode 100755 index 000000000..9de2b5631 --- /dev/null +++ b/v2v/test-v2v-o-qemu.sh @@ -0,0 +1,64 @@ +#!/bin/bash - +# libguestfs virt-v2v test script +# Copyright (C) 2014 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 -o qemu. + +unset CDPATH +export LANG=C +set -e + +if [ -n "$SKIP_TEST_V2V_O_QEMU_SH" ]; then + echo "$0: test skipped because environment variable is set" + exit 77 +fi + +if [ "$(guestfish get-backend)" = "uml" ]; then + echo "$0: test skipped because UML backend does not support network" + exit 77 +fi + +abs_top_builddir="$(cd ..; pwd)" +libvirt_uri="test://$abs_top_builddir/tests/guests/guests.xml" + +f=../tests/guests/windows.img +if ! test -f $f || ! test -s $f; then + echo "$0: test skipped because phony Windows image was not created" + exit 77 +fi + +virt_tools_data_dir=${VIRT_TOOLS_DATA_DIR:-/usr/share/virt-tools} +if ! test -r $virt_tools_data_dir/rhsrvany.exe; then + echo "$0: test skipped because rhsrvany.exe is not installed" + exit 77 +fi + +d=test-v2v-o-qemu.d +rm -rf $d +mkdir $d + +$VG virt-v2v --debug-gc \ + -i libvirt -ic "$libvirt_uri" windows \ + -o qemu -os $d + +# Test that the disk was created. +test -f $d/windows-sda + +# Test that the script was created and is executable. +test -x $d/windows.sh + +rm -r $d diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod index 1230fe4ce..d90ad1bb0 100644 --- a/v2v/virt-v2v.pod +++ b/v2v/virt-v2v.pod @@ -31,12 +31,12 @@ libguestfs E 1.28. =head1 INPUT AND OUTPUT MODES ┌────────────┐ ┌─────────▶ -o null - -i disk ───────────┐ │ │ │┌───────▶ -o local - -i ova ─────────┐ └──▶ │ virt-v2v │ ─┘│ - └────▶ │ conversion │ ──┘┌────────────┐ - ESX ──▶┌────────────┐ │ server │ ───▶ -o libvirt │─▶ KVM - Xen ──▶│ -i libvirt ──▶ │ │ │ (default) │ - ... ──▶│ (default) │ │ │ ──┐└────────────┘ + -i disk ───────────┐ │ │ ─┘┌───────▶ -o local + -i ova ─────────┐ └──▶ │ virt-v2v │ ──┘┌───────▶ -o qemu + └────▶ │ conversion │ ───┘┌────────────┐ + ESX ──▶┌────────────┐ │ server │ ────▶ -o libvirt │─▶ KVM + Xen ──▶│ -i libvirt ──▶ │ │ │ (default) │ + ... ──▶│ (default) │ │ │ ──┐ └────────────┘ └────────────┘ │ │ ─┐└──────▶ -o glance -i libvirtxml ────────▶ │ │ ┐└─────────▶ -o rhev └────────────┘ └──────────▶ -o vdsm @@ -64,7 +64,11 @@ I<-o libvirt> is used for writing to any libvirt target. Libvirt can connect to local or remote KVM hypervisors. The I<-oc> option selects the precise libvirt target. -I<-o local> is used to write to a local disk image (mainly for testing). +I<-o local> is used to write to a local disk image with a local +libvirt configuration file (mainly for testing). + +I<-o qemu> writes to a local disk image with a shell script for +booting the guest directly in qemu (mainly for testing). I<-o rhev> is used to write to a RHEV-M / oVirt target. I<-o vdsm> is only used when virt-v2v runs under VDSM control. @@ -134,6 +138,11 @@ Since C contains the path(s) to the guest disk image(s) you do not need to specify the name of the disk image on the command line. +To convert a local disk image and immediately boot it in local +qemu, do: + + virt-v2v -i disk disk.img -o qemu -os /var/tmp --qemu-boot + =head1 OPTIONS =over 4 @@ -293,6 +302,17 @@ written. This is the same as I<-o rhev>. +=item B<-o qemu> + +Set the output method to I. + +This is similar to I<-o local>, except that a shell script is written +which you can use to boot the guest in qemu. The converted disks and +shell script are written to the directory specified by I<-os>. + +When using this output mode, you can also specify the I<--qemu-boot> +option which boots the guest under qemu immediately. + =item B<-o rhev> Set the output method to I. @@ -341,7 +361,8 @@ The location of the storage for the converted guest. For I<-o libvirt>, this is a libvirt directory pool (see S>) or pool UUID. -For I<-o local>, this is a directory name. The directory must exist. +For I<-o local> and I<-o qemu>, this is a directory name. The +directory must exist. For I<-o rhev>, this can be an NFS path of the Export Storage Domain of the form ChostE:EpathE>, eg: @@ -366,6 +387,11 @@ Print information about the source guest and stop. This option is useful when you are setting up network and bridge maps. See L. +=item B<--qemu-boot> + +When using I<-o qemu> only, this boots the guest immediately after +virt-v2v finishes. + =item B<-q> =item B<--quiet>