From 0b4a72fd77f74e5a9f6885179febe601156df617 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Wed, 5 Feb 2014 19:09:26 -0500 Subject: [PATCH] virt-convert: Reimplement it We totally break CLI compat here, but the previous tool wasn't sustainable. Instead, repurpose the tool as strictly converting external formats like ovf/vmx to native libvirt XML, and launch the guest. So we drop vmx/virt-image output, and virt-image input, and a slew of command line options. I don't think anyone was depending on this in a scripted fashion, so in practice I don't think anyone will care. Add much more comprehensive unit tests while we are at it. --- man/virt-convert.pod | 122 ++--- man/virt-install.pod | 2 +- .../cli-test-xml/compare/convert-default.xml | 5 - ...e-auto1.xml => virt-clone-clone-auto1.xml} | 0 ...e-auto2.xml => virt-clone-clone-auto2.xml} | 0 .../compare/virt-convert-ovf-compare.xml | 69 +++ .../compare/virt-convert-vmx-compare.xml | 65 +++ ...e-boot0.xml => virt-image-image-boot0.xml} | 0 ...e-boot1.xml => virt-image-image-boot1.xml} | 0 ...e-nogfx.xml => virt-image-image-nogfx.xml} | 0 ....xml => virt-install-arm-vexpress-f19.xml} | 0 ...ml => virt-install-arm-vexpress-plain.xml} | 0 ...-auto.xml => virt-install-cpuset-auto.xml} | 0 .../{default.xml => virt-install-default.xml} | 0 ...efault.xml => virt-install-fs-default.xml} | 0 ...4-url.xml => virt-install-kvm-f14-url.xml} | 0 ...chine.xml => virt-install-kvm-machine.xml} | 0 ....xml => virt-install-kvm-win2k3-cdrom.xml} | 0 ...xenner.xml => virt-install-kvm-xenner.xml} | 0 ...-init.xml => virt-install-manual-init.xml} | 0 ...ices.xml => virt-install-many-devices.xml} | 0 ...-fail.xml => virt-install-noargs-fail.xml} | 0 ...xml => virt-install-ppc64-pseries-f20.xml} | 0 ...-64.xml => virt-install-qemu-32-on-64.xml} | 0 ...-plain.xml => virt-install-qemu-plain.xml} | 0 ...-sparc.xml => virt-install-qemu-sparc.xml} | 0 ...iet-url.xml => virt-install-quiet-url.xml} | 0 ...le-pxe.xml => virt-install-simple-pxe.xml} | 0 ...-cdrom.xml => virt-install-w2k3-cdrom.xml} | 0 ...fault.xml => virt-install-xen-default.xml} | 0 .../{xen-hvm.xml => virt-install-xen-hvm.xml} | 0 ....xml => virt-install-xen-ia64-default.xml} | 0 ...-hvm.xml => virt-install-xen-ia64-hvm.xml} | 0 ...64-pv.xml => virt-install-xen-ia64-pv.xml} | 0 .../{xen-pv.xml => virt-install-xen-pv.xml} | 0 ...-basic.xml => virt-xml-add-disk-basic.xml} | 0 ...l => virt-xml-add-disk-create-storage.xml} | 0 ...get.xml => virt-xml-add-disk-notarget.xml} | 0 ...evice.xml => virt-xml-add-host-device.xml} | 0 ...l-add-sound.xml => virt-xml-add-sound.xml} | 0 ...otune.xml => virt-xml-build-blkiotune.xml} | 0 ...l-build-cpu.xml => virt-xml-build-cpu.xml} | 0 ...l-build-tpm.xml => virt-xml-build-tpm.xml} | 0 ...xml-edit-all.xml => virt-xml-edit-all.xml} | 0 ...lock.xml => virt-xml-edit-clear-clock.xml} | 0 ...ar-cpu.xml => virt-xml-edit-clear-cpu.xml} | 0 ...-disk.xml => virt-xml-edit-clear-disk.xml} | 0 ...-neg-num.xml => virt-xml-edit-neg-num.xml} | 0 ...-pos-num.xml => virt-xml-edit-pos-num.xml} | 0 ...xml => virt-xml-edit-select-disk-path.xml} | 0 ...l => virt-xml-edit-select-disk-target.xml} | 0 ...l => virt-xml-edit-select-network-mac.xml} | 0 ...l => virt-xml-edit-select-sound-model.xml} | 0 ...xml => virt-xml-edit-simple-blkiotune.xml} | 0 ...boot.xml => virt-xml-edit-simple-boot.xml} | 0 ...l.xml => virt-xml-edit-simple-channel.xml} | 0 ...ock.xml => virt-xml-edit-simple-clock.xml} | 0 ...e.xml => virt-xml-edit-simple-console.xml} | 0 ...ml => virt-xml-edit-simple-controller.xml} | 0 ...e-cpu.xml => virt-xml-edit-simple-cpu.xml} | 0 ...virt-xml-edit-simple-disk-remove-path.xml} | 0 ...disk.xml => virt-xml-edit-simple-disk.xml} | 0 ....xml => virt-xml-edit-simple-features.xml} | 0 ...ml => virt-xml-edit-simple-filesystem.xml} | 0 ....xml => virt-xml-edit-simple-graphics.xml} | 0 ...l => virt-xml-edit-simple-host-device.xml} | 0 ...ml => virt-xml-edit-simple-memballoon.xml} | 0 ...ry.xml => virt-xml-edit-simple-memory.xml} | 0 ....xml => virt-xml-edit-simple-metadata.xml} | 0 ...k.xml => virt-xml-edit-simple-network.xml} | 0 ....xml => virt-xml-edit-simple-numatune.xml} | 0 ....xml => virt-xml-edit-simple-parallel.xml} | 0 ...ple-pm.xml => virt-xml-edit-simple-pm.xml} | 0 ....xml => virt-xml-edit-simple-redirdev.xml} | 0 ...e-rng.xml => virt-xml-edit-simple-rng.xml} | 0 ....xml => virt-xml-edit-simple-security.xml} | 0 ...al.xml => virt-xml-edit-simple-serial.xml} | 0 ...xml => virt-xml-edit-simple-smartcard.xml} | 0 ...w.xml => virt-xml-edit-simple-soundhw.xml} | 0 ...e-tpm.xml => virt-xml-edit-simple-tpm.xml} | 0 ...pus.xml => virt-xml-edit-simple-vcpus.xml} | 0 ...deo.xml => virt-xml-edit-simple-video.xml} | 0 ....xml => virt-xml-edit-simple-watchdog.xml} | 0 ...l-print-xml.xml => virt-xml-print-xml.xml} | 0 ...dex.xml => virt-xml-remove-disk-index.xml} | 0 ...path.xml => virt-xml-remove-disk-path.xml} | 0 ...el.xml => virt-xml-remove-sound-model.xml} | 0 ...-all.xml => virt-xml-remove-video-all.xml} | 0 ...stdin-edit.xml => virt-xml-stdin-edit.xml} | 0 .../data.raw => ovf/test.ovf-disk1.vmdk} | 0 tests/cli-test-xml/virtconv/ovf/test1.ovf | 123 +++++ .../{virtimage/root.raw => ovf/testfile} | 0 .../virtconv/virtimage/scratch.raw | 0 .../virtconv/virtimage/test1.virt-image | 48 -- tests/clitest.py | 153 +++--- .../ovf2libvirt_ovf_directory.libvirt | 64 +++ .../libvirt_output/ovf2libvirt_test1.libvirt | 71 +++ .../ovf2libvirt_test1.libvirt.disk_qcow2 | 71 +++ .../libvirt_output/ovf2libvirt_test2.libvirt | 65 +++ .../vmx2libvirt_test-vmx-zip.libvirt | 70 +++ .../libvirt_output/vmx2libvirt_test1.libvirt | 67 +++ .../vmx2libvirt_test1.libvirt.disk_raw | 67 +++ .../vmx2libvirt_vmx-dir.libvirt | 68 +++ .../CentOS-6.4-i386-Gnome-disk1.vmdk | Bin 0 -> 10480 bytes .../ovf_directory/CentOS-6.4-i386-Gnome.ovf | 263 +++++++++++ .../virtimage_input/test1.virt-image | 48 -- .../virtimage_output/convert-qcow2.virt-image | 25 - .../ovf2virtimage_test1.virt-image | 27 -- .../ovf2virtimage_test2.virt-image | 25 - .../virtimage_output/test1.virt-image | 29 -- .../vmx2virtimage_test-vmdk-desc.virt-image | 25 - .../vmx2virtimage_test1.virt-image | 25 - .../virtconv-files/vmx_input/test-vmx-zip.zip | Bin 0 -> 2130 bytes .../{ => vmx-dir}/test-vmdk-desc.vmdk | 0 .../{ => vmx-dir}/test-vmdk-desc.vmx | 0 .../vmx_output/virtimage2vmx_test1.vmx | 62 --- tests/virtconvtest.py | 132 ++---- virt-convert | 292 +++--------- virt-install | 86 +--- virtconv/__init__.py | 18 +- virtconv/diskcfg.py | 316 ------------- virtconv/formats.py | 270 ++++++++--- virtconv/netdevcfg.py | 42 -- virtconv/ovf.py | 386 +++++++++++++++ virtconv/parsers/__init__.py | 1 - virtconv/parsers/ovf.py | 439 ------------------ virtconv/parsers/virtimage.py | 320 ------------- virtconv/vmcfg.py | 82 ---- virtconv/{parsers => }/vmx.py | 260 ++++------- virtinst/cli.py | 80 +++- virtinst/connection.py | 10 +- virtinst/guest.py | 3 +- virtinst/storage.py | 37 +- virtinst/util.py | 28 +- 134 files changed, 2114 insertions(+), 2347 deletions(-) delete mode 100644 tests/cli-test-xml/compare/convert-default.xml rename tests/cli-test-xml/compare/{clone-auto1.xml => virt-clone-clone-auto1.xml} (100%) rename tests/cli-test-xml/compare/{clone-auto2.xml => virt-clone-clone-auto2.xml} (100%) create mode 100644 tests/cli-test-xml/compare/virt-convert-ovf-compare.xml create mode 100644 tests/cli-test-xml/compare/virt-convert-vmx-compare.xml rename tests/cli-test-xml/compare/{image-boot0.xml => virt-image-image-boot0.xml} (100%) rename tests/cli-test-xml/compare/{image-boot1.xml => virt-image-image-boot1.xml} (100%) rename tests/cli-test-xml/compare/{image-nogfx.xml => virt-image-image-nogfx.xml} (100%) rename tests/cli-test-xml/compare/{arm-vexpress-f19.xml => virt-install-arm-vexpress-f19.xml} (100%) rename tests/cli-test-xml/compare/{arm-vexpress-plain.xml => virt-install-arm-vexpress-plain.xml} (100%) rename tests/cli-test-xml/compare/{cpuset-auto.xml => virt-install-cpuset-auto.xml} (100%) rename tests/cli-test-xml/compare/{default.xml => virt-install-default.xml} (100%) rename tests/cli-test-xml/compare/{fs-default.xml => virt-install-fs-default.xml} (100%) rename tests/cli-test-xml/compare/{kvm-f14-url.xml => virt-install-kvm-f14-url.xml} (100%) rename tests/cli-test-xml/compare/{kvm-machine.xml => virt-install-kvm-machine.xml} (100%) rename tests/cli-test-xml/compare/{kvm-win2k3-cdrom.xml => virt-install-kvm-win2k3-cdrom.xml} (100%) rename tests/cli-test-xml/compare/{kvm-xenner.xml => virt-install-kvm-xenner.xml} (100%) rename tests/cli-test-xml/compare/{manual-init.xml => virt-install-manual-init.xml} (100%) rename tests/cli-test-xml/compare/{many-devices.xml => virt-install-many-devices.xml} (100%) rename tests/cli-test-xml/compare/{noargs-fail.xml => virt-install-noargs-fail.xml} (100%) rename tests/cli-test-xml/compare/{ppc64-pseries-f20.xml => virt-install-ppc64-pseries-f20.xml} (100%) rename tests/cli-test-xml/compare/{qemu-32-on-64.xml => virt-install-qemu-32-on-64.xml} (100%) rename tests/cli-test-xml/compare/{qemu-plain.xml => virt-install-qemu-plain.xml} (100%) rename tests/cli-test-xml/compare/{qemu-sparc.xml => virt-install-qemu-sparc.xml} (100%) rename tests/cli-test-xml/compare/{quiet-url.xml => virt-install-quiet-url.xml} (100%) rename tests/cli-test-xml/compare/{simple-pxe.xml => virt-install-simple-pxe.xml} (100%) rename tests/cli-test-xml/compare/{w2k3-cdrom.xml => virt-install-w2k3-cdrom.xml} (100%) rename tests/cli-test-xml/compare/{xen-default.xml => virt-install-xen-default.xml} (100%) rename tests/cli-test-xml/compare/{xen-hvm.xml => virt-install-xen-hvm.xml} (100%) rename tests/cli-test-xml/compare/{xen-ia64-default.xml => virt-install-xen-ia64-default.xml} (100%) rename tests/cli-test-xml/compare/{xen-ia64-hvm.xml => virt-install-xen-ia64-hvm.xml} (100%) rename tests/cli-test-xml/compare/{xen-ia64-pv.xml => virt-install-xen-ia64-pv.xml} (100%) rename tests/cli-test-xml/compare/{xen-pv.xml => virt-install-xen-pv.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-add-disk-basic.xml => virt-xml-add-disk-basic.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-add-disk-create-storage.xml => virt-xml-add-disk-create-storage.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-add-disk-notarget.xml => virt-xml-add-disk-notarget.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-add-host-device.xml => virt-xml-add-host-device.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-add-sound.xml => virt-xml-add-sound.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-build-blkiotune.xml => virt-xml-build-blkiotune.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-build-cpu.xml => virt-xml-build-cpu.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-build-tpm.xml => virt-xml-build-tpm.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-all.xml => virt-xml-edit-all.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-clear-clock.xml => virt-xml-edit-clear-clock.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-clear-cpu.xml => virt-xml-edit-clear-cpu.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-clear-disk.xml => virt-xml-edit-clear-disk.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-neg-num.xml => virt-xml-edit-neg-num.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-pos-num.xml => virt-xml-edit-pos-num.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-select-disk-path.xml => virt-xml-edit-select-disk-path.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-select-disk-target.xml => virt-xml-edit-select-disk-target.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-select-network-mac.xml => virt-xml-edit-select-network-mac.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-select-sound-model.xml => virt-xml-edit-select-sound-model.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-blkiotune.xml => virt-xml-edit-simple-blkiotune.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-boot.xml => virt-xml-edit-simple-boot.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-channel.xml => virt-xml-edit-simple-channel.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-clock.xml => virt-xml-edit-simple-clock.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-console.xml => virt-xml-edit-simple-console.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-controller.xml => virt-xml-edit-simple-controller.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-cpu.xml => virt-xml-edit-simple-cpu.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-disk-remove-path.xml => virt-xml-edit-simple-disk-remove-path.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-disk.xml => virt-xml-edit-simple-disk.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-features.xml => virt-xml-edit-simple-features.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-filesystem.xml => virt-xml-edit-simple-filesystem.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-graphics.xml => virt-xml-edit-simple-graphics.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-host-device.xml => virt-xml-edit-simple-host-device.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-memballoon.xml => virt-xml-edit-simple-memballoon.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-memory.xml => virt-xml-edit-simple-memory.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-metadata.xml => virt-xml-edit-simple-metadata.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-network.xml => virt-xml-edit-simple-network.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-numatune.xml => virt-xml-edit-simple-numatune.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-parallel.xml => virt-xml-edit-simple-parallel.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-pm.xml => virt-xml-edit-simple-pm.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-redirdev.xml => virt-xml-edit-simple-redirdev.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-rng.xml => virt-xml-edit-simple-rng.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-security.xml => virt-xml-edit-simple-security.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-serial.xml => virt-xml-edit-simple-serial.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-smartcard.xml => virt-xml-edit-simple-smartcard.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-soundhw.xml => virt-xml-edit-simple-soundhw.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-tpm.xml => virt-xml-edit-simple-tpm.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-vcpus.xml => virt-xml-edit-simple-vcpus.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-video.xml => virt-xml-edit-simple-video.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-edit-simple-watchdog.xml => virt-xml-edit-simple-watchdog.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-print-xml.xml => virt-xml-print-xml.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-remove-disk-index.xml => virt-xml-remove-disk-index.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-remove-disk-path.xml => virt-xml-remove-disk-path.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-remove-sound-model.xml => virt-xml-remove-sound-model.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-remove-video-all.xml => virt-xml-remove-video-all.xml} (100%) rename tests/cli-test-xml/compare/{virtxml-stdin-edit.xml => virt-xml-stdin-edit.xml} (100%) rename tests/cli-test-xml/virtconv/{virtimage/data.raw => ovf/test.ovf-disk1.vmdk} (100%) create mode 100644 tests/cli-test-xml/virtconv/ovf/test1.ovf rename tests/cli-test-xml/virtconv/{virtimage/root.raw => ovf/testfile} (100%) delete mode 100644 tests/cli-test-xml/virtconv/virtimage/scratch.raw delete mode 100644 tests/cli-test-xml/virtconv/virtimage/test1.virt-image create mode 100644 tests/virtconv-files/libvirt_output/ovf2libvirt_ovf_directory.libvirt create mode 100644 tests/virtconv-files/libvirt_output/ovf2libvirt_test1.libvirt create mode 100644 tests/virtconv-files/libvirt_output/ovf2libvirt_test1.libvirt.disk_qcow2 create mode 100644 tests/virtconv-files/libvirt_output/ovf2libvirt_test2.libvirt create mode 100644 tests/virtconv-files/libvirt_output/vmx2libvirt_test-vmx-zip.libvirt create mode 100644 tests/virtconv-files/libvirt_output/vmx2libvirt_test1.libvirt create mode 100644 tests/virtconv-files/libvirt_output/vmx2libvirt_test1.libvirt.disk_raw create mode 100644 tests/virtconv-files/libvirt_output/vmx2libvirt_vmx-dir.libvirt create mode 100644 tests/virtconv-files/ovf_input/ovf_directory/CentOS-6.4-i386-Gnome-disk1.vmdk create mode 100644 tests/virtconv-files/ovf_input/ovf_directory/CentOS-6.4-i386-Gnome.ovf delete mode 100644 tests/virtconv-files/virtimage_input/test1.virt-image delete mode 100644 tests/virtconv-files/virtimage_output/convert-qcow2.virt-image delete mode 100644 tests/virtconv-files/virtimage_output/ovf2virtimage_test1.virt-image delete mode 100644 tests/virtconv-files/virtimage_output/ovf2virtimage_test2.virt-image delete mode 100644 tests/virtconv-files/virtimage_output/test1.virt-image delete mode 100644 tests/virtconv-files/virtimage_output/vmx2virtimage_test-vmdk-desc.virt-image delete mode 100644 tests/virtconv-files/virtimage_output/vmx2virtimage_test1.virt-image create mode 100644 tests/virtconv-files/vmx_input/test-vmx-zip.zip rename tests/virtconv-files/vmx_input/{ => vmx-dir}/test-vmdk-desc.vmdk (100%) rename tests/virtconv-files/vmx_input/{ => vmx-dir}/test-vmdk-desc.vmx (100%) delete mode 100644 tests/virtconv-files/vmx_output/virtimage2vmx_test1.vmx delete mode 100644 virtconv/diskcfg.py delete mode 100644 virtconv/netdevcfg.py create mode 100644 virtconv/ovf.py delete mode 100644 virtconv/parsers/__init__.py delete mode 100644 virtconv/parsers/ovf.py delete mode 100644 virtconv/parsers/virtimage.py delete mode 100644 virtconv/vmcfg.py rename virtconv/{parsers => }/vmx.py (53%) diff --git a/man/virt-convert.pod b/man/virt-convert.pod index 5c977884..b8eff835 100644 --- a/man/virt-convert.pod +++ b/man/virt-convert.pod @@ -2,36 +2,29 @@ =head1 NAME -virt-convert - convert virtual machines between formats +virt-convert - convert ovf/vmx to native libvirt guests =head1 SYNOPSIS -B [OPTION]... INPUT.VMX|INPUT-DIR [OUTPUT.XML|OUTPUT-DIR] +B INPUT.vmx|INPUT.ovf|INPUT-DIR|INPUT.zip [OPTIONS] =head1 DESCRIPTION -B is a command line tool for converting virtual machines -from one format to another. Pass in either a VM definition file (such -as VMWare vmx format) or a directory containing a VM. By default, a new -VM definition file, and converted disk images, will be placed in a new -output directory. +B is a command line tool for converting VMX of OVF virtual +machines to native libvirt XML. Disk format conversion can also be done +at the same time. -If an output directory is specified, it will be created if necessary, -and the output VM definition placed within, along with any disk images -as needed. +The simplest invocation is simply: virt-convert INPUT. INPUT might be +a .vmx or .ovf file, a directory containing a .vmx or .ovf file (and +likely 1 or more disk images), or an appliance archive like .zip, .tar.gz, +or .ova. virt-convert will try to do the right thing in each case. -If an output VM definition file is specified, it will be created -alongside any disks in the same directory. +By default, the virt-convert will convert all encountered disk images +to 'raw' format, sending the output to a new directory location. So the +original disk images are _not_ altered in place. =head1 OPTIONS -Any of the options can be omitted, in which case B will -use defaults when required. An input VM definition or containing directory -must be provided. By default, an output directory is generated based upon -the name of the VM. The default input format is VMWare vmx, and the -default output format is a libvirt "image" XML definition -(see L). - =over 4 =item -h, --help @@ -42,62 +35,27 @@ Show the help message and exit Show program's version number and exit +=item --connect=URI + +Connect to a non-default hypervisor. See L for details + =back =head2 Conversion Options =over 2 -=item -i format +=item -i/--input-format FORMAT -Input format. Currently, C, C, and C are supported. +Input format. This should be auto-detected, but can be forced if necessary. Currently C and C are supported. -=item -o format +=item -D/--disk-format DISK-FORMAT -Output format. Currently, C and C are supported. +Output disk format. The default is 'raw', so any encountered disk images will be converted to 'raw' format using L. Pass C if no conversion should be performed: in this case the images will just be copied to the specified --destination. -=item -D format +=item --destination DIRECTORY -Output disk format, or C if no conversion should be performed. See -L. - -=back - -=head2 Virtualization Type options - -Options to override the default virtualization type choices. - -=over 2 - -=item -v, --hvm Create a fully virtualized guest image - -Convert machine to a hvm/qemu based image (this is the default if paravirt -is not specified) - -=item -p, --paravirt Create a paravirtualized guest image - -Convert machine to a paravirt xen based image - -=back - -=head2 General Options - -General configuration parameters that apply to all types of guest installs. - -=over 2 - -=item -a ARCH, --arch=ARCH - -Architecture of the virtual machine (i686, x86_64, ppc). Defaults to -that of the host machine. - -=item --os-variant=OS_VARIANT - -Optimize the guest configuration for a specific operating system (ex. -'fedora18', 'rhel7', 'winxp'). While not requires, specifying this -options is HIGHLY RECOMMENDED, as it can greatly increase performance -by specifying virtio among other guest tweaks. -See L for valid values. +The directory to send converted/copied disk images. If not specified, the hypervisor default is used, typically /var/lib/libvirt/images. =back @@ -105,6 +63,23 @@ See L for valid values. =over 2 +=item --noautoconsole + +Don't automatically try to connect to the guest console. The default behaviour +is to launch L to display the graphical console, or to run the +C C command to display the text console. Use of this parameter +will disable this behaviour. + +=item --print-xml + +Print the generated libvirt XML, but do not perform any disk conversions or +install/start the guest. This option implies --dry-run. + +=item --dry-run + +Proceed through the conversion process, but don't convert disks or actually +write any converted files. + =item -q, --quiet Avoid verbose output. @@ -113,22 +88,21 @@ Avoid verbose output. Print debugging information -=item --dry-run - -Proceed through the conversion process, but don't convert disks or actually -write any converted files. - =back =head1 EXAMPLES -Convert a paravirt guest from C: +Run a fedora18 OVA archive: - # virt-convert --arch=i686 --paravirt image.vmx + # virt-convert fedora18.ova -Convert a 64-bit hvm guest: +Run an extracted zip archive containing a centos6 .vmx and .vmdk file, converting the images to qcow2 format - # virt-convert --arch=x86_64 vmx-appliance/ hvm-appliance/ + # virt-convert centos6/ --disk-format qcow2 + +Convert the specified .vmx file. Any references disk images must be in the same directory. Don't change the disk format. Move the disk images to /tmp + + # virt-convert foo.vmx --disk-format none --destination /tmp =head1 BUGS @@ -143,7 +117,7 @@ There is NO WARRANTY, to the extent permitted by law. =head1 SEE ALSO -L, the project website C +L, the project website C =cut diff --git a/man/virt-install.pod b/man/virt-install.pod index c8004953..ff08d725 100644 --- a/man/virt-install.pod +++ b/man/virt-install.pod @@ -827,7 +827,7 @@ This deprecates the following options: --vnc, --vncport, --vnclisten, -k/--keyma =item --noautoconsole Don't automatically try to connect to the guest console. The default behaviour -is to launch a VNC client to display the graphical console, or to run the +is to launch L to display the graphical console, or to run the C C command to display the text console. Use of this parameter will disable this behaviour. diff --git a/tests/cli-test-xml/compare/convert-default.xml b/tests/cli-test-xml/compare/convert-default.xml deleted file mode 100644 index 4b980595..00000000 --- a/tests/cli-test-xml/compare/convert-default.xml +++ /dev/null @@ -1,5 +0,0 @@ -Generating output in 'virt-image' format to /tmp/__virtinst_tests__virtconv-outdir/ -Converting disk 'root.raw' to type raw... -Converting disk 'scratch.raw' to type raw... -Converting disk 'data.raw' to type raw... -Done. \ No newline at end of file diff --git a/tests/cli-test-xml/compare/clone-auto1.xml b/tests/cli-test-xml/compare/virt-clone-clone-auto1.xml similarity index 100% rename from tests/cli-test-xml/compare/clone-auto1.xml rename to tests/cli-test-xml/compare/virt-clone-clone-auto1.xml diff --git a/tests/cli-test-xml/compare/clone-auto2.xml b/tests/cli-test-xml/compare/virt-clone-clone-auto2.xml similarity index 100% rename from tests/cli-test-xml/compare/clone-auto2.xml rename to tests/cli-test-xml/compare/virt-clone-clone-auto2.xml diff --git a/tests/cli-test-xml/compare/virt-convert-ovf-compare.xml b/tests/cli-test-xml/compare/virt-convert-ovf-compare.xml new file mode 100644 index 00000000..c073ffc3 --- /dev/null +++ b/tests/cli-test-xml/compare/virt-convert-ovf-compare.xml @@ -0,0 +1,69 @@ +Copying test.ovf-disk1.vmdk to /tmp/test.ovf-disk1 +Copying testfile to /tmp/testfile + + test.ovf + 00000000-1111-2222-3333-444444444444 + This is the description, created by RWMJ. + 795648 + 795648 + 3 + + hvm + + + + + + + + + + + + + destroy + restart + restart + + /usr/bin/qemu-system-x86_64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/cli-test-xml/compare/virt-convert-vmx-compare.xml b/tests/cli-test-xml/compare/virt-convert-vmx-compare.xml new file mode 100644 index 00000000..20f046d2 --- /dev/null +++ b/tests/cli-test-xml/compare/virt-convert-vmx-compare.xml @@ -0,0 +1,65 @@ +Running /usr/bin/qemu-img convert -O qcow2 fedora.vmdk /var/lib/libvirt/images/fedora.qcow2 + + fedora + 00000000-1111-2222-3333-444444444444 + 524288 + 524288 + 1 + + hvm + + + + + + + + + + + + + destroy + restart + restart + + /usr/bin/qemu-system-x86_64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/cli-test-xml/compare/image-boot0.xml b/tests/cli-test-xml/compare/virt-image-image-boot0.xml similarity index 100% rename from tests/cli-test-xml/compare/image-boot0.xml rename to tests/cli-test-xml/compare/virt-image-image-boot0.xml diff --git a/tests/cli-test-xml/compare/image-boot1.xml b/tests/cli-test-xml/compare/virt-image-image-boot1.xml similarity index 100% rename from tests/cli-test-xml/compare/image-boot1.xml rename to tests/cli-test-xml/compare/virt-image-image-boot1.xml diff --git a/tests/cli-test-xml/compare/image-nogfx.xml b/tests/cli-test-xml/compare/virt-image-image-nogfx.xml similarity index 100% rename from tests/cli-test-xml/compare/image-nogfx.xml rename to tests/cli-test-xml/compare/virt-image-image-nogfx.xml diff --git a/tests/cli-test-xml/compare/arm-vexpress-f19.xml b/tests/cli-test-xml/compare/virt-install-arm-vexpress-f19.xml similarity index 100% rename from tests/cli-test-xml/compare/arm-vexpress-f19.xml rename to tests/cli-test-xml/compare/virt-install-arm-vexpress-f19.xml diff --git a/tests/cli-test-xml/compare/arm-vexpress-plain.xml b/tests/cli-test-xml/compare/virt-install-arm-vexpress-plain.xml similarity index 100% rename from tests/cli-test-xml/compare/arm-vexpress-plain.xml rename to tests/cli-test-xml/compare/virt-install-arm-vexpress-plain.xml diff --git a/tests/cli-test-xml/compare/cpuset-auto.xml b/tests/cli-test-xml/compare/virt-install-cpuset-auto.xml similarity index 100% rename from tests/cli-test-xml/compare/cpuset-auto.xml rename to tests/cli-test-xml/compare/virt-install-cpuset-auto.xml diff --git a/tests/cli-test-xml/compare/default.xml b/tests/cli-test-xml/compare/virt-install-default.xml similarity index 100% rename from tests/cli-test-xml/compare/default.xml rename to tests/cli-test-xml/compare/virt-install-default.xml diff --git a/tests/cli-test-xml/compare/fs-default.xml b/tests/cli-test-xml/compare/virt-install-fs-default.xml similarity index 100% rename from tests/cli-test-xml/compare/fs-default.xml rename to tests/cli-test-xml/compare/virt-install-fs-default.xml diff --git a/tests/cli-test-xml/compare/kvm-f14-url.xml b/tests/cli-test-xml/compare/virt-install-kvm-f14-url.xml similarity index 100% rename from tests/cli-test-xml/compare/kvm-f14-url.xml rename to tests/cli-test-xml/compare/virt-install-kvm-f14-url.xml diff --git a/tests/cli-test-xml/compare/kvm-machine.xml b/tests/cli-test-xml/compare/virt-install-kvm-machine.xml similarity index 100% rename from tests/cli-test-xml/compare/kvm-machine.xml rename to tests/cli-test-xml/compare/virt-install-kvm-machine.xml diff --git a/tests/cli-test-xml/compare/kvm-win2k3-cdrom.xml b/tests/cli-test-xml/compare/virt-install-kvm-win2k3-cdrom.xml similarity index 100% rename from tests/cli-test-xml/compare/kvm-win2k3-cdrom.xml rename to tests/cli-test-xml/compare/virt-install-kvm-win2k3-cdrom.xml diff --git a/tests/cli-test-xml/compare/kvm-xenner.xml b/tests/cli-test-xml/compare/virt-install-kvm-xenner.xml similarity index 100% rename from tests/cli-test-xml/compare/kvm-xenner.xml rename to tests/cli-test-xml/compare/virt-install-kvm-xenner.xml diff --git a/tests/cli-test-xml/compare/manual-init.xml b/tests/cli-test-xml/compare/virt-install-manual-init.xml similarity index 100% rename from tests/cli-test-xml/compare/manual-init.xml rename to tests/cli-test-xml/compare/virt-install-manual-init.xml diff --git a/tests/cli-test-xml/compare/many-devices.xml b/tests/cli-test-xml/compare/virt-install-many-devices.xml similarity index 100% rename from tests/cli-test-xml/compare/many-devices.xml rename to tests/cli-test-xml/compare/virt-install-many-devices.xml diff --git a/tests/cli-test-xml/compare/noargs-fail.xml b/tests/cli-test-xml/compare/virt-install-noargs-fail.xml similarity index 100% rename from tests/cli-test-xml/compare/noargs-fail.xml rename to tests/cli-test-xml/compare/virt-install-noargs-fail.xml diff --git a/tests/cli-test-xml/compare/ppc64-pseries-f20.xml b/tests/cli-test-xml/compare/virt-install-ppc64-pseries-f20.xml similarity index 100% rename from tests/cli-test-xml/compare/ppc64-pseries-f20.xml rename to tests/cli-test-xml/compare/virt-install-ppc64-pseries-f20.xml diff --git a/tests/cli-test-xml/compare/qemu-32-on-64.xml b/tests/cli-test-xml/compare/virt-install-qemu-32-on-64.xml similarity index 100% rename from tests/cli-test-xml/compare/qemu-32-on-64.xml rename to tests/cli-test-xml/compare/virt-install-qemu-32-on-64.xml diff --git a/tests/cli-test-xml/compare/qemu-plain.xml b/tests/cli-test-xml/compare/virt-install-qemu-plain.xml similarity index 100% rename from tests/cli-test-xml/compare/qemu-plain.xml rename to tests/cli-test-xml/compare/virt-install-qemu-plain.xml diff --git a/tests/cli-test-xml/compare/qemu-sparc.xml b/tests/cli-test-xml/compare/virt-install-qemu-sparc.xml similarity index 100% rename from tests/cli-test-xml/compare/qemu-sparc.xml rename to tests/cli-test-xml/compare/virt-install-qemu-sparc.xml diff --git a/tests/cli-test-xml/compare/quiet-url.xml b/tests/cli-test-xml/compare/virt-install-quiet-url.xml similarity index 100% rename from tests/cli-test-xml/compare/quiet-url.xml rename to tests/cli-test-xml/compare/virt-install-quiet-url.xml diff --git a/tests/cli-test-xml/compare/simple-pxe.xml b/tests/cli-test-xml/compare/virt-install-simple-pxe.xml similarity index 100% rename from tests/cli-test-xml/compare/simple-pxe.xml rename to tests/cli-test-xml/compare/virt-install-simple-pxe.xml diff --git a/tests/cli-test-xml/compare/w2k3-cdrom.xml b/tests/cli-test-xml/compare/virt-install-w2k3-cdrom.xml similarity index 100% rename from tests/cli-test-xml/compare/w2k3-cdrom.xml rename to tests/cli-test-xml/compare/virt-install-w2k3-cdrom.xml diff --git a/tests/cli-test-xml/compare/xen-default.xml b/tests/cli-test-xml/compare/virt-install-xen-default.xml similarity index 100% rename from tests/cli-test-xml/compare/xen-default.xml rename to tests/cli-test-xml/compare/virt-install-xen-default.xml diff --git a/tests/cli-test-xml/compare/xen-hvm.xml b/tests/cli-test-xml/compare/virt-install-xen-hvm.xml similarity index 100% rename from tests/cli-test-xml/compare/xen-hvm.xml rename to tests/cli-test-xml/compare/virt-install-xen-hvm.xml diff --git a/tests/cli-test-xml/compare/xen-ia64-default.xml b/tests/cli-test-xml/compare/virt-install-xen-ia64-default.xml similarity index 100% rename from tests/cli-test-xml/compare/xen-ia64-default.xml rename to tests/cli-test-xml/compare/virt-install-xen-ia64-default.xml diff --git a/tests/cli-test-xml/compare/xen-ia64-hvm.xml b/tests/cli-test-xml/compare/virt-install-xen-ia64-hvm.xml similarity index 100% rename from tests/cli-test-xml/compare/xen-ia64-hvm.xml rename to tests/cli-test-xml/compare/virt-install-xen-ia64-hvm.xml diff --git a/tests/cli-test-xml/compare/xen-ia64-pv.xml b/tests/cli-test-xml/compare/virt-install-xen-ia64-pv.xml similarity index 100% rename from tests/cli-test-xml/compare/xen-ia64-pv.xml rename to tests/cli-test-xml/compare/virt-install-xen-ia64-pv.xml diff --git a/tests/cli-test-xml/compare/xen-pv.xml b/tests/cli-test-xml/compare/virt-install-xen-pv.xml similarity index 100% rename from tests/cli-test-xml/compare/xen-pv.xml rename to tests/cli-test-xml/compare/virt-install-xen-pv.xml diff --git a/tests/cli-test-xml/compare/virtxml-add-disk-basic.xml b/tests/cli-test-xml/compare/virt-xml-add-disk-basic.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-add-disk-basic.xml rename to tests/cli-test-xml/compare/virt-xml-add-disk-basic.xml diff --git a/tests/cli-test-xml/compare/virtxml-add-disk-create-storage.xml b/tests/cli-test-xml/compare/virt-xml-add-disk-create-storage.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-add-disk-create-storage.xml rename to tests/cli-test-xml/compare/virt-xml-add-disk-create-storage.xml diff --git a/tests/cli-test-xml/compare/virtxml-add-disk-notarget.xml b/tests/cli-test-xml/compare/virt-xml-add-disk-notarget.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-add-disk-notarget.xml rename to tests/cli-test-xml/compare/virt-xml-add-disk-notarget.xml diff --git a/tests/cli-test-xml/compare/virtxml-add-host-device.xml b/tests/cli-test-xml/compare/virt-xml-add-host-device.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-add-host-device.xml rename to tests/cli-test-xml/compare/virt-xml-add-host-device.xml diff --git a/tests/cli-test-xml/compare/virtxml-add-sound.xml b/tests/cli-test-xml/compare/virt-xml-add-sound.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-add-sound.xml rename to tests/cli-test-xml/compare/virt-xml-add-sound.xml diff --git a/tests/cli-test-xml/compare/virtxml-build-blkiotune.xml b/tests/cli-test-xml/compare/virt-xml-build-blkiotune.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-build-blkiotune.xml rename to tests/cli-test-xml/compare/virt-xml-build-blkiotune.xml diff --git a/tests/cli-test-xml/compare/virtxml-build-cpu.xml b/tests/cli-test-xml/compare/virt-xml-build-cpu.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-build-cpu.xml rename to tests/cli-test-xml/compare/virt-xml-build-cpu.xml diff --git a/tests/cli-test-xml/compare/virtxml-build-tpm.xml b/tests/cli-test-xml/compare/virt-xml-build-tpm.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-build-tpm.xml rename to tests/cli-test-xml/compare/virt-xml-build-tpm.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-all.xml b/tests/cli-test-xml/compare/virt-xml-edit-all.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-all.xml rename to tests/cli-test-xml/compare/virt-xml-edit-all.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-clear-clock.xml b/tests/cli-test-xml/compare/virt-xml-edit-clear-clock.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-clear-clock.xml rename to tests/cli-test-xml/compare/virt-xml-edit-clear-clock.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-clear-cpu.xml b/tests/cli-test-xml/compare/virt-xml-edit-clear-cpu.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-clear-cpu.xml rename to tests/cli-test-xml/compare/virt-xml-edit-clear-cpu.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-clear-disk.xml b/tests/cli-test-xml/compare/virt-xml-edit-clear-disk.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-clear-disk.xml rename to tests/cli-test-xml/compare/virt-xml-edit-clear-disk.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-neg-num.xml b/tests/cli-test-xml/compare/virt-xml-edit-neg-num.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-neg-num.xml rename to tests/cli-test-xml/compare/virt-xml-edit-neg-num.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-pos-num.xml b/tests/cli-test-xml/compare/virt-xml-edit-pos-num.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-pos-num.xml rename to tests/cli-test-xml/compare/virt-xml-edit-pos-num.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-select-disk-path.xml b/tests/cli-test-xml/compare/virt-xml-edit-select-disk-path.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-select-disk-path.xml rename to tests/cli-test-xml/compare/virt-xml-edit-select-disk-path.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-select-disk-target.xml b/tests/cli-test-xml/compare/virt-xml-edit-select-disk-target.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-select-disk-target.xml rename to tests/cli-test-xml/compare/virt-xml-edit-select-disk-target.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-select-network-mac.xml b/tests/cli-test-xml/compare/virt-xml-edit-select-network-mac.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-select-network-mac.xml rename to tests/cli-test-xml/compare/virt-xml-edit-select-network-mac.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-select-sound-model.xml b/tests/cli-test-xml/compare/virt-xml-edit-select-sound-model.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-select-sound-model.xml rename to tests/cli-test-xml/compare/virt-xml-edit-select-sound-model.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-blkiotune.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-blkiotune.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-blkiotune.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-blkiotune.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-boot.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-boot.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-boot.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-boot.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-channel.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-channel.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-channel.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-channel.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-clock.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-clock.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-clock.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-clock.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-console.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-console.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-console.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-console.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-controller.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-controller.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-controller.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-controller.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-cpu.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-cpu.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-cpu.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-cpu.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-disk-remove-path.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-disk-remove-path.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-disk-remove-path.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-disk-remove-path.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-disk.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-disk.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-disk.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-disk.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-features.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-features.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-features.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-features.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-filesystem.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-filesystem.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-filesystem.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-filesystem.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-graphics.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-graphics.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-graphics.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-graphics.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-host-device.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-host-device.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-host-device.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-host-device.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-memballoon.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-memballoon.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-memballoon.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-memballoon.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-memory.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-memory.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-memory.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-memory.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-metadata.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-metadata.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-metadata.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-metadata.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-network.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-network.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-network.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-network.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-numatune.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-numatune.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-numatune.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-numatune.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-parallel.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-parallel.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-parallel.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-parallel.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-pm.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-pm.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-pm.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-pm.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-redirdev.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-redirdev.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-redirdev.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-redirdev.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-rng.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-rng.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-rng.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-rng.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-security.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-security.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-security.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-security.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-serial.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-serial.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-serial.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-serial.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-smartcard.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-smartcard.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-smartcard.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-smartcard.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-soundhw.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-soundhw.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-soundhw.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-soundhw.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-tpm.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-tpm.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-tpm.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-tpm.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-vcpus.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-vcpus.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-vcpus.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-vcpus.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-video.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-video.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-video.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-video.xml diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-watchdog.xml b/tests/cli-test-xml/compare/virt-xml-edit-simple-watchdog.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-edit-simple-watchdog.xml rename to tests/cli-test-xml/compare/virt-xml-edit-simple-watchdog.xml diff --git a/tests/cli-test-xml/compare/virtxml-print-xml.xml b/tests/cli-test-xml/compare/virt-xml-print-xml.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-print-xml.xml rename to tests/cli-test-xml/compare/virt-xml-print-xml.xml diff --git a/tests/cli-test-xml/compare/virtxml-remove-disk-index.xml b/tests/cli-test-xml/compare/virt-xml-remove-disk-index.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-remove-disk-index.xml rename to tests/cli-test-xml/compare/virt-xml-remove-disk-index.xml diff --git a/tests/cli-test-xml/compare/virtxml-remove-disk-path.xml b/tests/cli-test-xml/compare/virt-xml-remove-disk-path.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-remove-disk-path.xml rename to tests/cli-test-xml/compare/virt-xml-remove-disk-path.xml diff --git a/tests/cli-test-xml/compare/virtxml-remove-sound-model.xml b/tests/cli-test-xml/compare/virt-xml-remove-sound-model.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-remove-sound-model.xml rename to tests/cli-test-xml/compare/virt-xml-remove-sound-model.xml diff --git a/tests/cli-test-xml/compare/virtxml-remove-video-all.xml b/tests/cli-test-xml/compare/virt-xml-remove-video-all.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-remove-video-all.xml rename to tests/cli-test-xml/compare/virt-xml-remove-video-all.xml diff --git a/tests/cli-test-xml/compare/virtxml-stdin-edit.xml b/tests/cli-test-xml/compare/virt-xml-stdin-edit.xml similarity index 100% rename from tests/cli-test-xml/compare/virtxml-stdin-edit.xml rename to tests/cli-test-xml/compare/virt-xml-stdin-edit.xml diff --git a/tests/cli-test-xml/virtconv/virtimage/data.raw b/tests/cli-test-xml/virtconv/ovf/test.ovf-disk1.vmdk similarity index 100% rename from tests/cli-test-xml/virtconv/virtimage/data.raw rename to tests/cli-test-xml/virtconv/ovf/test.ovf-disk1.vmdk diff --git a/tests/cli-test-xml/virtconv/ovf/test1.ovf b/tests/cli-test-xml/virtconv/ovf/test1.ovf new file mode 100644 index 00000000..372388f5 --- /dev/null +++ b/tests/cli-test-xml/virtconv/ovf/test1.ovf @@ -0,0 +1,123 @@ + + + + + + + + + Virtual disk information + + + + The list of logical networks + + The VM Network network + + + + A virtual machine + test.ovf + + The kind of installed guest operating system + Red Hat Enterprise Linux 5 (64-bit) + + + Virtual hardware requirements + + Virtual Hardware Family + 0 + test.ovf + vmx-07 + + + hertz * 10^6 + Number of Virtual CPUs + 1 virtual CPU(s) + 1 + 3 + 3 + + + byte * 2^20 + Memory Size + 512MB of memory + 2 + 4 + 777 + + + 0 + SCSI Controller + SCSI controller 0 + 3 + lsilogic + 6 + + + 1 + IDE Controller + IDE 1 + 4 + 5 + + + 0 + IDE Controller + IDE 0 + 5 + 5 + + + 0 + false + Floppy Drive + Floppy drive 1 + 6 + 14 + + + 0 + false + CD/DVD Drive 1 + 7 + 4 + 15 + + + 7 + true + VM Network + E1000 ethernet adapter on "VM Network" + Network adapter 1 + 8 + E1000 + 10 + + + 0 + Hard disk 1 + ovf:/disk/vmdisk1 + 9 + 3 + 17 + + + 1 + Hard disk 2 + ovf:/file/vmfile1 + 10 + 4 + 17 + + + + A human-readable annotation + This is the description, created by RWMJ. + + + + A human-readable annotation + This is the description, created by RWMJ. + + diff --git a/tests/cli-test-xml/virtconv/virtimage/root.raw b/tests/cli-test-xml/virtconv/ovf/testfile similarity index 100% rename from tests/cli-test-xml/virtconv/virtimage/root.raw rename to tests/cli-test-xml/virtconv/ovf/testfile diff --git a/tests/cli-test-xml/virtconv/virtimage/scratch.raw b/tests/cli-test-xml/virtconv/virtimage/scratch.raw deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/cli-test-xml/virtconv/virtimage/test1.virt-image b/tests/cli-test-xml/virtconv/virtimage/test1.virt-image deleted file mode 100644 index dfe60332..00000000 --- a/tests/cli-test-xml/virtconv/virtimage/test1.virt-image +++ /dev/null @@ -1,48 +0,0 @@ - - test-image - - - - - xen - i386 - - - - pygrub - - - - - - - - i686 - - - - hvm - - - - - - - - 7 - 262144 - - - - - - - - - - - - - - - diff --git a/tests/clitest.py b/tests/clitest.py index fd294014..0d3cf50a 100644 --- a/tests/clitest.py +++ b/tests/clitest.py @@ -32,7 +32,6 @@ from virtinst import support from tests import virtinstall, virtimage, virtclone, virtconvert, virtxml from tests import utils -os.environ["VIRTCONV_TEST_NO_DISK_CONVERSION"] = "1" os.environ["LANG"] = "en_US.UTF-8" # Used to ensure consistent SDL xml output @@ -75,13 +74,10 @@ virtimage_exist = ["/tmp/__virtinst__cli_root.raw"] # Images created by virt-image virtimage_new = ["/tmp/__virtinst__cli_scratch.raw"] -# virt-convert output dirs -virtconv_dirs = [virtconv_out] - exist_files = exist_images + virtimage_exist -new_files = new_images + virtimage_new + virtconv_dirs +new_files = new_images + virtimage_new clean_files = (new_images + exist_images + - virtimage_exist + virtimage_new + virtconv_dirs + [ro_dir]) + virtimage_exist + virtimage_new + [ro_dir]) promptlist = [] @@ -118,10 +114,8 @@ test_files = { 'COLLIDE' : "/dev/default-pool/collidevol1.img", 'SHARE' : "/dev/default-pool/sharevol.img", - 'VIRTCONV_OUT' : "%s/test.out" % virtconv_out, - 'VC_IMG1' : "%s/virtimage/test1.virt-image" % vcdir, - 'VC_IMG2' : "tests/image-xml/image-format.xml", - 'VMX_IMG1' : "%s/vmx/test1.vmx" % vcdir, + 'OVF_IMG1' : "%s/tests/virtconv-files/ovf_input/test1.ovf" % os.getcwd(), + 'VMX_IMG1' : "%s/tests/virtconv-files/vmx_input/test1.vmx" % os.getcwd(), } @@ -173,9 +167,9 @@ class Command(object): elif app.count("virt-image"): ret = virtimage.main(conn=conn) elif app.count("virt-convert"): - ret = virtconvert.main() + ret = virtconvert.main(conn=conn) elif app.count("virt-xml"): - ret = virtxml.main() + ret = virtxml.main(conn=conn) except SystemExit, sys_e: ret = sys_e.code @@ -226,7 +220,7 @@ class Command(object): conn = utils.openconn(self.argv[idx + 1]) break - if not conn and "virt-convert" not in self.argv[0]: + if not conn: raise RuntimeError("couldn't parse URI from command %s" % self.argv) @@ -380,9 +374,8 @@ class App(object): if not iscompare: args = "--debug" - if self.appname != "virt-convert": - if "--connect " not in cli: - args += " --connect %(TESTURI)s" + if "--connect " not in cli: + args += " --connect %(TESTURI)s" if self.appname in ["virt-install"]: if "--name " not in cli: @@ -426,6 +419,7 @@ class App(object): cmd = Command(cmdstr) cmd.check_success = valid if compfile: + compfile = os.path.basename(self.appname) + "-" + compfile cmd.compare_file = "%s/%s.xml" % (compare_xmldir, compfile) cmd.skip_check = skip_check or category.skip_check cmd.compare_check = compare_check or category.compare_check @@ -784,76 +778,75 @@ c.add_invalid("test-many-devices --add-device --host-device 0x0781:0x5151 --upda c.add_invalid("test-many-devices --remove-device --host-device 1 --update") # test driver doesn't support detachdevice... c.add_invalid("test-many-devices --edit --graphics password=foo --update") # test driver doesn't support updatdevice... c.add_invalid("--build-xml --memory 10,maxmemory=20") # building XML for option that doesn't support it -c.add_compare("test --print-xml --edit --vcpus 7", "virtxml-print-xml") # test --print-xml -c.add_compare("test --print-xml --edit --vcpus 7", "virtxml-print-xml") # test --print-xml -c.add_compare("--edit --cpu host-passthrough", "virtxml-stdin-edit", input_file=(xmldir + "/virtxml-stdin-edit.xml")) # stdin test -c.add_compare("--build-xml --cpu pentium3,+x2apic", "virtxml-build-cpu") -c.add_compare("--build-xml --tpm /dev/tpm", "virtxml-build-tpm") -c.add_compare("--build-xml --blkiotune weight=100,device_path=/dev/sdf,device_weight=200", "virtxml-build-blkiotune") +c.add_compare("test --print-xml --edit --vcpus 7", "print-xml") # test --print-xml +c.add_compare("--edit --cpu host-passthrough", "stdin-edit", input_file=(xmldir + "/virtxml-stdin-edit.xml")) # stdin test +c.add_compare("--build-xml --cpu pentium3,+x2apic", "build-cpu") +c.add_compare("--build-xml --tpm /dev/tpm", "build-tpm") +c.add_compare("--build-xml --blkiotune weight=100,device_path=/dev/sdf,device_weight=200", "build-blkiotune") c = vixml.add_category("simple edit diff", "test-many-devices --edit --print-diff --define", compare_check=support.SUPPORT_CONN_PANIC_DEVICE) c.add_compare("""--metadata name=foo-my-new-name,uuid=12345678-12F4-1234-1234-123456789AFA,description="hey this is my new -very,very=new desc\\\'",title="This is my,funky=new title" """, "virtxml-edit-simple-metadata") -c.add_compare("--memory 500,maxmemory=1000,hugepages=off", "virtxml-edit-simple-memory") -c.add_compare("--vcpus 10,maxvcpus=20,cores=5,sockets=4,threads=1", "virtxml-edit-simple-vcpus") -c.add_compare("--cpu model=pentium2,+x2apic,forbid=pbe", "virtxml-edit-simple-cpu") -c.add_compare("--numatune 1-5,7,mode=strict", "virtxml-edit-simple-numatune") -c.add_compare("--blkiotune weight=500,device_path=/dev/sdf,device_weight=600", "virtxml-edit-simple-blkiotune") -c.add_compare("--boot loader=foo.bar,network,useserial=on,init=/bin/bash", "virtxml-edit-simple-boot") -c.add_compare("--security label=foo,bar,baz,UNKNOWN=val,relabel=on", "virtxml-edit-simple-security") -c.add_compare("--features eoi=on,hyperv_relaxed=off,acpi=", "virtxml-edit-simple-features") -c.add_compare("--clock offset=localtime,hpet_present=yes,kvmclock_present=no,rtc_tickpolicy=merge", "virtxml-edit-simple-clock") -c.add_compare("--pm suspend_to_mem=yes,suspend_to_disk=no", "virtxml-edit-simple-pm") -c.add_compare("--disk /dev/zero,perms=ro,startup_policy=optional", "virtxml-edit-simple-disk") -c.add_compare("--disk path=", "virtxml-edit-simple-disk-remove-path") -c.add_compare("--network source=br0,type=bridge,model=virtio,mac=", "virtxml-edit-simple-network") -c.add_compare("--graphics tlsport=5902,keymap=ja", "virtxml-edit-simple-graphics") -c.add_compare("--controller index=2,model=lsilogic", "virtxml-edit-simple-controller") -c.add_compare("--smartcard type=spicevmc", "virtxml-edit-simple-smartcard") -c.add_compare("--redirdev type=spicevmc,server=example.com:12345", "virtxml-edit-simple-redirdev") -c.add_compare("--tpm path=/dev/tpm", "virtxml-edit-simple-tpm") -c.add_compare("--rng rate_bytes=3333,rate_period=4444", "virtxml-edit-simple-rng") -c.add_compare("--watchdog action=reset", "virtxml-edit-simple-watchdog") -c.add_compare("--memballoon model=none", "virtxml-edit-simple-memballoon") -c.add_compare("--serial pty", "virtxml-edit-simple-serial") -c.add_compare("--parallel unix,path=/some/other/log", "virtxml-edit-simple-parallel") -c.add_compare("--channel null", "virtxml-edit-simple-channel") -c.add_compare("--console target_type=serial", "virtxml-edit-simple-console") -c.add_compare("--filesystem /1/2/3,/4/5/6,mode=mapped", "virtxml-edit-simple-filesystem") -c.add_compare("--video cirrus", "virtxml-edit-simple-video") -c.add_compare("--sound pcspk", "virtxml-edit-simple-soundhw") -c.add_compare("--host-device 0x0781:0x5151,driver_name=vfio", "virtxml-edit-simple-host-device") +very,very=new desc\\\'",title="This is my,funky=new title" """, "edit-simple-metadata") +c.add_compare("--memory 500,maxmemory=1000,hugepages=off", "edit-simple-memory") +c.add_compare("--vcpus 10,maxvcpus=20,cores=5,sockets=4,threads=1", "edit-simple-vcpus") +c.add_compare("--cpu model=pentium2,+x2apic,forbid=pbe", "edit-simple-cpu") +c.add_compare("--numatune 1-5,7,mode=strict", "edit-simple-numatune") +c.add_compare("--blkiotune weight=500,device_path=/dev/sdf,device_weight=600", "edit-simple-blkiotune") +c.add_compare("--boot loader=foo.bar,network,useserial=on,init=/bin/bash", "edit-simple-boot") +c.add_compare("--security label=foo,bar,baz,UNKNOWN=val,relabel=on", "edit-simple-security") +c.add_compare("--features eoi=on,hyperv_relaxed=off,acpi=", "edit-simple-features") +c.add_compare("--clock offset=localtime,hpet_present=yes,kvmclock_present=no,rtc_tickpolicy=merge", "edit-simple-clock") +c.add_compare("--pm suspend_to_mem=yes,suspend_to_disk=no", "edit-simple-pm") +c.add_compare("--disk /dev/zero,perms=ro,startup_policy=optional", "edit-simple-disk") +c.add_compare("--disk path=", "edit-simple-disk-remove-path") +c.add_compare("--network source=br0,type=bridge,model=virtio,mac=", "edit-simple-network") +c.add_compare("--graphics tlsport=5902,keymap=ja", "edit-simple-graphics") +c.add_compare("--controller index=2,model=lsilogic", "edit-simple-controller") +c.add_compare("--smartcard type=spicevmc", "edit-simple-smartcard") +c.add_compare("--redirdev type=spicevmc,server=example.com:12345", "edit-simple-redirdev") +c.add_compare("--tpm path=/dev/tpm", "edit-simple-tpm") +c.add_compare("--rng rate_bytes=3333,rate_period=4444", "edit-simple-rng") +c.add_compare("--watchdog action=reset", "edit-simple-watchdog") +c.add_compare("--memballoon model=none", "edit-simple-memballoon") +c.add_compare("--serial pty", "edit-simple-serial") +c.add_compare("--parallel unix,path=/some/other/log", "edit-simple-parallel") +c.add_compare("--channel null", "edit-simple-channel") +c.add_compare("--console target_type=serial", "edit-simple-console") +c.add_compare("--filesystem /1/2/3,/4/5/6,mode=mapped", "edit-simple-filesystem") +c.add_compare("--video cirrus", "edit-simple-video") +c.add_compare("--sound pcspk", "edit-simple-soundhw") +c.add_compare("--host-device 0x0781:0x5151,driver_name=vfio", "edit-simple-host-device") c = vixml.add_category("edit selection", "test-many-devices --print-diff --define", compare_check=support.SUPPORT_CONN_PANIC_DEVICE) c.add_invalid("--edit target=vvv --disk /dev/null") # no match found -c.add_compare("--edit 3 --sound pcspk", "virtxml-edit-pos-num") -c.add_compare("--edit -1 --video qxl", "virtxml-edit-neg-num") -c.add_compare("--edit all --host-device driver_name=vfio", "virtxml-edit-all") -c.add_compare("--edit ich6 --sound pcspk", "virtxml-edit-select-sound-model") -c.add_compare("--edit target=hda --disk /dev/null", "virtxml-edit-select-disk-target") -c.add_compare("--edit /tmp/foobar2 --disk shareable=off,readonly=on", "virtxml-edit-select-disk-path") -c.add_compare("--edit mac=00:11:7f:33:44:55 --network target=nic55", "virtxml-edit-select-network-mac") +c.add_compare("--edit 3 --sound pcspk", "edit-pos-num") +c.add_compare("--edit -1 --video qxl", "edit-neg-num") +c.add_compare("--edit all --host-device driver_name=vfio", "edit-all") +c.add_compare("--edit ich6 --sound pcspk", "edit-select-sound-model") +c.add_compare("--edit target=hda --disk /dev/null", "edit-select-disk-target") +c.add_compare("--edit /tmp/foobar2 --disk shareable=off,readonly=on", "edit-select-disk-path") +c.add_compare("--edit mac=00:11:7f:33:44:55 --network target=nic55", "edit-select-network-mac") c = vixml.add_category("edit clear", "test-many-devices --print-diff --define", compare_check=support.SUPPORT_CONN_PANIC_DEVICE) c.add_invalid("--edit --memory 200,clearxml=yes") # clear isn't wired up for memory -c.add_compare("--edit --cpu host-passthrough,clearxml=yes", "virtxml-edit-clear-cpu") -c.add_compare("--edit --clock offset=utc,clearxml=yes", "virtxml-edit-clear-clock") -c.add_compare("--edit --disk /foo/bar,target=fda,bus=fdc,device=floppy,clearxml=yes", "virtxml-edit-clear-disk") +c.add_compare("--edit --cpu host-passthrough,clearxml=yes", "edit-clear-cpu") +c.add_compare("--edit --clock offset=utc,clearxml=yes", "edit-clear-clock") +c.add_compare("--edit --disk /foo/bar,target=fda,bus=fdc,device=floppy,clearxml=yes", "edit-clear-disk") c = vixml.add_category("add/rm devices", "test-many-devices --print-diff --define", compare_check=support.SUPPORT_CONN_PANIC_DEVICE) c.add_invalid("--add-device --security foo") # --add-device without a device c.add_invalid("--remove-device --clock utc") # --remove-device without a dev -c.add_compare("--add-device --host-device net_00_1c_25_10_b1_e4", "virtxml-add-host-device") -c.add_compare("--add-device --sound pcspk", "virtxml-add-sound") -c.add_compare("--add-device --disk %(EXISTIMG1)s,bus=virtio,target=vdf", "virtxml-add-disk-basic") -c.add_compare("--add-device --disk %(EXISTIMG1)s", "virtxml-add-disk-notarget") # filling in acceptable target -c.add_compare("--add-device --disk %(NEWIMG1)s,size=.01", "virtxml-add-disk-create-storage") -c.add_compare("--remove-device --sound ich6", "virtxml-remove-sound-model") -c.add_compare("--remove-device --disk 6", "virtxml-remove-disk-index") -c.add_compare("--remove-device --disk /dev/null", "virtxml-remove-disk-path") -c.add_compare("--remove-device --video all", "virtxml-remove-video-all") +c.add_compare("--add-device --host-device net_00_1c_25_10_b1_e4", "add-host-device") +c.add_compare("--add-device --sound pcspk", "add-sound") +c.add_compare("--add-device --disk %(EXISTIMG1)s,bus=virtio,target=vdf", "add-disk-basic") +c.add_compare("--add-device --disk %(EXISTIMG1)s", "add-disk-notarget") # filling in acceptable target +c.add_compare("--add-device --disk %(NEWIMG1)s,size=.01", "add-disk-create-storage") +c.add_compare("--remove-device --sound ich6", "remove-sound-model") +c.add_compare("--remove-device --disk 6", "remove-disk-index") +c.add_compare("--remove-device --disk /dev/null", "remove-disk-path") +c.add_compare("--remove-device --video all", "remove-video-all") vimag = App("virt-image") @@ -895,18 +888,12 @@ c.add_invalid("--boot 10") # Out of bounds index vconv = App("virt-convert") -c = vconv.add_category("misc", "") -c.add_compare("%(VC_IMG1)s %(VIRTCONV_OUT)s", "convert-default") # virt-image to default (virt-image) w/ no convert -c.add_valid("%(VC_IMG1)s -D none %(VIRTCONV_OUT)s") # virt-image to default (virt-image) w/ no convert -c.add_valid("%(VC_IMG1)s -o virt-image -D none %(VIRTCONV_OUT)s") # virt-image to virt-image w/ no convert -c.add_valid("%(VC_IMG1)s -o vmx -D none %(VIRTCONV_OUT)s") # virt-image to vmx w/ no convert -c.add_valid("%(VC_IMG1)s -o vmx -D raw %(VIRTCONV_OUT)s") # virt-image to vmx w/ raw -c.add_valid("%(VC_IMG1)s -o vmx -D vmdk %(VIRTCONV_OUT)s") # virt-image to vmx w/ vmdk -c.add_valid("%(VC_IMG1)s -o vmx -D qcow2 %(VIRTCONV_OUT)s") # virt-image to vmx w/ qcow2 -c.add_valid("%(VMX_IMG1)s -o vmx -D none %(VIRTCONV_OUT)s") # vmx to vmx no convert -c.add_valid("%(VC_IMG2)s -o vmx -D vmdk %(VIRTCONV_OUT)s") # virt-image with exotic formats specified -c.add_invalid("%(VC_IMG1)s -o virt-image -D foobarfmt %(VIRTCONV_OUT)s") # virt-image to virt-image with invalid format -c.add_invalid("%(VC_IMG1)s -o ovf %(VIRTCONV_OUT)s") # virt-image to ovf (has no output formatter) +c = vconv.add_category("misc", "--connect %(KVMURI)s --dry") +c.add_invalid("%(VMX_IMG1)s --input-format foo") # invalid input format +c.add_invalid("%(EXISTIMG1)s") # invalid input file + +c.add_compare("%(VMX_IMG1)s --disk-format qcow2 --print-xml", "vmx-compare") +c.add_compare("%(OVF_IMG1)s --disk-format none --destination /tmp --print-xml", "ovf-compare") diff --git a/tests/virtconv-files/libvirt_output/ovf2libvirt_ovf_directory.libvirt b/tests/virtconv-files/libvirt_output/ovf2libvirt_ovf_directory.libvirt new file mode 100644 index 00000000..c88c140d --- /dev/null +++ b/tests/virtconv-files/libvirt_output/ovf2libvirt_ovf_directory.libvirt @@ -0,0 +1,64 @@ + + CentOS-6.4-i386-Gnome.ovf + 00000000-1111-2222-3333-444444444444 + 524288 + 524288 + 1 + + hvm + + + + + + + + + + + + + destroy + restart + restart + + /usr/bin/qemu-system-x86_64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Copying CentOS-6.4-i386-Gnome-disk1.vmdk to /var/lib/libvirt/images/CentOS-6.4-i386-Gnome-disk1 diff --git a/tests/virtconv-files/libvirt_output/ovf2libvirt_test1.libvirt b/tests/virtconv-files/libvirt_output/ovf2libvirt_test1.libvirt new file mode 100644 index 00000000..22978cab --- /dev/null +++ b/tests/virtconv-files/libvirt_output/ovf2libvirt_test1.libvirt @@ -0,0 +1,71 @@ + + test.ovf + 00000000-1111-2222-3333-444444444444 + This is the description, created by RWMJ. + 795648 + 795648 + 3 + + hvm + + + + + + + + + + + + + destroy + restart + restart + + /usr/bin/qemu-system-x86_64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Copying test.ovf-disk1.vmdk to /var/lib/libvirt/images/test.ovf-disk1 +Copying testfile to /var/lib/libvirt/images/testfile diff --git a/tests/virtconv-files/libvirt_output/ovf2libvirt_test1.libvirt.disk_qcow2 b/tests/virtconv-files/libvirt_output/ovf2libvirt_test1.libvirt.disk_qcow2 new file mode 100644 index 00000000..d86ced04 --- /dev/null +++ b/tests/virtconv-files/libvirt_output/ovf2libvirt_test1.libvirt.disk_qcow2 @@ -0,0 +1,71 @@ + + test.ovf + 00000000-1111-2222-3333-444444444444 + This is the description, created by RWMJ. + 795648 + 795648 + 3 + + hvm + + + + + + + + + + + + + destroy + restart + restart + + /usr/bin/qemu-system-x86_64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Running /usr/bin/qemu-img convert -O qcow2 test.ovf-disk1.vmdk /var/lib/libvirt/images/test.ovf-disk1.qcow2 +Running /usr/bin/qemu-img convert -O qcow2 testfile /var/lib/libvirt/images/testfile.qcow2 diff --git a/tests/virtconv-files/libvirt_output/ovf2libvirt_test2.libvirt b/tests/virtconv-files/libvirt_output/ovf2libvirt_test2.libvirt new file mode 100644 index 00000000..aa0303e5 --- /dev/null +++ b/tests/virtconv-files/libvirt_output/ovf2libvirt_test2.libvirt @@ -0,0 +1,65 @@ + + w2k3_32bit + 00000000-1111-2222-3333-444444444444 + Description added by RWMJ. + 1048576 + 1048576 + 1 + + hvm + + + + + + + + + + + + + destroy + restart + restart + + /usr/bin/qemu-system-x86_64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Copying w2k3 32bit-disk1.vmdk to /var/lib/libvirt/images/w2k3_32bit-disk1 diff --git a/tests/virtconv-files/libvirt_output/vmx2libvirt_test-vmx-zip.libvirt b/tests/virtconv-files/libvirt_output/vmx2libvirt_test-vmx-zip.libvirt new file mode 100644 index 00000000..179978be --- /dev/null +++ b/tests/virtconv-files/libvirt_output/vmx2libvirt_test-vmx-zip.libvirt @@ -0,0 +1,70 @@ + + minix + 00000000-1111-2222-3333-444444444444 + 204800 + 204800 + 1 + + hvm + + + + + + + + + + + + + + destroy + restart + restart + + /usr/bin/qemu-system-x86_64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +test-vmx-zip.zip appears to be an archive, running: unar -o /var/tmp/virt-convert-tmp test-vmx-zip.zip +Copying MS-DOS.vmdk to /var/lib/libvirt/images/MS-DOS diff --git a/tests/virtconv-files/libvirt_output/vmx2libvirt_test1.libvirt b/tests/virtconv-files/libvirt_output/vmx2libvirt_test1.libvirt new file mode 100644 index 00000000..1ff4eec8 --- /dev/null +++ b/tests/virtconv-files/libvirt_output/vmx2libvirt_test1.libvirt @@ -0,0 +1,67 @@ + + fedora + 00000000-1111-2222-3333-444444444444 + 524288 + 524288 + 1 + + hvm + + + + + + + + + + + + + destroy + restart + restart + + /usr/bin/qemu-system-x86_64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Copying fedora.vmdk to /var/lib/libvirt/images/fedora diff --git a/tests/virtconv-files/libvirt_output/vmx2libvirt_test1.libvirt.disk_raw b/tests/virtconv-files/libvirt_output/vmx2libvirt_test1.libvirt.disk_raw new file mode 100644 index 00000000..2abd1e20 --- /dev/null +++ b/tests/virtconv-files/libvirt_output/vmx2libvirt_test1.libvirt.disk_raw @@ -0,0 +1,67 @@ + + fedora + 00000000-1111-2222-3333-444444444444 + 524288 + 524288 + 1 + + hvm + + + + + + + + + + + + + destroy + restart + restart + + /usr/bin/qemu-system-x86_64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Running /usr/bin/qemu-img convert -O raw fedora.vmdk /var/lib/libvirt/images/fedora.raw diff --git a/tests/virtconv-files/libvirt_output/vmx2libvirt_vmx-dir.libvirt b/tests/virtconv-files/libvirt_output/vmx2libvirt_vmx-dir.libvirt new file mode 100644 index 00000000..7887f369 --- /dev/null +++ b/tests/virtconv-files/libvirt_output/vmx2libvirt_vmx-dir.libvirt @@ -0,0 +1,68 @@ + + esx4.0-rhel4.8-i386 + 00000000-1111-2222-3333-444444444444 + 524288 + 524288 + 2 + + hvm + + + + + + + + + + + + + + destroy + restart + restart + + /usr/bin/qemu-system-x86_64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Copying ESX4.0-rhel4u8-32b-flat.vmdk to /var/lib/libvirt/images/ESX4.0-rhel4u8-32b-flat diff --git a/tests/virtconv-files/ovf_input/ovf_directory/CentOS-6.4-i386-Gnome-disk1.vmdk b/tests/virtconv-files/ovf_input/ovf_directory/CentOS-6.4-i386-Gnome-disk1.vmdk new file mode 100644 index 0000000000000000000000000000000000000000..68784859b0a226410e5c750c36d2c1421f9db767 GIT binary patch literal 10480 zcmeIuF#!Mo0K%a4Pi+kkh(KY$fB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM Q7%*VKfB^#r3>f$x7%1=n0RR91 literal 0 HcmV?d00001 diff --git a/tests/virtconv-files/ovf_input/ovf_directory/CentOS-6.4-i386-Gnome.ovf b/tests/virtconv-files/ovf_input/ovf_directory/CentOS-6.4-i386-Gnome.ovf new file mode 100644 index 00000000..9409c9d9 --- /dev/null +++ b/tests/virtconv-files/ovf_input/ovf_directory/CentOS-6.4-i386-Gnome.ovf @@ -0,0 +1,263 @@ + + + + + + + List of the virtual disks used in the package + + + + Logical networks used in the package + + Logical network used by this appliance. + + + + A virtual machine + + The kind of installed guest operating system + RedHat + RedHat + + + Virtual hardware requirements for a virtual machine + + Virtual Hardware Family + 0 + CentOS-6.4-i386-Gnome + virtualbox-2.2 + + + 1 virtual CPU + Number of virtual CPUs + 1 virtual CPU + 1 + 3 + 1 + + + MegaBytes + 512 MB of memory + Memory Size + 512 MB of memory + 2 + 4 + 512 + + + 0 + ideController0 + IDE Controller + ideController0 + 3 + PIIX4 + 5 + + + 1 + ideController1 + IDE Controller + ideController1 + 4 + PIIX4 + 5 + + + 0 + sataController0 + SATA Controller + sataController0 + 5 + AHCI + 20 + + + true + Ethernet adapter on 'NAT' + NAT + Ethernet adapter on 'NAT' + 6 + E1000 + 10 + + + 0 + usb + USB Controller + usb + 7 + 23 + + + 3 + false + sound + Sound Card + sound + 8 + ensoniq1371 + 35 + + + 0 + true + cdrom1 + CD-ROM Drive + cdrom1 + 9 + 4 + 15 + + + 0 + disk1 + Disk Image + disk1 + /disk/vmdisk1 + 10 + 5 + 17 + + + + Complete VirtualBox machine configuration in VirtualBox format + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/virtconv-files/virtimage_input/test1.virt-image b/tests/virtconv-files/virtimage_input/test1.virt-image deleted file mode 100644 index dfe60332..00000000 --- a/tests/virtconv-files/virtimage_input/test1.virt-image +++ /dev/null @@ -1,48 +0,0 @@ - - test-image - - - - - xen - i386 - - - - pygrub - - - - - - - - i686 - - - - hvm - - - - - - - - 7 - 262144 - - - - - - - - - - - - - - - diff --git a/tests/virtconv-files/virtimage_output/convert-qcow2.virt-image b/tests/virtconv-files/virtimage_output/convert-qcow2.virt-image deleted file mode 100644 index b6dae17f..00000000 --- a/tests/virtconv-files/virtimage_output/convert-qcow2.virt-image +++ /dev/null @@ -1,25 +0,0 @@ - - conv-image - - - - - - x86_64 - - - - - - - - 2 - 524288 - - - - - - - - diff --git a/tests/virtconv-files/virtimage_output/ovf2virtimage_test1.virt-image b/tests/virtconv-files/virtimage_output/ovf2virtimage_test1.virt-image deleted file mode 100644 index 06123dcf..00000000 --- a/tests/virtconv-files/virtimage_output/ovf2virtimage_test1.virt-image +++ /dev/null @@ -1,27 +0,0 @@ - - test.ovf - - This is the description, created by RWMJ. - - - - i686 - - - - - - - - - 3 - 795648 - - - - - - - - - diff --git a/tests/virtconv-files/virtimage_output/ovf2virtimage_test2.virt-image b/tests/virtconv-files/virtimage_output/ovf2virtimage_test2.virt-image deleted file mode 100644 index cf73e6e5..00000000 --- a/tests/virtconv-files/virtimage_output/ovf2virtimage_test2.virt-image +++ /dev/null @@ -1,25 +0,0 @@ - - w2k3_32bit - - Description added by RWMJ. - - - - i686 - - - - - - - - 1 - 1048576 - - - - - - - - diff --git a/tests/virtconv-files/virtimage_output/test1.virt-image b/tests/virtconv-files/virtimage_output/test1.virt-image deleted file mode 100644 index 90346e03..00000000 --- a/tests/virtconv-files/virtimage_output/test1.virt-image +++ /dev/null @@ -1,29 +0,0 @@ - - test-image - - - - - - i686 - - - - - - - - - - 7 - 262144 - - - - - - - - - - diff --git a/tests/virtconv-files/virtimage_output/vmx2virtimage_test-vmdk-desc.virt-image b/tests/virtconv-files/virtimage_output/vmx2virtimage_test-vmdk-desc.virt-image deleted file mode 100644 index c9aca5c6..00000000 --- a/tests/virtconv-files/virtimage_output/vmx2virtimage_test-vmdk-desc.virt-image +++ /dev/null @@ -1,25 +0,0 @@ - - esx4.0-rhel4.8-i386 - - - - - - i686 - - - - - - - - 2 - 524288 - - - - - - - - diff --git a/tests/virtconv-files/virtimage_output/vmx2virtimage_test1.virt-image b/tests/virtconv-files/virtimage_output/vmx2virtimage_test1.virt-image deleted file mode 100644 index b931cd9c..00000000 --- a/tests/virtconv-files/virtimage_output/vmx2virtimage_test1.virt-image +++ /dev/null @@ -1,25 +0,0 @@ - - fedora - - - - - - i686 - - - - - - - - 1 - 524288 - - - - - - - - diff --git a/tests/virtconv-files/vmx_input/test-vmx-zip.zip b/tests/virtconv-files/vmx_input/test-vmx-zip.zip new file mode 100644 index 0000000000000000000000000000000000000000..3098d502e8b1a88afe8dc29e88d8bfe98b1d8bbd GIT binary patch literal 2130 zcmWIWW@h1H0D;rh?k->klwf0!VaUzQ%dF534dG;9j&=GPGzo}HE4UdLSzagpgP5Uej9*coDWV18rFp$(WW4RO$e9gaD>36<|xQIerZSVKhtT2A%dhY#^{l z`6GYW`_4}qwJwhY0tMK;RGA*VxivfKp?iw8=F`_3FE8;8)KuUS;XL$_LgeD}HOFN5yEdDS;oL|y8x2!F;T<=@zO zIkQHgJ+WE&P4W9={x=%NqQ`f~>CH%q=eu_$;mxWK0-?tkH(iY2smlH@TlXT2Idq6=*gvNQjW^&9f<{8StFUVP_Lk7;K%7fnl?^w)5smN#?m`oQ?E{au@udq`A6)aXoDm!P_)6K6GUT49K|X4;te$ge4nqbx&RpaHxwBdgwRt!URhCM zEH}%cOX9Vq`mD7ZLktAhNzT8yH)fIN z3u#ZTbL}d|pWl40d2Vf7Ek5J&;dnkHhMAY0m9I1;tL`?HEby-LdM>rj*hgI7Cz@@c z>mNDi0M-7oN4tW5e%9L%@bs=|`pU9HpMD3|*KX6f=G6aU`L7isef57zII@-YE(tm* z8rPGm|NYOTFG0x`=F@D=+je$%^3Q)Y*-0lN`rD#sXY7v2>h+eYr>wO;Ebu>1>B5AJ z?sI+5@9UkP_UNQV-lmHc?LKmIgdPQ{{4Rf&tAD*`SNE@qkgDARVV^#3-rsVv)&8Go zx?SP3cYlmmuiv}nd)JquuaC?#U!H!+^vliY=7UCNo@K?%oKsRX8YTB`FHcGE`#@#J^n(`22*exOaA*HrE5SoGUEm zwWlZeUhTTZaz;H&=h{85mxancqJydnVy|~s&p~xgZ?g+Cl_tjUi9 zG6Mdr54o*^l#py!Q*%DT{C&Z9kn>`&kRfNGpB~EbSSY1v86*VN0U}+$@y(3TP~-zQSWHW|agn7F3ySX> outbuf, msg - def setUp(self): - pass + converter = VirtConverter(conn, infile, print_cb=print_cb) - def _convert_helper(self, infile, outfile, in_type, out_type): - inp = virtconv.formats.find_parser_by_file(infile) - outp = virtconv.formats.parser_by_name(out_type) - - if not inp or inp.name != in_type: + if converter.parser.name != in_type: raise AssertionError("find_parser_by_file for '%s' returned " "wrong parser type.\n" "Expected: %s\n" "Received: %s\n" % - (infile, in_type, - str((not inp) and str(inp) or inp.name))) + (infile, in_type, converter.parser.name)) - vmdef = inp.import_file(infile) - out_expect = outp.export(vmdef) + converter.convert_disks(disk_format, dry=True) + guest = converter.get_guest() + ignore, out_xml = guest.start_install(return_xml=True) + out_expect = out_xml + if outbuf.getvalue(): + out_expect += ("\n\n" + outbuf.getvalue()) - if not os.path.exists(outfile): - open(outfile, "w").write(out_expect) utils.diff_compare(out_expect, outfile) + utils.test_create(converter.conn, out_xml) - def _build_compare_path(self, base, in_path, out_dir, out_type): - out_path = os.path.basename(in_path).rsplit(".", 1)[0] - return "%s/%s_%s.%s" % (out_dir, base, out_path, out_type) - - def _compare_files(self, base, in_type, out_type, in_dir, out_dir): + def _compare_single_file(self, in_path, in_type, disk_format=None): cwd = os.getcwd() - in_dir = os.path.join(cwd, in_dir) - out_dir = os.path.join(cwd, out_dir) + base = in_type + "2libvirt" + in_base = os.path.basename(in_path).rsplit(".", 1)[0] + out_path = "%s/%s_%s.%s" % (out_dir, base, in_base, "libvirt") + if disk_format: + out_path += ".disk_%s" % disk_format - for in_path in glob.glob(os.path.join(in_dir, "*." + in_type)): - if in_type != out_type: - out_path = self._build_compare_path(base, in_path, - out_dir, out_type) - else: - out_path = in_path + try: + os.chdir(os.path.dirname(in_path)) + self._convert_helper(in_path, out_path, in_type, disk_format) + finally: + os.chdir(cwd) - try: - os.chdir(os.path.dirname(in_path)) - self._convert_helper(in_path, out_path, in_type, out_type) - finally: - os.chdir(cwd) + def _compare_files(self, in_type): + in_dir = base_dir + in_type + "_input" - def testVMX2VirtImage(self): - base = "vmx2virtimage" - in_type = "vmx" - out_type = "virt-image" - in_dir = vmx_input - out_dir = virtimage_output + if not os.path.exists(in_dir): + raise RuntimeError("Directory does not exist: %s" % in_dir) - self._compare_files(base, in_type, out_type, in_dir, out_dir) + for in_path in glob.glob(os.path.join(in_dir, "*")): + self._compare_single_file(in_path, in_type) - def testVirtImage2VMX(self): - base = "virtimage2vmx" - in_type = "virt-image" - out_type = "vmx" - in_dir = virtimage_input - out_dir = vmx_output + def testOVF2Libvirt(self): + self._compare_files("ovf") + def testVMX2Libvirt(self): + self._compare_files("vmx") - self._compare_files(base, in_type, out_type, in_dir, out_dir) - - def testOVF2VirtImage(self): - base = "ovf2virtimage" - in_type = "ovf" - out_type = "virt-image" - in_dir = ovf_input - out_dir = virtimage_output - - self._compare_files(base, in_type, out_type, in_dir, out_dir) - - # For x2x conversion, we want to use already tested output, since ideally - # we should be able to run a generated config continually through the - # converter and it will generate the same result - def testVMX2VMX(self): - base = None - in_type = out_type = "vmx" - in_dir = out_dir = vmx_output - - self._compare_files(base, in_type, out_type, in_dir, out_dir) - - def testVirtImage2VirtImage(self): - base = None - in_type = out_type = "virt-image" - in_dir = out_dir = virtimage_output - - self._compare_files(base, in_type, out_type, in_dir, out_dir) + def testDiskConvert(self): + self._compare_single_file( + base_dir + "ovf_input/test1.ovf", "ovf", disk_format="qcow2") + self._compare_single_file( + base_dir + "vmx_input/test1.vmx", "vmx", disk_format="raw") diff --git a/virt-convert b/virt-convert index bdc01341..98cb6fb6 100755 --- a/virt-convert +++ b/virt-convert @@ -1,7 +1,8 @@ #!/usr/bin/python # -# Copyright 2008, 2013 Red Hat, Inc. +# Copyright 2008, 2013, 2014 Red Hat, Inc. # Joey Boggs +# Cole Robinson # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. @@ -21,261 +22,104 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. -import argparse -import errno -import logging -import os import sys from virtinst import cli -from virtinst.cli import fail, print_stdout, print_stderr -import virtconv.formats as formats -import virtconv.vmcfg as vmcfg -import virtconv.diskcfg as diskcfg +from virtinst.cli import fail, print_stderr, print_stdout + +from virtconv import VirtConverter + +# Example appliances: +# +# OVF/OVA: +# http://virtualboxes.org/tag/ova/ +# VMX, but they are all multipart which is current unsupported +# http://www.thoughtpolice.co.uk/vmware/ +# Minix VMX: +# http://download.minix3.org/iso/minix3_1_2a_vmware.zip -def get_default_arch(): - arch = os.uname()[4] - if arch == "x86_64": - return "x86_64" - return "i686" - +##################### +# Argument handling # +##################### def parse_args(): - """Parse and verify command line.""" + desc =_( +"Convert an OVF or VMX appliance to native libvirt XML, and run " +"the guest.\nThe VM contents are not altered. Disk images are " +"copied to the hypervisor\ndefault storage location.\n\n" +"Examples:\n" +" virt-convert fedora18.ova\n" +" virt-convert centos6.zip --disk-format qcow2" +) parser = cli.setupParser( - "%(prog)s inputdir|input.vmx [outputdir|output.xml] [options]", - _("Convert from virtual machine descriptor format to another. The " - "VM contents are not altered.")) + "%(prog)s inputconfig [options]", desc) parser.add_argument("input", metavar="inputconfig", nargs=1, - help=_("Conversion input: flat file or directory.")) - def add_output_arg(p): - p.add_argument("output", metavar="outputconfig", nargs='?', - help=_("Conversion destination")) - add_output_arg(parser) + help=_("Conversion input. Can be a ovf/vmx file, a directory " + "containing a config and disk images, or a zip/ova/7z/etc " + "archive.")) + cli.add_connect_option(parser) cong = parser.add_argument_group("Conversion Options") cong.add_argument("-i", "--input-format", - help=_("Input format, e.g. 'vmx'")) - cong.add_argument("-o", "--output-format", - default="virt-image", - help=_("Output format, e.g. 'virt-image'")) - cong.add_argument("-D", "--disk-format", - help=_("Output disk format")) - - virg = parser.add_argument_group("Virtualization Type Options") - virg.add_argument("-v", "--hvm", action="store_true", dest="fullvirt", - help=_("This guest should be a fully virtualized guest")) - virg.add_argument("-p", "--paravirt", action="store_true", dest="paravirt", - help=_("This guest should be a paravirtualized guest")) - - cfgg = parser.add_argument_group("Guest Configuration Options") - cfgg.add_argument("-a", "--arch", - default=get_default_arch(), - help=_("Machine Architecture Type (i686/x86_64/ppc)")) - cli.add_distro_options(cfgg) - cli.add_old_feature_options(cfgg) + help=_("Force the input format. 'vmx' or 'ovf'")) + cong.add_argument("-D", "--disk-format", default='raw', + help=_("Output disk format. default is 'raw'. " + "Disable conversion with 'none'")) + cong.add_argument("--destination", default=None, + help=_("Destination directory the disk images should be " + "converted/copied to. Defaults to the default " + "libvirt directory.")) misc = parser.add_argument_group("Miscellaneous Options") - cli.add_misc_options(misc, dryrun=True) + cli.add_misc_options(misc, dryrun=True, printxml=True, noautoconsole=True) - options, leftovers = parser.parse_known_args() - if options.input: - options.input = options.input[0] - - # argparse does not allow interspersed positional arguments, which we - # used to allow with optparse. All this crazyness is to keep old - # cli working - parser2 = argparse.ArgumentParser() - add_output_arg(parser2) - if not options.output: - opt2, leftovers = parser2.parse_known_args(leftovers) - options.output = opt2.output - if leftovers: - leftovers = sys.argv[:] - if options.output in leftovers: - leftovers.pop(leftovers.index(options.output)) - if options.input in leftovers: - leftovers.pop(leftovers.index(options.input)) - parser.parse_args(leftovers) - - cli.setupLogging("virt-convert", options.debug, options.quiet) - - if (options.disk_format and - options.disk_format not in diskcfg.disk_formats()): - parser.error(_("Unknown output disk format \"%s\"") % - options.disk_format) - - if not options.output: - options.output_file = None - options.output_dir = None - if os.path.isdir(options.input): - options.output_dir = options.input - elif os.path.isdir(options.output) or options.output.endswith("/"): - options.output_file = None - options.output_dir = options.output - else: - options.output_file = options.output - options.output_dir = os.path.dirname(os.path.realpath(options.output)) - - if options.output_format not in formats.formats(): - parser.error(_("Unknown output format \"%s\")" % - options.output_format)) - if options.output_format not in formats.output_formats(): - parser.error(_("No output handler for format \"%s\")" - % options.output_format)) - - if not os.access(options.input, os.R_OK): - parser.error(_("Couldn't access input argument \"%s\"\n") % options.input) - sys.exit(1) - - if not options.input_format: - try: - (options.input, options.input_format) = formats.find_input(options.input) - except StandardError, e: - parser.error(_("Couldn't determine input format for \"%s\": %s") % - (options.input, e)) - sys.exit(1) - - if options.input_format not in formats.formats(): - parser.error(_("Unknown input format \"%s\")" % options.input_format)) - if options.input_format not in formats.input_formats(): - parser.error(_("No input handler for format \"%s\"") - % options.input_format) - - if os.path.isdir(options.input): - (options.input_file, ignore) = formats.find_input(options.input, - options.input_format) - options.input_dir = options.input - else: - options.input_file = options.input - options.input_dir = os.path.dirname(os.path.realpath(options.input)) + options = parser.parse_args() + options.input = options.input[0] return options -def cleanup(msg, options, vmdef, paths): - """ - After failure, clean up anything we created. - """ - logging.error(msg) - if options.dry: - return +####################### +# Functional handlers # +####################### - try: - for disk in vmdef.disks.values(): - disk.cleanup() - - paths.reverse() - for path in paths: - if os.path.isdir(path): - os.rmdir(path) - elif os.path.isfile(path): - os.remove(path) - except OSError, e: - fail(_("Couldn't clean up output directory \"%s\": %s") % - (options.output_dir, e.strerror)) - - sys.exit(1) - - -def main(): +def main(conn=None): cli.earlyLogging() options = parse_args() + cli.setupLogging("virt-convert", options.debug, options.quiet) - inp = formats.parser_by_name(options.input_format) - outp = formats.parser_by_name(options.output_format) + if conn is None: + conn = cli.getConnection(options.connect) + if options.xmlonly: + options.dry = True + options.quiet = True - vmdef = None + conscb = options.autoconsole and cli.show_console_for_guest or None + converter = VirtConverter(conn, options.input, + input_name=options.input_format, print_cb=print_stdout) try: - vmdef = inp.import_file(options.input_file) - except IOError, e: - fail(_("Couldn't import file \"%s\": %s") % - (options.input_file, e.strerror)) - except Exception, e: - fail(_("Couldn't import file \"%s\": %s") % (options.input_file, e)) + converter.convert_disks(options.disk_format or "none", + destdir=options.destination, dry=options.dry) - if options.paravirt: - vmdef.type = vmcfg.VM_TYPE_PV - else: - vmdef.type = vmcfg.VM_TYPE_HVM + guest = converter.get_guest() - vmdef.arch = options.arch - cli.set_os_variant(vmdef, options.distro_type, options.distro_variant) - vmdef.noapic = options.noapic - vmdef.noacpi = options.noacpi + if options.xmlonly: + print_stdout(guest.start_install(return_xml=True)[1], + do_force=True) + elif not options.dry: + print_stdout(_("Creating guest '%s'.") % guest.name) + guest.start_install() + cli.connect_console(guest, conscb, True) + except: + converter.cleanup() + raise - clean = [] - - unixname = vmdef.name.replace(" ", "-") - - if not options.output_dir: - options.output_dir = unixname - try: - logging.debug("Creating directory %s", options.output_dir) - if not options.dry: - os.mkdir(options.output_dir) - clean += [options.output_dir] - except OSError, e: - if (e.errno != errno.EEXIST): - fail("Could not create directory %s: %s" % - (options.output_dir, e.strerror)) - - if not options.output_file: - options.output_file = os.path.join(options.output_dir, - "%s%s" % (unixname, outp.suffix)) - - logging.debug("input_file: %s", options.input_file) - logging.debug("input_dir: %s", options.input_dir) - logging.debug("output_file: %s", options.output_file) - logging.debug("output_dir: %s", options.output_dir) - - print_stdout(_("Generating output in '%(format)s' format to %(dir)s/") % - {"format": options.output_format, "dir": options.output_dir}) - - try: - for d in vmdef.disks.values(): - dformat = options.disk_format - - if not dformat: - if options.output_format == "vmx": - dformat = "vmdk" - else: - dformat = "raw" - - if d.path and dformat != "none": - print_stdout(_("Converting disk '%(path)s' to type " - "%(format)s...") % {"path": d.path, - "format": dformat}) - - if not options.dry: - d.convert(options.input_dir, options.output_dir, dformat) - - except OSError, e: - cleanup(_("Couldn't convert disks: %s") % e.strerror, - options, vmdef, clean) - except RuntimeError, e: - cleanup(_("Couldn't convert disks: %s") % e, options, vmdef, clean) - - try: - output = outp.export(vmdef) - logging.debug("Output VM config:\n%s", output) - - if not options.dry: - outfile = open(options.output_file, "w") - outfile.writelines(output) - outfile.close() - - clean += [options.output_file] - except ValueError, e: - cleanup(_("Couldn't export to file \"%s\": %s") % - (options.output_file, e), options, vmdef, clean) - - print_stdout("Done.") return 0 + if __name__ == "__main__": try: sys.exit(main()) diff --git a/virt-install b/virt-install index 286bab3b..2a24d41c 100755 --- a/virt-install +++ b/virt-install @@ -19,7 +19,6 @@ import argparse import logging -import os import re import sys import time @@ -487,38 +486,6 @@ def build_guest_instance(conn, options, parsermap): # Install process helpers # ########################### -def _run_console(args): - logging.debug("Running: %s", " ".join(args)) - child = os.fork() - if child: - return child - - os.execvp(args[0], args) - os._exit(1) # pylint: disable=W0212 - - -def vnc_console(dom, uri): - args = ["/usr/bin/virt-viewer", - "--connect", uri, - "--wait", str(dom.ID())] - - if not os.path.exists(args[0]): - logging.warn(_("Unable to connect to graphical console: " - "virt-viewer not installed. Please install " - "the 'virt-viewer' package.")) - return None - - return _run_console(args) - - -def txt_console(dom, uri): - args = ["/usr/bin/virsh", - "--connect", uri, - "console", str(dom.ID())] - - return _run_console(args) - - def domain_is_crashed(domain): """ Return True if the created domain object is in a crashed state @@ -554,44 +521,7 @@ def domain_is_shutdown(domain): return state == libvirt.VIR_DOMAIN_NOSTATE and cpu_time == 0 -def connect_console(domain, consolecb, wait): - """ - Launched the passed console callback for the already defined - domain. If domain isn't running, return an error. - """ - child = None - if consolecb: - child = consolecb(domain) - - if not child or not wait: - return - - # If we connected the console, wait for it to finish - try: - os.waitpid(child, 0) - except OSError, e: - logging.debug("waitpid: %s: %s", e.errno, e.message) - - def start_install(guest, continue_inst, options): - def show_console(dom): - xmlobj = virtinst.Guest(guest.conn, parsexml=dom.XMLDesc(0)) - gdev = xmlobj.get_devices("graphics") - if not gdev: - logging.debug("Connecting to text console") - return txt_console(dom, guest.conn.getURI()) - - gtype = gdev[0].type - if gtype in [virtinst.VirtualGraphics.TYPE_VNC, - virtinst.VirtualGraphics.TYPE_SPICE]: - logging.debug("Launching virt-viewer for graphics type '%s'", - gtype) - return vnc_console(dom, guest.conn.getURI()) - else: - logging.debug("No viewer to launch for graphics type '%s'", - gtype) - return None - # There are two main cases we care about: # # Scripts: these should specify --wait always, maintaining the @@ -616,7 +546,7 @@ def start_install(guest, continue_inst, options): # --wait 0 implies --noautoconsole options.autoconsole = (wait_time != 0) and options.autoconsole or False - conscb = options.autoconsole and show_console or None + conscb = options.autoconsole and cli.show_console_for_guest or None meter = (options.quiet and progress.BaseMeter() or progress.TextMeter(fo=sys.stdout)) @@ -631,13 +561,13 @@ def start_install(guest, continue_inst, options): # Do first install phase dom = guest.start_install(meter=meter, noboot=options.noreboot) - connect_console(dom, conscb, wait_on_console) + cli.connect_console(guest, conscb, wait_on_console) dom = check_domain(guest, dom, conscb, wait_on_install, wait_time, start_time) if continue_inst: dom = guest.continue_install(meter=meter) - connect_console(dom, conscb, wait_on_console) + cli.connect_console(guest, conscb, wait_on_console) dom = check_domain(guest, dom, conscb, wait_on_install, wait_time, start_time) @@ -649,7 +579,7 @@ def start_install(guest, continue_inst, options): print_stdout( _("Guest installation complete... restarting guest.")) dom.create() - connect_console(dom, conscb, wait=True) + cli.connect_console(guest, conscb, True) except KeyboardInterrupt: logging.debug("", exc_info=True) @@ -860,11 +790,7 @@ def parse_args(): netg.add_argument("--nonetworks", action="store_true", help=_("Don't create network interfaces for the guest.")) - vncg = cli.graphics_option_group(parser) - vncg.add_argument("--noautoconsole", action="store_false", - dest="autoconsole", default=True, - help=_("Don't automatically try to connect to the guest " - "console")) + cli.graphics_option_group(parser) devg = parser.add_argument_group(_("Device Options")) cli.add_device_options(devg, sound_back_compat=True) @@ -895,7 +821,7 @@ def parse_args(): help=_("Minutes to wait for install to complete.")) cli.add_misc_options(misc, prompt=True, printxml=True, printstep=True, - noreboot=True, dryrun=True) + noreboot=True, dryrun=True, noautoconsole=True) return parser.parse_args() diff --git a/virtconv/__init__.py b/virtconv/__init__.py index 5cdca2b8..9942ec03 100644 --- a/virtconv/__init__.py +++ b/virtconv/__init__.py @@ -19,20 +19,4 @@ # MA 02110-1301 USA. # -import pkgutil -import imp -import os - -parsers_path = [os.path.join(__path__[0], "parsers/")] - -# iter_modules is only in Python 2.5, sadly -parser_names = ["vmx", "virtimage", "ovf"] - -if hasattr(pkgutil, "iter_modules"): - parser_names = [] - for ignore, name, ignore in pkgutil.iter_modules(parsers_path): - parser_names += [name] - -for name in parser_names: - filename, pathname, desc = imp.find_module(name, parsers_path) - imp.load_module(name, filename, pathname, desc) +from virtconv.formats import VirtConverter diff --git a/virtconv/diskcfg.py b/virtconv/diskcfg.py deleted file mode 100644 index 103f6cc5..00000000 --- a/virtconv/diskcfg.py +++ /dev/null @@ -1,316 +0,0 @@ -# -# Copyright 2013 Red Hat, Inc. -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# 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. -# - -import subprocess -import shutil -import errno -import sys -import os -import re -import logging - - -DISK_FORMAT_NONE = 0 -DISK_FORMAT_RAW = 1 -DISK_FORMAT_VMDK = 2 -DISK_FORMAT_VDISK = 3 -DISK_FORMAT_QCOW = 4 -DISK_FORMAT_QCOW2 = 5 -DISK_FORMAT_COW = 6 -DISK_FORMAT_VDI = 7 - -DISK_TYPE_DISK = 0 -DISK_TYPE_CDROM = 1 -DISK_TYPE_ISO = 2 - -CSUM_SHA1 = 0 -CSUM_SHA256 = 1 - -disk_suffixes = { - DISK_FORMAT_RAW: ".raw", - DISK_FORMAT_VMDK: ".vmdk", - DISK_FORMAT_VDISK: ".vdisk", - DISK_FORMAT_QCOW: ".qcow", - DISK_FORMAT_QCOW2: ".qcow2", - DISK_FORMAT_COW: ".cow", - DISK_FORMAT_VDI: ".vdi", -} - -qemu_formats = { - DISK_FORMAT_RAW: "raw", - DISK_FORMAT_VMDK: "vmdk", - DISK_FORMAT_VDISK: "vdisk", - DISK_FORMAT_QCOW: "qcow", - DISK_FORMAT_QCOW2: "qcow2", - DISK_FORMAT_COW: "cow", - DISK_FORMAT_VDI: "vdi", -} - -disk_format_names = { - "none": DISK_FORMAT_NONE, - "raw": DISK_FORMAT_RAW, - "vmdk": DISK_FORMAT_VMDK, - "vdisk": DISK_FORMAT_VDISK, - "qcow": DISK_FORMAT_QCOW, - "qcow2": DISK_FORMAT_QCOW2, - "cow": DISK_FORMAT_COW, - "vdi": DISK_FORMAT_VDI, -} - -checksum_types = { - CSUM_SHA1 : "sha1", - CSUM_SHA256 : "sha256", -} - - -def ensuredirs(path): - """ - Make sure that all the containing directories of the given file - path exist. - """ - try: - os.makedirs(os.path.dirname(path)) - except OSError, e: - if e.errno != errno.EEXIST: - raise - - -def run_cmd(cmd): - """ - Return the exit status and output to stdout and stderr. - """ - logging.debug("Running command: %s", " ".join(cmd)) - proc = subprocess.Popen(cmd, stderr=subprocess.PIPE, - stdout=subprocess.PIPE, - close_fds=True) - ret = proc.wait() - return ret, proc.stdout.readlines(), proc.stderr.readlines() - - -def run_vdiskadm(args): - """Run vdiskadm, returning the output.""" - ret, stdout, stderr = run_cmd(["/usr/sbin/vdiskadm"] + args) - - if ret != 0: - raise RuntimeError("Disk conversion failed with " - "exit status %d: %s" % (ret, "".join(stderr))) - if len(stderr): - print >> sys.stderr, stderr - - return stdout - - -class disk(object): - """Definition of an individual disk instance.""" - - def __init__(self, path=None, fmt=DISK_FORMAT_NONE, bus="ide", - typ=DISK_TYPE_DISK): - self.path = path - self.format = fmt - self.bus = bus - self.type = typ - self.clean = [] - self.csum_dict = {} - - def cleanup(self): - """ - Remove any generated output. - """ - - for path in self.clean: - if os.path.isfile(path): - os.remove(path) - if os.path.isdir(path): - os.removedirs(path) - - self.clean = [] - - def copy_file(self, infile, outfile): - """Copy an individual file.""" - self.clean += [outfile] - ensuredirs(outfile) - shutil.copy(infile, outfile) - - def out_file(self, out_format): - """Return the relative path of the output file.""" - if not out_format: - return self.path - - relout = self.path.replace(disk_suffixes[self.format], - disk_suffixes[out_format]) - return re.sub(r'\s', '_', relout) - - def vdisk_convert(self, absin, absout): - """ - Import the given disk into vdisk, including any sub-files as - necessary. - """ - - stdout = run_vdiskadm(["import", "-fnp", absin, absout]) - - for item in stdout: - ignore, path = item.strip().split(':', 1) - self.clean += [os.path.join(absout, path)] - - run_vdiskadm(["import", "-fp", absin, absout]) - - def qemu_convert(self, absin, absout, out_format): - """ - Use qemu-img to convert the given disk. Note that at least some - version of qemu-img cannot handle multi-file VMDKs, so this can - easily go wrong. - Gentoo, Debian, and Ubuntu (potentially others) install kvm-img - with kvm and qemu-img with qemu. Both would work. - """ - - self.clean += [absout] - - ret, ignore, stderr = run_cmd(["qemu-img", "convert", "-O", - qemu_formats[out_format], absin, absout]) - if ret == 127: - ret, ignore, stderr = run_cmd(["kvm-img", "convert", "-O", - qemu_formats[out_format], absin, absout]) - if ret != 0: - raise RuntimeError("Disk conversion failed with " - "exit status %d: %s" % (ret, "".join(stderr))) - if len(stderr): - print >> sys.stderr, stderr - - def copy(self, indir, outdir, out_format): - """ - If needed, copy top-level disk files to outdir. If the copy is - done, then self.path is updated as needed. - - Returns (input_in_outdir, need_conversion) - """ - - need_conversion = (out_format != DISK_FORMAT_NONE and - self.format != out_format) - - if os.path.isabs(self.path): - return True, need_conversion - - relin = self.path - absin = os.path.join(indir, relin) - relout = self.out_file(self.format) - absout = os.path.join(outdir, relout) - - # - # If we're going to use vdiskadm, it's much smarter; don't - # attempt any copies. - # - if out_format == DISK_FORMAT_VDISK: - return False, True - - # - # If we're using the same directory, just account for any spaces - # in the disk filename and we're done. - # - if indir == outdir: - if relin != relout: - # vdisks cannot have spaces - if self.format == DISK_FORMAT_VDISK: - raise RuntimeError("Disk conversion failed: " - "invalid vdisk '%s'" % self.path) - self.clean += [absout] - self.copy_file(absin, absout) - self.path = relout - return True, need_conversion - - # - # If we're not performing any conversion, just copy the file. - # XXX: This can go wrong for multi-part disks! - # - if not need_conversion: - self.clean += [absout] - self.copy_file(absin, absout) - self.path = relout - return True, False - - # - # We're doing a conversion step, so we can rely upon convert() - # to place something in outdir. - # - return False, True - - def convert(self, indir, outdir, output_format): - """ - Convert a disk into the requested format if possible, in the - given output directory. Raises RuntimeError or other failures. - """ - - if self.type != DISK_TYPE_DISK: - return - - out_format = disk_format_names[output_format] - - if not (out_format == DISK_FORMAT_NONE or - out_format == DISK_FORMAT_VDISK or - out_format == DISK_FORMAT_RAW or - out_format == DISK_FORMAT_VMDK or - out_format == DISK_FORMAT_QCOW or - out_format == DISK_FORMAT_QCOW2 or - out_format == DISK_FORMAT_COW): - raise NotImplementedError(_("Cannot convert to disk format %s") % - output_format) - - indir = os.path.normpath(os.path.abspath(indir)) - outdir = os.path.normpath(os.path.abspath(outdir)) - - input_in_outdir, need_conversion = self.copy(indir, outdir, out_format) - - if not need_conversion: - assert(input_in_outdir) - return - - if os.path.isabs(self.path): - raise NotImplementedError(_("Cannot convert disk with absolute" - " path %s") % self.path) - - if input_in_outdir: - indir = outdir - - relin = self.path - absin = os.path.join(indir, relin) - relout = self.out_file(out_format) - absout = os.path.join(outdir, relout) - - ensuredirs(absout) - - if os.getenv("VIRTCONV_TEST_NO_DISK_CONVERSION"): - self.format = out_format - self.path = self.out_file(self.format) - return - - if out_format == DISK_FORMAT_VDISK: - self.vdisk_convert(absin, absout) - else: - self.qemu_convert(absin, absout, out_format) - - self.format = out_format - self.path = relout - - -def disk_formats(): - """ - Return a list of supported disk formats. - """ - return disk_format_names.keys() diff --git a/virtconv/formats.py b/virtconv/formats.py index 36d7c50f..5eb43567 100644 --- a/virtconv/formats.py +++ b/virtconv/formats.py @@ -19,12 +19,18 @@ # MA 02110-1301 USA. # +from distutils.spawn import find_executable +import logging import os +import re +import shutil +import subprocess +import tempfile -_parsers = [] +from virtinst import StoragePool -class parser(object): +class parser_class(object): """ Base class for particular config file format definitions of a VM instance. @@ -32,7 +38,6 @@ class parser(object): Warning: this interface is not (yet) considered stable and may change at will. """ - @staticmethod def identify_file(input_file): """ @@ -41,95 +46,246 @@ class parser(object): raise NotImplementedError @staticmethod - def import_file(input_file): + def export_libvirt(conn, input_file): """ - Import a configuration file. Raises if the file couldn't be - opened, or parsing otherwise failed. - """ - raise NotImplementedError - - @staticmethod - def export(vm): - """ - Export a configuration file as a string. - @vm vm configuration instance - - Raises ValueError if configuration is not suitable. + Import a configuration file and turn it into a libvirt Guest object """ raise NotImplementedError -def register_parser(new_parser): - """ - Register a particular config format parser. This should be called by each - config plugin on import. - """ - - global _parsers - _parsers += [new_parser] +from virtconv.vmx import vmx_parser as _vmx_parser +from virtconv.ovf import ovf_parser as _ovf_parser -def parser_by_name(name): +_parsers = [ + _vmx_parser, + _ovf_parser, +] + + +def _is_test(): + return bool(os.getenv("VIRTINST_TEST_SUITE")) + + +def _find_parser_by_name(input_name): """ Return the parser of the given name. """ - parsers = [p for p in _parsers if p.name == name] + parsers = [p for p in _parsers if p.name == input_name] if len(parsers): return parsers[0] + raise RuntimeError(_("No parser found for type '%s'") % input_name) -def find_parser_by_file(input_file): +def _find_parser_by_file(input_file): """ Return the parser that is capable of comprehending the given file. """ for p in _parsers: if p.identify_file(input_file): return p - return None + raise RuntimeError(_("Don't know how to parse file %s") % input_file) -def formats(): +def _run_cmd(cmd): """ - Return a list of supported formats. + Return the exit status and output to stdout and stderr. """ - return [p.name for p in _parsers] + logging.debug("Running command: %s", " ".join(cmd)) + proc = subprocess.Popen(cmd, stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + close_fds=True) + stdout, stderr = proc.communicate() + ret = proc.wait() + + logging.debug("stdout=%s", stdout) + logging.debug("stderr=%s", stderr) + + if ret == 0: + return + + out = stdout + if stderr: + if out: + out += "\n" + out += stderr + raise RuntimeError("%s: failed with exit status %d: %s" % + (" ".join(cmd), ret, out)) -def input_formats(): +def _find_input(input_file, parser, print_cb): """ - Return a list of supported input formats. + Given the input file, determine if its a directory, archive, etc """ - return [p.name for p in _parsers if p.can_import] + force_clean = [] + + try: + ext = os.path.splitext(input_file)[1] + tempdir = None + if ext and ext[1:] in ["zip", "gz", "ova", + "tar", "bz2", "bzip2", "7z", "xz"]: + basedir = "/var/tmp" + if _is_test(): + tempdir = os.path.join(basedir, "virt-convert-tmp") + else: + tempdir = tempfile.mkdtemp( + prefix="virt-convert-tmp", dir=basedir) + + base = os.path.basename(input_file) + cmd = ["unar", "-o", tempdir, base] + print_cb(_("%s appears to be an archive, running: %s") % + (base, " ".join(cmd))) + + cmd[-1] = input_file + _run_cmd(cmd) + force_clean.append(tempdir) + input_file = tempdir + + if not os.path.isdir(input_file): + if not parser: + parser = _find_parser_by_file(input_file) + return input_file, parser, force_clean + + parsers = parser and [parser] or _parsers + for root, ignore, files in os.walk(input_file): + for p in parsers: + for f in [f for f in files if f.endswith(p.suffix)]: + path = os.path.join(root, f) + if p.identify_file(path): + return path, p, force_clean + + raise RuntimeError("Could not find parser for file %s" % input_file) + except: + for f in force_clean: + shutil.rmtree(f) + raise -def output_formats(): +class VirtConverter(object): """ - Return a list of supported output formats. + Public interface for actually performing the conversion """ - return [p.name for p in _parsers if p.can_export] + def __init__(self, conn, input_file, print_cb=None, input_name=None): + self.conn = conn + self._err_clean = [] + self._force_clean = [] + if print_cb is None: + def cb(msg): + print msg + print_cb = cb + self.print_cb = print_cb -def find_input(path, fmt=None): - """ - Search for a configuration file automatically. If @format is given, - then only search using a matching format parser. - """ + parser = None + if input_name: + parser = _find_parser_by_name(input_name) - if os.path.isdir(path): - files = os.listdir(path) + logging.debug("converter __init__ with input=%s parser=%s", + input_file, parser) - for p in _parsers: - if not p.can_identify: - continue - if fmt and fmt != p.name: - continue + (self._input_file, + self.parser, + self._force_clean) = _find_input(input_file, parser, self.print_cb) + self._top_dir = os.path.dirname(self._input_file) - if os.path.isfile(path): - if p.identify_file(path): - return (path, p.name) - elif os.path.isdir(path): - for cfgfile in [x for x in files if x.endswith(p.suffix)]: - if p.identify_file(os.path.join(path, cfgfile)): - return (os.path.join(path, cfgfile), p.name) + logging.debug("converter not input_file=%s parser=%s", + self._input_file, self.parser) - raise StandardError(_("Unknown format")) + cwd = os.getcwd() + try: + os.chdir(self._top_dir) + self._guest = self.parser.export_libvirt(self.conn, + self._input_file) + self._guest.add_default_devices() + finally: + os.chdir(cwd) + + def __del__(self): + for f in self._force_clean: + shutil.rmtree(f) + + def get_guest(self): + return self._guest + + def cleanup(self): + """ + Remove any generated output. + """ + for path in self._err_clean: + if os.path.isfile(path): + os.remove(path) + if os.path.isdir(path): + shutil.rmtree(path) + + def _copy_file(self, absin, absout, dry): + self.print_cb("Copying %s to %s" % (os.path.basename(absin), absout)) + if not dry: + shutil.copy(absin, absout) + + def _qemu_convert(self, absin, absout, disk_format, dry): + """ + Use qemu-img to convert the given disk. Note that at least some + version of qemu-img cannot handle multi-file VMDKs, so this can + easily go wrong. + Gentoo, Debian, and Ubuntu (potentially others) install kvm-img + with kvm and qemu-img with qemu. Both would work. + """ + binnames = ["qemu-img", "kvm-img"] + + if _is_test(): + executable = "/usr/bin/qemu-img" + else: + for binname in binnames: + executable = find_executable(binname) + if executable: + break + + if executable is None: + raise RuntimeError(_("None of %s tools found.") % binnames) + + base = os.path.basename(absin) + cmd = [executable, "convert", "-O", disk_format, base, absout] + self.print_cb("Running %s" % " ".join(cmd)) + if dry: + return + + cmd[4] = absin + _run_cmd(cmd) + + def convert_disks(self, disk_format, destdir=None, dry=False): + """ + Convert a disk into the requested format if possible, in the + given output directory. Raises RuntimeError or other failures. + """ + if disk_format == "none": + disk_format = None + + if destdir is None: + destdir = StoragePool.get_default_path(self.conn) + + guest = self.get_guest() + for disk in guest.get_devices("disk"): + if disk.device != "disk": + continue + + if disk_format and disk.driver_type == disk_format: + logging.debug("path=%s is already in requested format=%s", + disk.path, disk_format) + disk_format = None + + basepath = os.path.splitext(os.path.basename(disk.path))[0] + newpath = re.sub(r'\s', '_', basepath) + if disk_format: + newpath += ("." + disk_format) + newpath = os.path.join(destdir, newpath) + if os.path.exists(newpath): + raise RuntimeError(_("New path name '%s' already exists") % + newpath) + + if not disk_format or disk_format == "none": + self._copy_file(disk.path, newpath, dry) + else: + self._qemu_convert(disk.path, newpath, disk_format, dry) + disk.driver_type = disk_format + disk.path = newpath + self._err_clean.append(newpath) diff --git a/virtconv/netdevcfg.py b/virtconv/netdevcfg.py deleted file mode 100644 index 94f19b15..00000000 --- a/virtconv/netdevcfg.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (C) 2013 Red Hat, Inc. -# -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# 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. -# - -NETDEV_TYPE_UNKNOWN = 0 -NETDEV_TYPE_BRIDGE = 1 -NETDEV_TYPE_DEV = 2 -NETDEV_TYPE_NETWORK = 3 - - -class netdev(object): - """Definition of an individual network device.""" - - def __init__(self, mac="auto", typ=NETDEV_TYPE_UNKNOWN, - source=None, driver=None): - """ - @mac: either a MAC address, or "auto" - @type: NETDEV_TYPE_* - @source: bridge or net device, or network name - @driver: device emulated for VM (e.g. vmxnet) - """ - self.mac = mac - self.type = typ - self.source = source - self.driver = driver diff --git a/virtconv/ovf.py b/virtconv/ovf.py new file mode 100644 index 00000000..31609432 --- /dev/null +++ b/virtconv/ovf.py @@ -0,0 +1,386 @@ +# +# Copyright 2009, 2013 Red Hat, Inc. +# Cole Robinson +# +# 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. +# + +import logging +import os + +import libxml2 + +import virtinst + +from virtconv.formats import parser_class + + +# Mapping of ResourceType value to device type +# http://konkretcmpi.org/cim218/CIM_ResourceAllocationSettingData.html +# +# "Other" [1] +# "Computer System" [2] +# "Processor" [3] +# "Memory" [4] +# "IDE Controller" [5] +# "Parallel SCSI HBA" [6] +# "FC HBA" [7] +# "iSCSI HBA" [8] +# "IB HCA" [9] +# "Ethernet Adapter" [10] +# "Other Network Adapter" [11] +# "I/O Slot" [12] +# "I/O Device" [13] +# "Floppy Drive" [14] +# "CD Drive" [15] +# "DVD drive" [16] +# "Disk Drive" [17] +# "Tape Drive" [18] +# "Storage Extent" [19] +# "Other storage device" [20] +# "Serial port" [21] +# "Parallel port" [22] +# "USB Controller" [23] +# "Graphics controller" [24] +# "IEEE 1394 Controller" [25] +# "Partitionable Unit" [26] +# "Base Partitionable Unit" [27] +# "Power" [28] +# "Cooling Capacity" [29] +# "Ethernet Switch Port" [30] + + +DEVICE_CPU = "3" +DEVICE_MEMORY = "4" +DEVICE_IDE_BUS = "5" +DEVICE_SCSI_BUS = "6" +DEVICE_ETHERNET = "10" +DEVICE_DISK = "17" +DEVICE_GRAPHICS = "24" + +# AllocationUnits mapping can be found in Appendix C here: +# http://www.dmtf.org/standards/documents/CIM/DSP0004.pdf + + + +def _ovf_register_namespace(ctx): + ctx.xpathRegisterNs("ovf", "http://schemas.dmtf.org/ovf/envelope/1") + ctx.xpathRegisterNs("ovfenv", "http://schemas.dmtf.org/ovf/environment/1") + ctx.xpathRegisterNs("rasd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData") + ctx.xpathRegisterNs("vssd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData") + ctx.xpathRegisterNs("vmw", "http://www.vmware.com/schema/ovf") + ctx.xpathRegisterNs("xsi", "http://www.w3.org/2001/XMLSchema-instance") + + +def node_list(node): + child_list = [] + child = node.children + while child: + child_list.append(child) + child = child.next + return child_list + + +def _get_child_content(parent_node, child_name): + for node in node_list(parent_node): + if node.name == child_name: + return node.content + + return None + + +def _xml_parse_wrapper(xml, parse_func, *args, **kwargs): + """ + Parse the passed xml string into an xpath context, which is passed + to parse_func, along with any extra arguments. + """ + doc = None + ctx = None + ret = None + + try: + doc = libxml2.parseDoc(xml) + ctx = doc.xpathNewContext() + _ovf_register_namespace(ctx) + ret = parse_func(doc, ctx, *args, **kwargs) + finally: + if ctx is not None: + ctx.xpathFreeContext() + if doc is not None: + doc.freeDoc() + return ret + + + +def _convert_alloc_val(ignore, val): + # This is a hack, but should we really have to decode + # allocation units = "bytes * 2^20"? + val = float(val) + + if val > 100000000: + # Assume bytes + return int(round(val / 1024.0 / 1024.0)) + + elif val > 100000: + # Assume kilobytes + return int(round(val / 1024.0)) + + elif val < 32: + # Assume GB + return int(val * 1024) + + return int(val) + + +def _import_file(doc, ctx, conn, input_file): + ignore = doc + def xpath_str(path): + ret = ctx.xpathEval(path) + result = None + if ret is not None: + if type(ret) == list: + if len(ret) >= 1: + result = ret[0].content + else: + result = ret + return result + + def bool_val(val): + if str(val).lower() == "false": + return False + elif str(val).lower() == "true": + return True + + return False + + def xpath_nodechildren(path): + # Return the children of the first node found by the xpath + nodes = ctx.xpathEval(path) + if not nodes: + return [] + return node_list(nodes[0]) + + def _lookup_disk_path(path): + fmt = "vmdk" + ref = None + + def _path_has_prefix(prefix): + if path.startswith(prefix): + return path[len(prefix):] + if path.startswith("ovf:" + prefix): + return path[len("ovf:" + prefix):] + return False + + if _path_has_prefix("/disk/"): + disk_ref = _path_has_prefix("/disk/") + xpath = (_make_section_xpath(envbase, "DiskSection") + + "/ovf:Disk[@ovf:diskId='%s']" % disk_ref) + + if not ctx.xpathEval(xpath): + raise ValueError(_("Unknown disk reference id '%s' " + "for path %s.") % (path, disk_ref)) + + ref = xpath_str(xpath + "/@ovf:fileRef") + + elif _path_has_prefix("/file/"): + ref = _path_has_prefix("/file/") + + else: + raise ValueError(_("Unknown storage path type %s." % path)) + + xpath = (envbase + "/ovf:References/ovf:File[@ovf:id='%s']" % ref) + + if not ctx.xpathEval(xpath): + raise ValueError(_("Unknown reference id '%s' " + "for path %s.") % (ref, path)) + + return xpath_str(xpath + "/@ovf:href"), fmt + + is_ovirt_format = False + envbase = "/ovf:Envelope[1]" + vsbase = envbase + "/ovf:VirtualSystem" + if not ctx.xpathEval(vsbase): + vsbase = envbase + "/ovf:Content[@xsi:type='ovf:VirtualSystem_Type']" + is_ovirt_format = True + + def _make_section_xpath(base, section_name): + if is_ovirt_format: + return (base + + "/ovf:Section[@xsi:type='ovf:%s_Type']" % section_name) + return base + "/ovf:%s" % section_name + + osbase = _make_section_xpath(vsbase, "OperatingSystemSection") + vhstub = _make_section_xpath(vsbase, "VirtualHardwareSection") + + if not ctx.xpathEval(vsbase): + raise RuntimeError("Did not find any VirtualSystem section") + if not ctx.xpathEval(vhstub): + raise RuntimeError("Did not find any VirtualHardwareSection") + vhbase = vhstub + "/ovf:Item[rasd:ResourceType='%s']" + + # General info + name = xpath_str(vsbase + "/ovf:Name") + desc = xpath_str(vsbase + "/ovf:AnnotationSection/ovf:Annotation") + if not desc: + desc = xpath_str(vsbase + "/ovf:Description") + vcpus = xpath_str((vhbase % DEVICE_CPU) + "/rasd:VirtualQuantity") + sockets = xpath_str((vhbase % DEVICE_CPU) + "/rasd:num_of_sockets") + cores = xpath_str((vhbase % DEVICE_CPU) + "/rasd:num_of_cores") + mem = xpath_str((vhbase % DEVICE_MEMORY) + "/rasd:VirtualQuantity") + alloc_mem = xpath_str((vhbase % DEVICE_MEMORY) + + "/rasd:AllocationUnits") + + os_id = xpath_str(osbase + "/@id") + os_version = xpath_str(osbase + "/@version") + # This is the VMWare OS name + os_vmware = xpath_str(osbase + "/@osType") + + logging.debug("OS parsed as: id=%s version=%s vmware=%s", + os_id, os_version, os_vmware) + + # Sections that we handle + # NetworkSection is ignored, since I don't have an example of + # a valid section in the wild. + parsed_sections = ["References", "DiskSection", "NetworkSection", + "VirtualSystem"] + + # Check for unhandled 'required' sections + for env_node in xpath_nodechildren(envbase): + if env_node.name in parsed_sections: + continue + elif env_node.isText(): + continue + + logging.debug("Unhandled XML section '%s'", + env_node.name) + + if not bool_val(env_node.prop("required")): + continue + raise StandardError(_("OVF section '%s' is listed as " + "required, but parser doesn't know " + "how to handle it.") % + env_node.name) + + disk_buses = {} + for node in ctx.xpathEval(vhbase % DEVICE_IDE_BUS): + instance_id = _get_child_content(node, "InstanceID") + disk_buses[instance_id] = "ide" + for node in ctx.xpathEval(vhbase % DEVICE_SCSI_BUS): + instance_id = _get_child_content(node, "InstanceID") + disk_buses[instance_id] = "scsi" + + ifaces = [] + for node in ctx.xpathEval(vhbase % DEVICE_ETHERNET): + iface = virtinst.VirtualNetworkInterface(conn) + # XXX: Just ignore 'source' info and choose the default + net_model = _get_child_content(node, "ResourceSubType") + if net_model and not net_model.isdigit(): + iface.model = net_model.lower() + iface.set_default_source() + ifaces.append(iface) + + disks = [] + for node in ctx.xpathEval(vhbase % DEVICE_DISK): + bus_id = _get_child_content(node, "Parent") + path = _get_child_content(node, "HostResource") + + bus = disk_buses.get(bus_id, "ide") + fmt = "raw" + + if path: + path, fmt = _lookup_disk_path(path) + + disk = virtinst.VirtualDisk(conn) + disk.path = path + disk.driver_type = fmt + disk.bus = bus + disk.device = "disk" + disks.append(disk) + + + # XXX: Convert these OS values to something useful + ignore = os_version + ignore = os_id + ignore = os_vmware + + (capsguest, capsdomain) = conn.caps.guest_lookup() + guest = conn.caps.build_virtinst_guest(conn, capsguest, capsdomain) + guest.installer = virtinst.ImportInstaller(conn) + + if not name: + name = os.path.basename(input_file) + + guest.name = name.replace(" ", "_") + guest.description = desc or None + if vcpus: + guest.vcpus = int(vcpus) + elif sockets or cores: + if sockets: + guest.cpu.sockets = int(sockets) + if cores: + guest.cpu.cores = int(cores) + guest.cpu.vcpus_from_topology() + + if mem: + guest.memory = _convert_alloc_val(alloc_mem, mem) * 1024 + + for dev in ifaces + disks: + guest.add_device(dev) + + return guest + + +class ovf_parser(parser_class): + """ + Support for OVF appliance configurations. + + Whitepaper: http://www.vmware.com/pdf/ovf_whitepaper_specification.pdf + Spec: http://www.dmtf.org/standards/published_documents/DSP0243_1.0.0.pdf + """ + name = "ovf" + suffix = ".ovf" + + @staticmethod + def identify_file(input_file): + """ + Return True if the given file is of this format. + """ + if os.path.getsize(input_file) > (1024 * 1024 * 2): + return + + infile = open(input_file, "r") + xml = infile.read() + infile.close() + + def parse_cb(doc, ctx): + ignore = doc + return bool(ctx.xpathEval("/ovf:Envelope")) + + try: + return _xml_parse_wrapper(xml, parse_cb) + except Exception, e: + logging.debug("Error parsing OVF XML: %s", str(e)) + + return False + + @staticmethod + def export_libvirt(conn, input_file): + infile = open(input_file, "r") + xml = infile.read() + infile.close() + logging.debug("Importing OVF XML:\n%s", xml) + + return _xml_parse_wrapper(xml, _import_file, conn, input_file) diff --git a/virtconv/parsers/__init__.py b/virtconv/parsers/__init__.py deleted file mode 100644 index 09a2da51..00000000 --- a/virtconv/parsers/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Copyright (C) 2013 Red Hat, Inc. diff --git a/virtconv/parsers/ovf.py b/virtconv/parsers/ovf.py deleted file mode 100644 index c8311773..00000000 --- a/virtconv/parsers/ovf.py +++ /dev/null @@ -1,439 +0,0 @@ -# -# Copyright 2009, 2013 Red Hat, Inc. -# Cole Robinson -# -# 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. -# - -import logging - -from virtinst import util - -import virtconv.formats as formats -import virtconv.vmcfg as vmcfg -import virtconv.diskcfg as diskcfg -import virtconv.netdevcfg as netdevcfg - - -# Mapping of ResourceType value to device type -# http://konkretcmpi.org/cim218/CIM_ResourceAllocationSettingData.html -# -# "Other" [1] -# "Computer System" [2] -# "Processor" [3] -# "Memory" [4] -# "IDE Controller" [5] -# "Parallel SCSI HBA" [6] -# "FC HBA" [7] -# "iSCSI HBA" [8] -# "IB HCA" [9] -# "Ethernet Adapter" [10] -# "Other Network Adapter" [11] -# "I/O Slot" [12] -# "I/O Device" [13] -# "Floppy Drive" [14] -# "CD Drive" [15] -# "DVD drive" [16] -# "Disk Drive" [17] -# "Tape Drive" [18] -# "Storage Extent" [19] -# "Other storage device" [20] -# "Serial port" [21] -# "Parallel port" [22] -# "USB Controller" [23] -# "Graphics controller" [24] -# "IEEE 1394 Controller" [25] -# "Partitionable Unit" [26] -# "Base Partitionable Unit" [27] -# "Power" [28] -# "Cooling Capacity" [29] -# "Ethernet Switch Port" [30] - - -DEVICE_CPU = "3" -DEVICE_MEMORY = "4" -DEVICE_IDE_BUS = "5" -DEVICE_SCSI_BUS = "6" -DEVICE_ETHERNET = "10" -DEVICE_DISK = "17" -DEVICE_GRAPHICS = "24" - -# AllocationUnits mapping can be found in Appendix C here: -# http://www.dmtf.org/standards/documents/CIM/DSP0004.pdf - - - -def ovf_register_namespace(ctx): - ctx.xpathRegisterNs("ovf", "http://schemas.dmtf.org/ovf/envelope/1") - ctx.xpathRegisterNs("ovfenv", "http://schemas.dmtf.org/ovf/environment/1") - ctx.xpathRegisterNs("rasd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData") - ctx.xpathRegisterNs("vssd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData") - ctx.xpathRegisterNs("vmw", "http://www.vmware.com/schema/ovf") - - -def node_list(node): - child_list = [] - child = node.children - while child: - child_list.append(child) - child = child.next - return child_list - - -def get_child_content(parent_node, child_name): - for node in node_list(parent_node): - if node.name == child_name: - return node.content - - return None - - -def _xpath(xml, path=None, func=None, return_list=False, - register_namespace=None): - """ - Return the content from the passed xml xpath, or return the result - of a passed function (receives xpathContext as its only arg) - """ - def _getter(doc, ctx, path): - ignore = doc - if func: - return func(ctx) - if not path: - raise ValueError("'path' or 'func' is required.") - - ret = ctx.xpathEval(path) - if type(ret) is list: - if len(ret) >= 1: - if return_list: - return ret - else: - return ret[0].content - else: - ret = None - return ret - - return util.xml_parse_wrapper(xml, _getter, path, - register_namespace=register_namespace) - - -def convert_alloc_val(ignore, val): - # XXX: This is a hack, but should we really have to decode - # allocation units = "bytes * 2^20"? - val = float(val) - - if val > 100000000: - # Assume bytes - return int(round(val / 1024.0 / 1024.0)) - - elif val > 100000: - # Assume kilobytes - return int(round(val / 1024.0)) - - elif val < 32: - # Assume GB - return int(val * 1024) - - return int(val) - - -def _parse_hw_section(vm, nodes, file_refs, disk_section): - vm.nr_vcpus = 0 - disk_buses = {} - - for device_node in nodes: - if device_node.name != "Item": - continue - - devtype = None - for item_node in node_list(device_node): - if item_node.name == "ResourceType": - devtype = item_node.content - - if devtype == DEVICE_CPU: - cpus = get_child_content(device_node, "VirtualQuantity") - if cpus: - vm.nr_vcpus += int(cpus) - - elif devtype == DEVICE_MEMORY: - mem = get_child_content(device_node, "VirtualQuantity") - alloc_str = get_child_content(device_node, "AllocationUnits") - if mem: - vm.memory = convert_alloc_val(alloc_str, mem) - - elif devtype == DEVICE_ETHERNET: - net_model = get_child_content(device_node, "ResourceSubType") - if net_model: - net_model = net_model.lower() - netdev = netdevcfg.netdev(driver=net_model) - vm.netdevs[len(vm.netdevs)] = netdev - - elif devtype == DEVICE_IDE_BUS: - instance_id = get_child_content(device_node, "InstanceID") - disk_buses[instance_id] = "ide" - - elif devtype == DEVICE_SCSI_BUS: - instance_id = get_child_content(device_node, "InstanceID") - disk_buses[instance_id] = "scsi" - - elif devtype in [DEVICE_DISK]: - bus_id = get_child_content(device_node, "Parent") - path = get_child_content(device_node, "HostResource") - - dev_num = int(get_child_content(device_node, "AddressOnParent")) - - if bus_id and bus_id not in disk_buses: - raise ValueError(_("Didn't find parent bus for disk '%s'" % - path)) - - bus = (bus_id and disk_buses[bus_id]) or "ide" - - fmt = diskcfg.DISK_FORMAT_RAW - - if path: - ref = None - fmt = diskcfg.DISK_FORMAT_VMDK - - if path.startswith("ovf:/disk/"): - disk_ref = path[len("ovf:/disk/"):] - if disk_ref not in disk_section: - raise ValueError(_("Unknown reference id '%s' " - "for path %s.") % (path, ref)) - - ref, fmt = disk_section[disk_ref] - - elif path.startswith("ovf:/file/"): - ref = path[len("ovf:/file/"):] - - else: - raise ValueError(_("Unknown storage path type %s." % path)) - - if not ref: - # XXX: This means allocate the disk. - pass - - if ref not in file_refs: - raise ValueError(_("Unknown reference id '%s' " - "for path %s.") % (path, ref)) - - path = file_refs[ref] - - disk = diskcfg.disk(path=path, fmt=fmt, bus=bus, - typ=diskcfg.DISK_TYPE_DISK) - - vm.disks[(bus, dev_num)] = disk - - else: - desc = get_child_content(device_node, "Description") - logging.debug("Unhandled device type=%s desc=%s", devtype, desc) - - -class ovf_parser(formats.parser): - """ - Support for OVF appliance configurations. - - Whitepaper: http://www.vmware.com/pdf/ovf_whitepaper_specification.pdf - Spec: http://www.dmtf.org/standards/published_documents/DSP0243_1.0.0.pdf - """ - - name = "ovf" - suffix = ".ovf" - can_import = True - can_export = False - can_identify = True - - @staticmethod - def identify_file(input_file): - """ - Return True if the given file is of this format. - """ - infile = open(input_file, "r") - xml = infile.read() - infile.close() - - res = False - try: - if xml.count(""): - res = bool(_xpath(xml, "/ovf:Envelope", return_list=True, - register_namespace=ovf_register_namespace)) - except Exception, e: - logging.debug("Error parsing OVF XML: %s", str(e)) - - return res - - @staticmethod - def import_file(input_file): - """ - Import a configuration file. Raises if the file couldn't be - opened, or parsing otherwise failed. - """ - - infile = open(input_file, "r") - xml = infile.read() - infile.close() - logging.debug("Importing OVF XML:\n%s", xml) - - return util.xml_parse_wrapper(xml, ovf_parser._import_file, - register_namespace=ovf_register_namespace) - - @staticmethod - def _import_file(doc, ctx): - ignore = doc - def xpath_str(path): - ret = ctx.xpathEval(path) - result = None - if ret is not None: - if type(ret) == list: - if len(ret) >= 1: - result = ret[0].content - else: - result = ret - return result - - def bool_val(val): - if str(val).lower() == "false": - return False - elif str(val).lower() == "true": - return True - - return False - - def xpath_nodes(path): - return ctx.xpathEval(path) - - vm = vmcfg.vm() - - file_refs = {} - disk_section = {} - net_section = {} - name = None - desc = None - - os_id_ignore = None - os_ver_ignore = None - os_type_ignore = None - - # XXX: Can have multiple machines nested as VirtualSystemCollection - # XXX: Need to check all Envelope - - # General info - name = xpath_str("/ovf:Envelope/ovf:VirtualSystem/ovf:Name") - - # Map files in to actual filename - ens = xpath_nodes("/ovf:Envelope[1]")[0] - envelope_node = ens.children - for envelope_node in node_list(ens): - - if envelope_node.name == "References": - for reference_node in envelope_node.children: - if reference_node.name != "File": - continue - - file_id = reference_node.prop("id") - path = reference_node.prop("href") - - # XXX: Should we validate the path exists? This can - # be http. - if file_id and path: - file_refs[file_id] = path - - elif envelope_node.name == "DiskSection": - for disk_node in envelope_node.children: - if disk_node.name != "Disk": - continue - - fmt = disk_node.prop("format") - if not fmt: - fmt = diskcfg.DISK_FORMAT_VMDK - elif fmt.lower().count("vmdk"): - fmt = diskcfg.DISK_FORMAT_VMDK - else: - fmt = diskcfg.DISK_FORMAT_VMDK - - disk_id = disk_node.prop("diskId") - file_ref = disk_node.prop("fileRef") - capacity = disk_node.prop("capacity") - alloc_str = disk_node.prop("AllocationUnits") - capacity = convert_alloc_val(alloc_str, capacity) - - # XXX: Empty fileref means 'create this disk' - disk_section[disk_id] = (file_ref, fmt) - - elif envelope_node.name == "NetworkSection": - for net_node in envelope_node.children: - if net_node.name != "Network": - continue - - net_name_ignore = net_node.prop("name") - net_section[name] = None - - elif not envelope_node.isText(): - logging.debug("Unhandled XML section '%s'", - envelope_node.name) - - req = bool_val(envelope_node.prop("required")) - if req: - raise StandardError(_("OVF section '%s' is listed as " - "required, but parser doesn't know " - "how to handle it.") % - envelope_node.name) - - # Now parse VirtualSystem, since we should have set up all the - # necessary file/disk/whatever refs - for envelope_node in node_list(ens): - if envelope_node.name != "VirtualSystem": - continue - - for vs_node in node_list(envelope_node): - - if vs_node.name == "Info": - pass - - elif vs_node.name == "Name": - name = vs_node.content - - elif vs_node.name == "OperatingSystemSection": - os_id_ignore = vs_node.prop("id") - os_ver_ignore = vs_node.prop("version") - # This is the VMWare OS name - os_type_ignore = vs_node.prop("osType") - - elif vs_node.name == "VirtualHardwareSection": - _parse_hw_section(vm, node_list(vs_node), file_refs, - disk_section) - - elif vs_node.name == "AnnotationSection": - for an_node in node_list(vs_node): - if an_node.name == "Annotation": - desc = an_node.content - - - vm.name = name - vm.description = desc - vm.validate() - - return vm - - @staticmethod - def export(vm): - """ - Export a configuration file as a string. - @vm vm configuration instance - - Raises ValueError if configuration is not suitable. - """ - raise NotImplementedError - -formats.register_parser(ovf_parser) diff --git a/virtconv/parsers/virtimage.py b/virtconv/parsers/virtimage.py deleted file mode 100644 index ada40c47..00000000 --- a/virtconv/parsers/virtimage.py +++ /dev/null @@ -1,320 +0,0 @@ -# -# Copyright 2013 Red Hat, Inc. -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# 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. -# - -import virtconv.formats as formats -import virtconv.vmcfg as vmcfg -import virtconv.diskcfg as diskcfg -import virtconv.netdevcfg as netdevcfg - -from virtinst import virtimage - -from xml.sax.saxutils import escape -import re -import logging - -ide_letters = list("abcdefghijklmnopqrstuvwxyz") - -pv_boot_template = \ -""" - - %(arch)s - - - - - - pygrub - -%(disks)s - """ - -hvm_boot_template = \ -""" - - %(arch)s - - - - -%(disks)s - """ - -image_template = \ -""" - %(name)s - - %(description)s - -%(boot_template)s - - %(nr_vcpus)s - %(memory)s -%(interface)s - - - - -%(storage)s - - -""" - - -def export_os_params(vm): - """ - Export OS-specific parameters. - """ - from virtinst import osdict - os = osdict.lookup_os(vm.os_variant) - - def get_os_val(key, default): - val = None - if os: - val = os.to_dict().get(key) - if val is None: - val = default - return val - - acpi = "" - if vm.noacpi is False and get_os_val("acpi", True): - acpi = "" - - apic = "" - if vm.noapic is False and get_os_val("apic", False): - apic = "" - - return acpi, apic - - -def export_disks(vm): - """ - Export code for the disks. Slightly tricky for two reasons. - - We can't handle duplicate disks: some vmx files define SCSI/IDE devices - that point to the same storage, and Xen isn't happy about that. We - just ignore any entries that have duplicate paths. - - Since there is no SCSI support in rombios, and the SCSI emulation is - troublesome with Solaris, we forcibly switch the disks to IDE, and expect - the guest OS to cope (which at least Linux does admirably). - - Note that we even go beyond hdd: above that work if the domU has PV - drivers. - """ - - paths = [] - - disks = {} - - for (bus, instance), disk in sorted(vm.disks.iteritems()): - - if disk.path and disk.path in paths: - continue - - if bus == "scsi": - instance = 0 - while disks.get(("ide", instance)): - instance += 1 - - disks[("ide", instance)] = disk - - if disk.path: - paths += [disk.path] - - diskout = [] - storage = [] - - for (bus, instance), disk in sorted(disks.iteritems()): - - # virt-image XML cannot handle an empty CD device - if not disk.path: - continue - - path = disk.path - drive_nr = ide_letters[int(instance) % 26] - - disk_prefix = "xvd" - if vm.type == vmcfg.VM_TYPE_HVM: - if bus == "ide": - disk_prefix = "hd" - else: - disk_prefix = "sd" - - # FIXME: needs updating for later Xen enhancements; need to - # implement capabilities checking for max disks etc. - diskout.append(""" \n""" % - (path, disk_prefix, drive_nr)) - - typ = "raw" - if disk.format in diskcfg.qemu_formats: - typ = diskcfg.qemu_formats[disk.format] - elif disk.typ == diskcfg.DISK_TYPE_ISO: - typ = "iso" - - storage.append( - """ \n""" % - (path, typ)) - - return storage, diskout - - -class virtimage_parser(formats.parser): - """ - Support for virt-install's image format (see virt-image man page). - """ - name = "virt-image" - suffix = ".virt-image.xml" - can_import = True - can_export = True - can_identify = True - - @staticmethod - def identify_file(input_file): - """ - Return True if the given file is of this format. - """ - try: - f = file(input_file, "r") - output = f.read() - f.close() - - virtimage.parse(output, input_file) - except RuntimeError: - return False - return True - - @staticmethod - def import_file(input_file): - """ - Import a configuration file. Raises if the file couldn't be - opened, or parsing otherwise failed. - """ - vm = vmcfg.vm() - try: - f = file(input_file, "r") - output = f.read() - f.close() - - logging.debug("Importing virt-image XML:\n%s", output) - config = virtimage.parse(output, input_file) - except Exception, e: - raise ValueError(_("Couldn't import file '%s': %s") % - (input_file, e)) - - domain = config.domain - boot = domain.boots[0] - - if not config.name: - raise ValueError(_("No Name defined in '%s'") % input_file) - vm.name = config.name - vm.arch = boot.arch - vm.memory = int(config.domain.memory / 1024) - if config.descr: - vm.description = config.descr - vm.nr_vcpus = config.domain.vcpu - - bus = "ide" - nr_disk = 0 - - for d in boot.drives: - disk = d.disk - format_mappings = { - virtimage.Disk.FORMAT_RAW: diskcfg.DISK_FORMAT_RAW, - virtimage.Disk.FORMAT_VMDK: diskcfg.DISK_FORMAT_VMDK, - virtimage.Disk.FORMAT_QCOW: diskcfg.DISK_FORMAT_QCOW, - virtimage.Disk.FORMAT_QCOW2: diskcfg.DISK_FORMAT_QCOW2, - virtimage.Disk.FORMAT_VDI: diskcfg.DISK_FORMAT_VDI, - } - - fmt = None - if disk.format in format_mappings: - fmt = format_mappings[disk.format] - else: - raise ValueError(_("Unknown disk format '%s'"), disk.format) - - devid = (bus, nr_disk) - vm.disks[devid] = diskcfg.disk(bus=bus, - typ=diskcfg.DISK_TYPE_DISK) - vm.disks[devid].format = fmt - vm.disks[devid].path = disk.file - nr_disk = nr_disk + 1 - - nics = domain.interface - nic_idx = 0 - while nic_idx in range(0, nics): - # XXX Eventually need to add support for mac addresses if given - vm.netdevs[nic_idx] = netdevcfg.netdev( - typ=netdevcfg.NETDEV_TYPE_UNKNOWN) - nic_idx = nic_idx + 1 - vm.validate() - return vm - - @staticmethod - def export(vm): - """ - Export a configuration file as a string. - @vm vm configuration instance - - Raises ValueError if configuration is not suitable. - """ - - if not vm.memory: - raise ValueError(_("VM must have a memory setting")) - - # xend wants the name to match r'^[A-Za-z0-9_\-\.\:\/\+]+$', and - # the schema agrees. - vmname = re.sub(r'[^A-Za-z0-9_\-\.:\/\+]+', '_', vm.name) - - # Hmm. Any interface is a good interface? - interface = None - if len(vm.netdevs): - interface = " " - - acpi, apic = export_os_params(vm) - - if vm.type == vmcfg.VM_TYPE_PV: - boot_template = pv_boot_template - else: - boot_template = hvm_boot_template - - (storage, disks) = export_disks(vm) - - boot_xml = boot_template % { - "disks" : "".join(disks).strip("\n"), - "arch" : vm.arch, - "acpi" : acpi, - "apic" : apic, - } - - out = image_template % { - "boot_template": boot_xml, - "name" : vmname, - "description" : escape(vm.description), - "nr_vcpus" : vm.nr_vcpus, - # Mb to Kb - "memory" : int(vm.memory) * 1024, - "interface" : interface, - "storage" : "".join(storage).strip("\n"), - } - - return out - -formats.register_parser(virtimage_parser) diff --git a/virtconv/vmcfg.py b/virtconv/vmcfg.py deleted file mode 100644 index 65760dc0..00000000 --- a/virtconv/vmcfg.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright (C) 2013 Red Hat, Inc. -# -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# 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. -# - -from virtconv import diskcfg - -VM_TYPE_UNKNOWN = 0 -VM_TYPE_PV = 1 -VM_TYPE_HVM = 2 - - -class vm(object): - """ - Generic configuration for a particular VM instance. - - At export, a plugin is guaranteed to have the at least the following - values set (any others needed should be checked for, raising - ValueError on failure): - - vm.name - vm.description (defaults to empty string) - vm.nr_vcpus (defaults to 1) - vm.type - vm.arch - - If vm.memory is set, it is in Mb units. - """ - - name = None - suffix = None - - def __init__(self): - self.name = None - self.description = None - self.memory = None - self.nr_vcpus = None - self.disks = {} - self.netdevs = {} - self.type = VM_TYPE_HVM - self.arch = "i686" - self.noacpi = None - self.noapic = None - self.os_variant = None - - def validate(self): - """ - Validate all parameters, and fix up any unset values to meet the - guarantees we make above. - """ - - if not self.name: - raise ValueError(_("VM name is not set")) - if not self.description: - self.description = "" - if not self.nr_vcpus: - self.nr_vcpus = 1 - if self.type == VM_TYPE_UNKNOWN: - raise ValueError(_("VM type is not set")) - if not self.arch: - raise ValueError(_("VM arch is not set")) - - for (bus, inst), disk in sorted(self.disks.iteritems()): - if disk.type == diskcfg.DISK_TYPE_DISK and not disk.path: - raise ValueError(_("Disk %s:%s storage does not exist") - % (bus, inst)) diff --git a/virtconv/parsers/vmx.py b/virtconv/vmx.py similarity index 53% rename from virtconv/parsers/vmx.py rename to virtconv/vmx.py index afbf28a9..2c6db892 100644 --- a/virtconv/parsers/vmx.py +++ b/virtconv/vmx.py @@ -19,69 +19,15 @@ # MA 02110-1301 USA. # -import virtconv.formats as formats -import virtconv.vmcfg as vmcfg -import virtconv.diskcfg as diskcfg -import virtconv.netdevcfg as netdevcfg - -import sys -import re -import os import logging +import os +import re import shlex +import virtinst +from virtinst import util -_VMX_MAIN_TEMPLATE = """ -#!/usr/bin/vmplayer - -# Generated by %(progname)s -# http://virt-manager.org/ - -# This is a Workstation 5 or 5.5 config file and can be used with Player -config.version = "8" -virtualHW.version = "4" -guestOS = "other" -displayName = "%(vm_name)s" -annotation = "%(vm_description)s" -guestinfo.vmware.product.long = "%(vm_name)s" -guestinfo.vmware.product.url = "http://virt-manager.org/" -guestinfo.vmware.product.class = "virtual machine" -numvcpus = "%(vm_nr_vcpus)s" -memsize = "%(vm_memory)d" -MemAllowAutoScaleDown = "FALSE" -MemTrimRate = "-1" -uuid.action = "create" -tools.remindInstall = "TRUE" -hints.hideAll = "TRUE" -tools.syncTime = "TRUE" -serial0.present = "FALSE" -serial1.present = "FALSE" -parallel0.present = "FALSE" -logging = "TRUE" -log.fileName = "%(vm_name)s.log" -log.append = "TRUE" -log.keepOld = "3" -isolation.tools.hgfs.disable = "FALSE" -isolation.tools.dnd.disable = "FALSE" -isolation.tools.copy.enable = "TRUE" -isolation.tools.paste.enabled = "TRUE" -floppy0.present = "FALSE" -""" -_VMX_ETHERNET_TEMPLATE = """ -ethernet%(dev)s.present = "TRUE" -ethernet%(dev)s.connectionType = "nat" -ethernet%(dev)s.addressType = "generated" -ethernet%(dev)s.generatedAddressOffset = "0" -ethernet%(dev)s.autoDetect = "TRUE" -""" -_VMX_IDE_TEMPLATE = """ -# IDE disk -ide%(dev)s.present = "TRUE" -ide%(dev)s.fileName = "%(disk_filename)s" -ide%(dev)s.mode = "persistent" -ide%(dev)s.startConnected = "TRUE" -ide%(dev)s.writeThrough = "TRUE" -""" +from virtconv.formats import parser_class class _VMXLine(object): @@ -149,7 +95,7 @@ class _VMXFile(object): return ret -def parse_vmdk(disk, filename): +def parse_vmdk(filename): """ Parse a VMDK descriptor file Reference: http://sanbarrow.com/vmdk-basics.html @@ -182,49 +128,54 @@ def parse_vmdk(disk, filename): raise RuntimeError(_("Don't know how to handle multistorage VMDK " "descriptors")) - diskline = disklines[0] - newpath = diskline.parse_disk_path() - logging.debug("VMDK file parsed path %s->%s", disk.path, newpath) - disk.path = newpath + return disklines[0].parse_disk_path() -def parse_netdev_entry(vm, fullkey, value): +def parse_netdev_entry(conn, ifaces, fullkey, value): """ Parse a particular key/value for a network. Throws ValueError. """ - ignore, ignore, inst, key = re.split("^(ethernet)([0-9]+).", fullkey) - lvalue = value.lower() if key == "present" and lvalue == "false": return - if not vm.netdevs.get(inst): - vm.netdevs[inst] = netdevcfg.netdev(typ=netdevcfg.NETDEV_TYPE_UNKNOWN) + net = None + for checkiface in ifaces: + if getattr(checkiface, "vmx_inst") == inst: + net = checkiface + break + if not net: + net = virtinst.VirtualNetworkInterface(conn) + setattr(net, "vmx_inst", inst) + net.set_default_source() + ifaces.append(net) - # "vlance", "vmxnet", "e1000" if key == "virtualdev": - vm.netdevs[inst].driver = lvalue + # "vlance", "vmxnet", "e1000" + if lvalue in ["e1000"]: + net.model = lvalue if key == "addresstype" and lvalue == "generated": - vm.netdevs[inst].mac = "auto" - # we ignore .generatedAddress for auto mode + # Autogenerate a MAC address, the default + pass if key == "address": - vm.netdevs[inst].mac = lvalue + # we ignore .generatedAddress for auto mode + net.macaddr = lvalue + return net, inst -def parse_disk_entry(vm, fullkey, value): +def parse_disk_entry(conn, disks, fullkey, value): """ Parse a particular key/value for a disk. FIXME: this should be a lot smarter. """ - # skip bus values, e.g. 'scsi0.present = "TRUE"' if re.match(r"^(scsi|ide)[0-9]+[^:]", fullkey): return - ignore, bus, bus_nr, inst, key = re.split(r"^(scsi|ide)([0-9]+):([0-9]+)\.", - fullkey) + ignore, bus, bus_nr, inst, key = re.split( + r"^(scsi|ide)([0-9]+):([0-9]+)\.", fullkey) lvalue = value.lower() @@ -238,47 +189,55 @@ def parse_disk_entry(vm, fullkey, value): elif bus == "scsi": inst = int(bus_nr) * 16 + (int(inst) % 16) - - devid = (bus, inst) - if not vm.disks.get(devid): - vm.disks[devid] = diskcfg.disk(bus=bus, - typ=diskcfg.DISK_TYPE_DISK) - disk = vm.disks[devid] + disk = None + for checkdisk in disks: + if checkdisk.bus == bus and getattr(checkdisk, "vmx_inst") == inst: + disk = checkdisk + break + if not disk: + disk = virtinst.VirtualDisk(conn) + disk.bus = bus + setattr(disk, "vmx_inst", inst) + disks.append(disk) if key == "devicetype": - if lvalue == "atapi-cdrom" or lvalue == "cdrom-raw": - disk.type = diskcfg.DISK_TYPE_CDROM - elif lvalue == "cdrom-image": - disk.type = diskcfg.DISK_TYPE_ISO + if (lvalue == "atapi-cdrom" or + lvalue == "cdrom-raw" or + lvalue == "cdrom-image"): + disk.device = "cdrom" if key == "filename": disk.path = value - disk.format = diskcfg.DISK_FORMAT_RAW + fmt = "raw" if lvalue.endswith(".vmdk"): - disk.format = diskcfg.DISK_FORMAT_VMDK + fmt = "vmdk" # See if the filename is actually a VMDK descriptor file - parse_vmdk(disk, disk.path) + newpath = parse_vmdk(disk.path) + if newpath: + logging.debug("VMDK file parsed path %s->%s", + disk.path, newpath) + disk.path = newpath + + disk.driver_type = fmt - -class vmx_parser(formats.parser): +class vmx_parser(parser_class): """ Support for VMWare .vmx files. Note that documentation is particularly sparse on this format, with pretty much the best resource being http://sanbarrow.com/vmx.html """ - name = "vmx" suffix = ".vmx" - can_import = True - can_export = True - can_identify = True @staticmethod def identify_file(input_file): """ Return True if the given file is of this format. """ + if os.path.getsize(input_file) > (1024 * 1024 * 2): + return + infile = open(input_file, "r") content = infile.readlines() infile.close() @@ -291,14 +250,7 @@ class vmx_parser(formats.parser): return False @staticmethod - def import_file(input_file): - """ - Import a configuration file. Raises if the file couldn't be - opened, or parsing otherwise failed. - """ - - vm = vmcfg.vm() - + def export_libvirt(conn, input_file): infile = open(input_file, "r") contents = infile.readlines() infile.close() @@ -311,78 +263,50 @@ class vmx_parser(formats.parser): raise ValueError(_("No displayName defined in '%s'") % input_file) - vm.name = config.get("displayname") - vm.memory = config.get("memsize") - vm.description = config.get("annotation") - vm.nr_vcpus = config.get("numvcpus") + name = config.get("displayname") + mem = config.get("memsize") + desc = config.get("annotation") + vcpus = config.get("numvcpus") - for key, value in config.items(): - if key.startswith("scsi") or key.startswith("ide"): - parse_disk_entry(vm, key, value) - if key.startswith("ethernet"): - parse_netdev_entry(vm, key, value) + def _find_keys(prefixes): + ret = [] + for key, value in config.items(): + for p in util.listify(prefixes): + if key.startswith(p): + ret.append((key, value)) + break + return ret - for devid, disk in vm.disks.iteritems(): - if disk.type == diskcfg.DISK_TYPE_DISK: + disks = [] + for key, value in _find_keys(["scsi", "ide"]): + parse_disk_entry(conn, disks, key, value) + + ifaces = [] + for key, value in _find_keys("ethernet"): + parse_netdev_entry(conn, ifaces, key, value) + + for disk in disks: + if disk.device == "disk": continue # vmx files often have dross left in path for CD entries if (disk.path is None or disk.path.lower() == "auto detect" or not os.path.exists(disk.path)): - vm.disks[devid].path = None + disk.path = None - vm.validate() - return vm + (capsguest, capsdomain) = conn.caps.guest_lookup() + guest = conn.caps.build_virtinst_guest(conn, capsguest, capsdomain) + guest.installer = virtinst.ImportInstaller(conn) - @staticmethod - def export(vm): - """ - Export a configuration file as a string. - @vm vm configuration instance + guest.name = name.replace(" ", "_") + guest.description = desc or None + if vcpus: + guest.vcpus = int(vcpus) + if mem: + guest.memory = int(mem) * 1024 - Raises ValueError if configuration is not suitable. - """ + for dev in ifaces + disks: + guest.add_device(dev) - vm.description = vm.description.strip() - vm.description = vm.description.replace("\n", "|") - vmx_out_template = [] - vmx_dict = { - #"now": time.strftime("%Y-%m-%dT%H:%M:%S %Z", time.localtime()), - "progname": os.path.basename(sys.argv[0]), - "vm_name": vm.name, - "vm_description": vm.description or "None", - "vm_nr_vcpus" : vm.nr_vcpus, - "vm_memory": long(vm.memory) - } - vmx_out = _VMX_MAIN_TEMPLATE % vmx_dict - vmx_out_template.append(vmx_out) - - disk_out_template = [] - for devid, disk in sorted(vm.disks.items()): - bus, dev_nr = devid - if bus.lower() != "ide": - logging.debug("Disk bus '%s' not yet supported. Skipping.", - bus.lower()) - continue - - dev = "%d:%d" % (dev_nr / 2, dev_nr % 2) - disk_dict = { - "dev": dev, - "disk_filename" : disk.path - } - disk_out = _VMX_IDE_TEMPLATE % disk_dict - disk_out_template.append(disk_out) - - eth_out_template = [] - if len(vm.netdevs): - for devnum in vm.netdevs: - eth_dict = { - "dev" : devnum - } - eth_out = _VMX_ETHERNET_TEMPLATE % eth_dict - eth_out_template.append(eth_out) - - return "".join(vmx_out_template + disk_out_template + eth_out_template) - -formats.register_parser(vmx_parser) + return guest diff --git a/virtinst/cli.py b/virtinst/cli.py index 1c77093d..6b0c12ac 100644 --- a/virtinst/cli.py +++ b/virtinst/cli.py @@ -331,6 +331,74 @@ def validate_disk(dev, warn_overwrite=False): check_size_conflict(dev) +def _run_console(args): + logging.debug("Running: %s", " ".join(args)) + child = os.fork() + if child: + return child + + os.execvp(args[0], args) + os._exit(1) # pylint: disable=W0212 + + +def _gfx_console(guest): + args = ["/usr/bin/virt-viewer", + "--connect", guest.conn.uri, + "--wait", guest.name] + + if not os.path.exists(args[0]): + logging.warn(_("Unable to connect to graphical console: " + "virt-viewer not installed. Please install " + "the 'virt-viewer' package.")) + return None + + return _run_console(args) + + +def _txt_console(guest): + args = ["/usr/bin/virsh", + "--connect", guest.conn.uri, + "console", guest.name] + + return _run_console(args) + + +def connect_console(guest, consolecb, wait): + """ + Launched the passed console callback for the already defined + domain. If domain isn't running, return an error. + """ + child = None + if consolecb: + child = consolecb(guest) + + if not child or not wait: + return + + # If we connected the console, wait for it to finish + try: + os.waitpid(child, 0) + except OSError, e: + logging.debug("waitpid: %s: %s", e.errno, e.message) + + +def show_console_for_guest(guest): + gdev = guest.get_devices("graphics") + if not gdev: + logging.debug("Connecting to text console") + return _txt_console(guest) + + gtype = gdev[0].type + if gtype in ["default", + virtinst.VirtualGraphics.TYPE_VNC, + virtinst.VirtualGraphics.TYPE_SPICE]: + logging.debug("Launching virt-viewer for graphics type '%s'", gtype) + return _gfx_console(guest) + else: + logging.debug("No viewer to launch for graphics type '%s'", gtype) + return None + + ########################### # CLI back compat helpers # ########################### @@ -482,13 +550,19 @@ def add_connect_option(parser): def add_misc_options(grp, prompt=False, replace=False, printxml=False, printstep=False, - noreboot=False, dryrun=False): + noreboot=False, dryrun=False, + noautoconsole=False): if prompt: grp.add_argument("--prompt", action="store_true", default=False, help=argparse.SUPPRESS) grp.add_argument("--force", action="store_true", default=False, help=argparse.SUPPRESS) + if noautoconsole: + grp.add_argument("--noautoconsole", action="store_false", + dest="autoconsole", default=True, + help=_("Don't automatically try to connect to the guest console")) + if noreboot: grp.add_argument("--noreboot", action="store_true", help=_("Don't boot guest after completing install.")) @@ -500,8 +574,8 @@ def add_misc_options(grp, prompt=False, replace=False, if printxml: grp.add_argument("--print-xml", action="store_true", dest="xmlonly", - help=_("Print the generated domain XML rather than define " - "and clone the guest.")) + help=_("Print the generated domain XML rather than create " + "the guest.")) if printstep: grp.add_argument("--print-step", dest="xmlstep", help=_("Print XML of a specific install step " diff --git a/virtinst/connection.py b/virtinst/connection.py index 4a2e9ed8..c2b534c6 100644 --- a/virtinst/connection.py +++ b/virtinst/connection.py @@ -66,7 +66,7 @@ class VirtualConnection(object): - simplified API wrappers that handle new and old ways of doing things """ def __init__(self, uri): - _initial_uri = uri or "" + self._initial_uri = uri or "" self._fake_pretty_name = None self._fake_libvirt_version = None @@ -74,9 +74,9 @@ class VirtualConnection(object): self._daemon_version = None self._conn_version = None - if _initial_uri.startswith(_virtinst_uri_magic): + if self._initial_uri.startswith(_virtinst_uri_magic): # virtinst unit test URI handling - uri = _initial_uri.replace(_virtinst_uri_magic, "") + uri = self._initial_uri.replace(_virtinst_uri_magic, "") ret = uri.split(",", 1) self._open_uri = ret[0] self._test_opts = VirtOptionString( @@ -84,8 +84,8 @@ class VirtualConnection(object): self._early_virtinst_test_uri() self._uri = self._virtinst_uri_make_fake() else: - self._open_uri = _initial_uri - self._uri = _initial_uri + self._open_uri = self._initial_uri + self._uri = self._initial_uri self._test_opts = {} self._libvirtconn = None diff --git a/virtinst/guest.py b/virtinst/guest.py index 0b8435ef..d55c2a0e 100644 --- a/virtinst/guest.py +++ b/virtinst/guest.py @@ -449,8 +449,7 @@ class Guest(XMLBuilder): def _create_guest(self, meter, start_xml, final_xml, is_initial, noboot): """ - Actually do the XML logging, guest defining/creating, console - launching and waiting + Actually do the XML logging, guest defining/creating @param is_initial: If running initial guest creation, else we are continuing the install diff --git a/virtinst/storage.py b/virtinst/storage.py index 51485d20..6f8eac64 100644 --- a/virtinst/storage.py +++ b/virtinst/storage.py @@ -79,6 +79,13 @@ class _StorageObject(XMLBuilder): is_single=True) +def _get_default_pool_path(conn): + path = "/var/lib/libvirt/images" + if conn.is_session_uri(): + path = os.path.expanduser("~/VirtualMachines") + return path + + class StoragePool(_StorageObject): """ Base class for building and installing libvirt storage pool xml @@ -177,9 +184,7 @@ class StoragePool(_StorageObject): pool = None name = "default" - path = "/var/lib/libvirt/images" - if conn.is_session_uri(): - path = os.path.expanduser("~/VirtualMachines") + path = _get_default_pool_path(conn) try: pool = conn.storagePoolLookupByName(name) @@ -196,14 +201,36 @@ class StoragePool(_StorageObject): defpool.type = defpool.TYPE_DIR defpool.name = name defpool.target_path = path - newpool = defpool.install(build=True, create=True, autostart=True) + defpool.install(build=True, create=True, autostart=True) conn.clear_cache(pools=True) - return newpool + return defpool except Exception, e: raise RuntimeError( _("Couldn't create default storage pool '%s': %s") % (path, str(e))) + + @staticmethod + def get_default_path(conn): + """ + Return the default storage path. If there's a 'default' pool, + report that. If there's no default pool, return the path we would + use for the default. + """ + path = _get_default_pool_path(conn) + if not conn.check_support(conn.SUPPORT_CONN_STORAGE): + os.makedirs(path) + return path + + try: + poolobj = conn.storagePoolLookupByName("default") + return StoragePool(conn, parsexml=poolobj.XMLDesc(0)).target_path + except: + pass + + return StoragePool.build_default_pool(conn).target_path + + @staticmethod def lookup_pool_by_path(conn, path): """ diff --git a/virtinst/util.py b/virtinst/util.py index 620cc06a..71296e59 100644 --- a/virtinst/util.py +++ b/virtinst/util.py @@ -165,7 +165,7 @@ def validate_macaddr(val): form = re.match("^([0-9a-fA-F]{1,2}:){5}[0-9a-fA-F]{1,2}$", val) if form is None: raise ValueError(_("MAC address must be of the format " - "AA:BB:CC:DD:EE:FF")) + "AA:BB:CC:DD:EE:FF, was '%s'") % val) def generate_name(base, collision_cb, suffix="", lib_collision=True, @@ -282,33 +282,9 @@ def parse_node_helper(xml, root_name, callback, exec_class=ValueError): return ret -def xml_parse_wrapper(xml, parse_func, *args, **kwargs): - """ - Parse the passed xml string into an xpath context, which is passed - to parse_func, along with any extra arguments. - """ - doc = None - ctx = None - ret = None - register_namespace = kwargs.pop("register_namespace", None) - - try: - doc = libxml2.parseDoc(xml) - ctx = doc.xpathNewContext() - if register_namespace: - register_namespace(ctx) - ret = parse_func(doc, ctx, *args, **kwargs) - finally: - if ctx is not None: - ctx.xpathFreeContext() - if doc is not None: - doc.freeDoc() - return ret - - def generate_uuid(conn): for ignore in range(256): - uuid = randomUUID(conn=conn) + uuid = randomUUID(conn) if not vm_uuid_collision(conn, uuid): return uuid