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.
This commit is contained in:
Richard W.M. Jones
2014-09-23 12:22:26 +01:00
parent 91c1f58e21
commit d1145f20cb
7 changed files with 251 additions and 8 deletions

View File

@@ -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

View File

@@ -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 \

View File

@@ -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 = {

103
v2v/output_qemu.ml Normal file
View File

@@ -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"

24
v2v/output_qemu.mli Normal file
View File

@@ -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. *)

64
v2v/test-v2v-o-qemu.sh Executable file
View File

@@ -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

View File

@@ -31,12 +31,12 @@ libguestfs E<ge> 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<guest-domain.xml> 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<qemu>.
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<rhev>.
@@ -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<C<virsh pool-list>>) 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 C<E<lt>hostE<gt>:E<lt>pathE<gt>>, 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</NETWORKS AND BRIDGES>.
=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>