Remove virt-image, as scheduled

As promised with the last release, remove virt-image. In 6 months I didn't
hear a peep from any actual users that cared.
This commit is contained in:
Cole Robinson 2014-09-06 18:05:43 -04:00
parent 2e7d477156
commit 5aafe008bc
26 changed files with 13 additions and 1762 deletions

2
.gitignore vendored
View File

@ -14,9 +14,7 @@ po/virt-manager.pot
/man/virt-manager.1
/man/virt-install.1
/man/virt-clone.1
/man/virt-image.1
/man/virt-convert.1
/man/virt-image.5
/man/virt-xml.1
/virt-manager.spec

View File

@ -1,240 +0,0 @@
=pod
=head1 NAME
virt-image - Format of the virtual image XML descriptor
=head1 DESCRIPTION
L<virt-image(1)> relies on an XML descriptor to create virtual machines from
virtual machine images. In general, a virtual machine image consists of the
XML descriptor (usually in a file F<image.xml>) and a number of files for
the virtual machine's disks.
In the following explanation of the structure of the image descriptor,
mandatory XML elements are marked as B<element>, whereas optional elements
are marked as I<element>.
All file names in the image descriptor are relative to the location of the
descriptor itself. Generally, disk files are either kept in the same
directory as the image descriptor, or in a subdirectory.
=head1 HOST MATCHING
The image descriptor contains information on the requirements a guest has
on the host platform through one or more the F</image/domain/boot>
descriptors (see section L</BOOT>). The image can only be used if at least
one of the boot descriptors is suitable for the host platform; a boot
descriptor is suitable if:
=over 4
=item *
The CPU architecture of the boot descriptor, given by the
F<boot/guest/arch> element, is supported by the host
=item *
The host supports a guest with the features requested in the
F<boot/guest/features> element, such as providing an APIC, or having ACPI
turned off
=back
If a suitable boot descriptor is found, the guest is created and booted
according to the information about booting the OS from the F<boot/os>
element and with the disks specified in the F<boot/drive> element. If more
than one suitable boot descriptor is found, one of them is chosen based on
a heuristic, generally preferring paravirtualized guests over full
virtualized ones, though this is an implementation detail of the tool
creating the virtual machine.
=head1 STRUCTURE
The image descriptor consists of three sections, all contained in the
toplevel B<image> element:
=over 4
=item General metadata about the image
A number of elements like I<label>, B<name>, and I<description> that give
some simple information about the image. The B<name> must be a string
suitable as a name for the virtual machine, the I<label> is a short
human-readable string suitable for display in graphical UI's, and the
I<description> should be a longer, free-form description of the purpose of
the image. The B<name> is mandatory.
=item Virtual machine attributes
The B<domain> element contains instructions on how to boot the image, and
device attributes such as the number of virtual CPU's and the size of the
memory. (see section L</DOMAIN>)
=item Storage layout
The B<storage> element lists the files to back the virtual machine's disks
and some information about their format and use. (see section L</STORAGE>)
=back
=head1 DOMAIN
The B<domain> element contains one or more B<boot> descriptors (see section
L</BOOT>) and a B<devices> element. The B<Devices> element lists the
recommended number of virtual CPU's in the B<vcpu> element and the
recommended amount of memory in kB in the B<memory> element. It also
indicates whether the virtual machine should have a network interface
through the I<interface> element and whether the virtual machine has a
graphical interface through the I<graphics> element.
=head2 BOOT
Each B<boot> descriptor details how the virtual machine should be started
on a certain hypervisor. The B<type> attribute of the B<boot> element,
which can either be C<xen> or C<hvm>, depending on whether the boot
descriptor is for a paravirtualized Xen(tm) guest or a fully-virtualized
guest.
The B<boot> element contains three subelements:
=over 4
=item The platform requirements of the guest
The platform requirements, contained in the B<guest> element, consist of
the B<arch> element and the I<features> element. The B<arch> element
indicates the CPU architecture the guest expects, e.g. C<i686>, C<x86_64>,
or C<ppc>.
The I<features> element indicates whether certain platform features should
be on or off. Currently, the platform features are I<pae>, I<acpi>, and
I<apic>. Omitting a togglable feature tag turns it off.
=item The details of booting the image's operating system
The B<os> element for fully-virtualized C<hvm> guests contains a B<loader>
element whose B<dev> attribute indicates whether to boot off a hard disk
(C<dev='hd'>) or off a CD-ROM (C<dev='cdrom'>)
For paravirtualized guests, the B<os> element either contains a
C<< <loader>pygrub</loader> >> element, indicating that the guest should be
booted with F<pygrub>, or B<kernel>, I<initrd> and I<cmdline> elements. The
contents of the B<kernel> and I<initrd> elements are the names of the
kernel and initrd files, whereas the I<cmdline> element contains the
command line that should be passed to the kernel on boot.
=item The mapping of disk files as devices into the guest
The mapping of disk files into the guest is performed by a list of B<drive>
elements inside the B<boot> element. Each B<drive> element references the
name of a disk file from the L</STORAGE> section through its B<disk>
attribute and can optionally specify as what device that disk file should
appear in the guest through its I<target> attribute. If the I<target> is
omitted, device names are assigned in the order in which the B<drive>
elements appear, skipping already assigned devices.
=back
=head1 STORAGE
The B<storage> element lists the disk image files that are part of the
virtual machine image in a list of one or more B<disk> elements. Each
B<disk> element can contain the following attributes:
=over 4
=item *
the B<file> attribute giving the name of the disk file
=item *
an optional I<id> attribute. The name given with that attribute is used to
reference the disk from the B<drive> element of a B<boot> descriptor. If
the I<id> attribute is missing, it defaults to the B<file> attribute.
=item *
the B<use> attribute indicating whether the disk file is a C<system>,
C<user>, or C<scratch> disk. The B<use> attribute differentiates disk files
so that an update based on replacing disk files can replace C<system>
disks, but leave C<user> disks untouched.
Generally, C<system> disks contain application code, C<user> disks contain
the application's data, and C<scratch> disks contain temporary state that
can be erased between runs of the guest.
The virtual machine image must contain files for all C<system> disks, and
may contain files for the C<user> and C<scratch> disks. If the latter are
not part of the image, they are initialized as empty files when a guest is
created, with the size given by the I<size> attribute.
=item *
the I<size> attribute giving the size of the disk in MB.
=item *
the I<format> attribute giving the format of the disk file. Currently, this
can be one of: C<raw> C<iso>, C<qcow>, C<qcow2>, or C<vmdk>.
=back
=head1 EXAMPLE
The image descriptor below can be used to create a virtual machine running
the System Rescue CD (C<http://www.sysresccd.org/>) Besides the descriptor,
you only need the ISO image from the System Rescue CD website.
<?xml version="1.0" encoding="UTF-8"?>
<image>
<name>sysresccd</name>
<domain>
<boot type="hvm">
<guest>
<arch>i686</arch>
</guest>
<os>
<loader dev="cdrom"/>
</os>
<drive disk="root.raw" target="hda"/>
<drive disk="sysresc"/>
</boot>
<devices>
<vcpu>1</vcpu>
<memory>262144</memory>
<interface/>
<graphics/>
</devices>
</domain>
<storage>
<disk file="root.raw" use="scratch" size="100" format="raw"/>
<disk id="sysresc" file="isos/systemrescuecd.iso"
use="system" format="iso"/>
</storage>
</image>
To create a virtual machine, save the above XML in F<image.xml> and run:
# virt-image --vnc image.xml
=head1 BUGS
Please see C<http://virt-manager.org/page/BugReporting>
=head1 COPYRIGHT
Copyright (C) Red Hat, Inc, and various contributors.
This is free software. You may redistribute copies of it under the terms
of the GNU General Public License C<http://www.gnu.org/licenses/gpl.html>.
There is NO WARRANTY, to the extent permitted by law.
=head1 SEE ALSO
L<virt-image(1)>, L<virt-install(1)>, the project website
C<http://virt-manager.org>, the Relax-NG grammar for image XML C<image.rng>
=cut

View File

@ -1,190 +0,0 @@
=pod
=head1 NAME
virt-image - create virtual machines from an image descriptor
=head1 SYNOPSIS
B<virt-image> [OPTION]... IMAGE.XML
=head1 DESCRIPTION
WARNING: B<virt-image> is planned for removal in the near future. If you are depending on this tool, please contact the developers at virt-tools-list@redhat.com
B<virt-image> is a command line tool for creating virtual machines from an
XML image descriptor C<IMAGE.XML> (L<virt-image(5)>). Most attributes of
the virtual machine are taken from the XML descriptor (e.g., where the
files to back the virtual machine's disks are and how to map them into the
guest), though certain information must be added on the command line, such
as the name of the guest.
The XML descriptor defines most attributes of the guest, making it possible
to bundle and distribute it together with the files backing the guest's
disks.
=head1 OPTIONS
Most options can be omitted, in which case B<virt-image> will use defaults
from the XML descriptor. When defaults are taken from the XML descriptor,
they are indicated below as a path. --name is the only required command
line option.
=over 4
=item -h, --help
Show the help message and exit
=item --version
Show program's version number and exit
=item --connect=URI
Connect to a non-default hypervisor. See L<virt-install(1)> for details
=back
=head2 General Options
General configuration parameters that apply to all types of guest installs.
=over 2
=item -n NAME, --name=NAME
Name of the guest instance
=item --memory=MEMORY
Memory to allocate for the guest, in MiB. Defaults to C</image/devices/memory> in the XML descriptor. This deprecates the -r/--ram option.
See L<virt-install(1)> for more details.
=item --vcpus=VCPUS
Number of vcpus to configure for your guest. Defaults to
C</image/devices/vcpu> in the XML descriptor. This option can also be
used to set CPU topology, please see L<virt-install(1)> for more info.
=item --cpu
Configure the CPU and CPU features exposed to the guest. Please see
L<virt-install(1)> for more info.
=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<virt-install(1)> for valid values.
=back
=head2 Networking Configuration
=over 2
=item -w NETWORK, --network=NETWORK
Connect the guest to the host network. This deprecates the -m/--mac and -b/--bridge options. See L<virt-install(1)> for details.
=back
=head2 Graphics Configuration
If no graphics option is specified, C<virt-image> will default to
'--graphics vnc' if the DISPLAY environment variable is set, otherwise
'--graphics none' is used.
=over 2
=item --graphics TYPE,opt1=arg1,opt2=arg2,...
Specifies the graphical display configuration. This does not configure any
virtual hardware, just how the guest's graphical display can be accessed.
See L<virt-install(1)> for details usage info.
This deprecates the following options: --vnc, --vncport, --vnclisten, -k/--keymap, --sdl, --nographics
=back
=head2 Miscellaneous Options
=over 2
=item --print-xml
Print the libvirt XML, but do not start the guest.
=item --boot=BOOT
The zero-based index of the boot record to use. The XML descriptor can
contain multiple C</image/domain/boot> elements for use on different
hypervisors. By default, the one that is most appropriate for the current
hypervisor is selected.
=item --replace
Shutdown and remove any existing guest with the passed C<--name> before
installing from the image.
=item --noreboot
Prevent the domain automatically booting after importing the image.
=item --skip-checksum
Do not check disk images against checksums (if they are listed in the
image xml).
=item -d, --debug
Print debugging information.
=back
=head1 EXAMPLES
Create and start a guest called C<example> with a VNC console from
C<image.xml>:
# virt-image --name example --vnc image.xml
Print the libvirt XML for a guest called C<example> without graphics, but
do not create or start a virtual machine:
# virt-image --print --name example --nographics image.xml
=head1 BUGS
Please see http://virt-manager.org/page/BugReporting
=head1 COPYRIGHT
Copyright (C) Red Hat, Inc, and various contributors.
This is free software. You may redistribute copies of it under the terms
of the GNU General Public License C<http://www.gnu.org/licenses/gpl.html>.
There is NO WARRANTY, to the extent permitted by law.
=head1 SEE ALSO
L<virt-image(5)>, L<virt-install(1)>, the project website
C<http://virt-manager.org>
=cut

View File

@ -32,7 +32,7 @@ def _generate_potfiles_in():
return ret
scripts = ["virt-manager", "virt-install",
"virt-clone", "virt-image", "virt-convert", "virt-xml"]
"virt-clone", "virt-convert", "virt-xml"]
potfiles = "\n".join(scripts) + "\n\n"
potfiles += "\n".join(find("virtManager", "*.py")) + "\n\n"
@ -145,7 +145,7 @@ class my_build(build):
def _make_bin_wrappers(self):
cmds = ["virt-manager", "virt-install", "virt-clone",
"virt-image", "virt-convert", "virt-xml"]
"virt-convert", "virt-xml"]
if not os.path.exists("build"):
os.mkdir("build")
@ -164,16 +164,9 @@ class my_build(build):
def _make_man_pages(self):
for path in glob.glob("man/*.pod"):
base = os.path.basename(path)
mantype = "1"
newbase = base
if base == "virt-image-xml.pod":
mantype = "5"
newbase = "virt-image.pod"
appname = os.path.splitext(newbase)[0]
appname = os.path.splitext(base)[0]
newpath = os.path.join(os.path.dirname(path),
appname + "." + mantype)
appname + ".1")
print "Generating %s" % newpath
ret = os.system('pod2man '
@ -566,7 +559,7 @@ class CheckPylint(Command):
pass
def run(self):
files = ["setup.py", "virt-install", "virt-clone", "virt-image",
files = ["setup.py", "virt-install", "virt-clone",
"virt-convert", "virt-xml", "virt-manager",
"virtcli", "virtinst", "virtconv", "virtManager",
"tests"]
@ -597,7 +590,6 @@ setup(
"build/virt-manager",
"build/virt-clone",
"build/virt-install",
"build/virt-image",
"build/virt-convert",
"build/virt-xml"]),
@ -606,7 +598,6 @@ setup(
"virt-manager",
"virt-install",
"virt-clone",
"virt-image",
"virt-convert",
"virt-xml",
]),
@ -618,11 +609,9 @@ setup(
"man/virt-manager.1",
"man/virt-install.1",
"man/virt-clone.1",
"man/virt-image.1",
"man/virt-convert.1",
"man/virt-xml.1"
]),
("share/man/man5", ["man/virt-image.5"]),
("share/virt-manager/virtManager", glob.glob("virtManager/*.py")),

View File

@ -68,7 +68,6 @@ def _cleanup_imports_cb():
atexit.register(_cleanup_imports_cb)
virtinstall = _import("virtinstall", "virt-install")
virtimage = _import("virtimage", "virt-image")
virtclone = _import("virtclone", "virt-clone")
virtconvert = _import("virtconvert", "virt-convert")
virtxml = _import("virtxml", "virt-xml")

View File

@ -1,42 +0,0 @@
<domain type="test">
<name>foobar</name>
<uuid>00000000-1111-2222-3333-444444444444</uuid>
<memory>262144</memory>
<currentMemory>131072</currentMemory>
<vcpu>7</vcpu>
<bootloader>/usr/bin/pygrub</bootloader>
<features>
<pae/>
</features>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<disk type="file" device="disk">
<source file="/tmp/__virtinst__cli_root.raw"/>
<target dev="xvda" bus="xen"/>
</disk>
<disk type="file" device="disk">
<source file="/tmp/__virtinst__cli_scratch.raw"/>
<target dev="xvdc" bus="xen"/>
</disk>
<controller type="usb" index="0" model="ich9-ehci1"/>
<controller type="usb" index="0" model="ich9-uhci1">
<master startport="0"/>
</controller>
<controller type="usb" index="0" model="ich9-uhci2">
<master startport="2"/>
</controller>
<controller type="usb" index="0" model="ich9-uhci3">
<master startport="4"/>
</controller>
<interface type="user">
<mac address="00:11:22:33:44:55"/>
</interface>
<input type="mouse" bus="xen"/>
<graphics type="vnc" port="-1" keymap="en-us"/>
<video>
<model type="vga"/>
</video>
</devices>
</domain>

View File

@ -1,44 +0,0 @@
<domain type="test">
<name>foobar</name>
<uuid>00000000-1111-2222-3333-444444444444</uuid>
<memory>65536</memory>
<currentMemory>65536</currentMemory>
<vcpu>7</vcpu>
<os>
<type arch="i686">hvm</type>
<boot dev="hd"/>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<clock offset="utc"/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<emulator>/usr/bin/test-hv</emulator>
<disk type="file" device="disk">
<source file="/tmp/__virtinst__cli_root.raw"/>
<target dev="hda" bus="ide"/>
</disk>
<controller type="usb" index="0" model="ich9-ehci1"/>
<controller type="usb" index="0" model="ich9-uhci1">
<master startport="0"/>
</controller>
<controller type="usb" index="0" model="ich9-uhci2">
<master startport="2"/>
</controller>
<controller type="usb" index="0" model="ich9-uhci3">
<master startport="4"/>
</controller>
<interface type="user">
<mac address="00:11:22:33:44:55"/>
<model type="e1000"/>
</interface>
<input type="mouse" bus="ps2"/>
<graphics type="vnc" port="-1" keymap="en-us"/>
<console type="pty"/>
</devices>
</domain>

View File

@ -1,38 +0,0 @@
<domain type="test">
<name>foobar</name>
<uuid>00000000-1111-2222-3333-444444444444</uuid>
<memory>65536</memory>
<currentMemory>65536</currentMemory>
<vcpu>7</vcpu>
<bootloader>/usr/bin/pygrub</bootloader>
<features>
<pae/>
</features>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<disk type="file" device="disk">
<source file="/tmp/__virtinst__cli_root.raw"/>
<target dev="xvda" bus="xen"/>
</disk>
<disk type="file" device="disk">
<source file="/tmp/__virtinst__cli_scratch.raw"/>
<target dev="xvdc" bus="xen"/>
</disk>
<controller type="usb" index="0" model="ich9-ehci1"/>
<controller type="usb" index="0" model="ich9-uhci1">
<master startport="0"/>
</controller>
<controller type="usb" index="0" model="ich9-uhci2">
<master startport="2"/>
</controller>
<controller type="usb" index="0" model="ich9-uhci3">
<master startport="4"/>
</controller>
<interface type="user">
<mac address="00:11:22:33:44:55"/>
</interface>
<input type="mouse" bus="xen"/>
</devices>
</domain>

View File

@ -1,37 +0,0 @@
<image>
<label>A simple test image</label>
<domain>
<boot type='xen'>
<guest>
<os_type>xen</os_type>
<arch>i686</arch>
<features><pae/></features>
</guest>
<os>
<loader>pygrub</loader>
</os>
<drive disk="/tmp/__virtinst__cli_root.raw" target="xvda"/>
<drive disk="/tmp/__virtinst__cli_scratch.raw" target="xvdc"/>
</boot>
<boot type="hvm">
<guest>
<arch>i686</arch>
<features><pae/></features>
</guest>
<os>
<type>hvm</type>
<loader dev="hd"/>
</os>
<drive disk="/tmp/__virtinst__cli_root.raw" target="hda"/>
</boot>
<devices>
<vcpu>7</vcpu>
<memory>262144</memory>
<interface/>
</devices>
</domain>
<storage>
<disk file="/tmp/__virtinst__cli_root.raw" format="raw" size="4096" use="system"/>
<disk file="/tmp/__virtinst__cli_scratch.raw" format="raw" size='100' use='scratch'/>
</storage>
</image>

View File

@ -1,38 +0,0 @@
<image>
<label>A simple test image</label>
<domain>
<boot type='xen'>
<guest>
<os_type>xen</os_type>
<arch>i686</arch>
<features><pae/></features>
</guest>
<os>
<loader>pygrub</loader>
</os>
<drive disk="/tmp/__virtinst__cli_root.raw" target="xvda"/>
<drive disk="/tmp/__virtinst__cli_scratch.raw" target="xvdc"/>
</boot>
<boot type="hvm">
<guest>
<arch>i686</arch>
<features><pae/></features>
</guest>
<os>
<type>hvm</type>
<loader dev="hd"/>
</os>
<drive disk="/tmp/__virtinst__cli_root.raw" target="hda"/>
</boot>
<devices>
<vcpu>7</vcpu>
<memory>262144</memory>
<interface/>
<graphics/>
</devices>
</domain>
<storage>
<disk file="/tmp/__virtinst__cli_root.raw" format="raw" size="4096" use="system"/>
<disk file="/tmp/__virtinst__cli_scratch.raw" format="raw" size='100' use='scratch'/>
</storage>
</image>

View File

@ -29,7 +29,7 @@ import StringIO
from virtinst import support
from tests import virtinstall, virtimage, virtclone, virtconvert, virtxml
from tests import virtinstall, virtclone, virtconvert, virtxml
from tests import utils
os.environ["LANG"] = "en_US.UTF-8"
@ -68,20 +68,12 @@ exist_images = [
ro_img,
]
# Images that need to exist ahead of time for virt-image
virtimage_exist = ["/tmp/__virtinst__cli_root.raw"]
# Images created by virt-image
virtimage_new = ["/tmp/__virtinst__cli_scratch.raw"]
# Fake iso for --location iso mounting
fake_iso = ["/tmp/fake.iso"]
exist_files = exist_images + virtimage_exist + fake_iso
new_files = new_images + virtimage_new
clean_files = (new_images + exist_images +
virtimage_exist + virtimage_new + [ro_dir]
+ fake_iso)
exist_files = exist_images + fake_iso
new_files = new_images
clean_files = (new_images + exist_images + [ro_dir] + fake_iso)
promptlist = []
@ -167,8 +159,6 @@ class Command(object):
ret = virtinstall.main(conn=conn)
elif app.count("virt-clone"):
ret = virtclone.main(conn=conn)
elif app.count("virt-image"):
ret = virtimage.main(conn=conn)
elif app.count("virt-convert"):
ret = virtconvert.main(conn=conn)
elif app.count("virt-xml"):
@ -397,10 +387,6 @@ class App(object):
not cli.count("--quiet")):
args += " --print-step all"
elif self.appname == "virt-image":
if not cli.count("--print"):
args += " --print"
elif self.appname == "virt-clone":
if not cli.count("--print-xml"):
args += " --print-xml"
@ -687,7 +673,7 @@ c.add_invalid("--mac 22:22:33:12:34:AB") # Colliding macaddr
c = vinst.add_category("storage", "--pxe --nographics --noautoconsole --hvm")
c.add_valid("--file %(EXISTIMG1)s --nonsparse --file-size 4") # Existing file, other opts
c.add_valid("--file %(EXISTIMG1)s") # Existing file, no opts
c.add_valid("--file %(EXISTIMG1)s --file virt-image --file virt-clone") # Multiple existing files
c.add_valid("--file %(EXISTIMG1)s --file virt-clone --file virt-clone") # Multiple existing files
c.add_valid("--file %(NEWIMG1)s --file-size .00001 --nonsparse") # Nonexistent file
c.add_valid("--disk path=%(EXISTIMG1)s,perms=ro,size=.0001,cache=writethrough,io=threads") # Existing disk, lots of opts
c.add_valid("--disk path=%(EXISTIMG1)s,perms=rw") # Existing disk, rw perms
@ -868,42 +854,6 @@ 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")
c = vimag.add_category("graphics", "--name test-image --boot 0 %(IMAGE_XML)s")
c.add_valid("--sdl") # SDL
c.add_valid("--vnc --keymap ja --vncport 5950 --vnclisten 1.2.3.4") # VNC w/ lots of options
c = vimag.add_category("misc", "")
c.add_valid("--network=?") # Make sure introspection doesn't blow up
c.add_compare("--name foobar --memory 128,maxmemory=256 --os-variant winxp --boot 0 %(IMAGE_XML)s", "image-boot0")
c.add_compare("--name foobar --ram 64 --network user,model=e1000 --boot 1 %(IMAGE_XML)s", "image-boot1")
c.add_compare("--name foobar --ram 64 --boot 0 %(IMAGE_NOGFX_XML)s", "image-nogfx")
c.add_valid("--name test --replace %(IMAGE_XML)s") # Colliding VM name w/ --replace
c.add_invalid("%(IMAGE_XML)s") # No name specified, and no prompt flag
c.add_invalid("--name test %(IMAGE_XML)s") # Colliding VM name without --replace
c = vimag.add_category("network", "--name test-image --boot 0 --nographics %(IMAGE_XML)s")
c.add_valid("--network=user") # user networking
c.add_valid("--network network:default --mac RANDOM") # VirtualNetwork with a random macaddr
c.add_valid("--network network:default --mac 00:11:22:33:44:55") # VirtualNetwork with a random macaddr
c.add_valid("--network=user,model=e1000") # with NIC model
c.add_valid("--network=network:default,model=e1000 --network=user,model=virtio") # several networks
c.add_invalid("--network=FOO") # Nonexistent network
c.add_invalid("--network=network:default --mac 1234") # Invalid mac
c = vimag.add_category("general", "--name test-image %(IMAGE_XML)s")
c.add_valid("") # All default values
c.add_valid("--print") # Print default
c.add_valid("--boot 0") # Manual boot idx 0
c.add_valid("--boot 1") # Manual boot idx 1
c.add_valid("--name foobar --ram 64 --os-variant winxp") # Lots of options
c.add_valid("--name foobar --ram 64 --os-variant none") # OS variant 'none'
c.add_invalid("--boot 10") # Out of bounds index
vconv = App("virt-convert")
@ -1026,7 +976,6 @@ def maketest(cmd):
_cmdlist = promptlist[:]
_cmdlist += vinst.cmds
_cmdlist += vclon.cmds
_cmdlist += vimag.cmds
_cmdlist += vconv.cmds
_cmdlist += vixml.cmds

View File

@ -1,35 +0,0 @@
<image>
<name>test-image</name>
<label>A simple test image</label>
<domain>
<boot type='xen'>
<guest>
<os_type>xen</os_type>
<arch>i386</arch>
<features><pae/></features>
</guest>
<os>
<loader>pygrub</loader>
</os>
<drive disk="root.raw" target="xvda"/>
<drive disk="data.raw" target="xvdb"/>
<drive disk="scratch.raw" target="xvdc"/>
</boot>
<devices>
<vcpu>7</vcpu>
<memory>262144</memory>
<interface/>
<graphics/>
</devices>
</domain>
<storage>
<disk file="disk.img"/>
<disk size="4096" use="system">
<partition file="boot.img"/>
<partition file="root.img"/>
</disk>
<disk file="root.raw" format="raw" size="4096" use="system"/>
<disk file="data.raw" format="raw" size='2048' use="data"/>
<disk file="scratch.raw" format="raw" size='100' use='scratch'/>
</storage>
</image>

View File

@ -1,27 +0,0 @@
<image>
<name>demo</name>
<domain>
<boot type="hvm">
<guest>
<arch>i686</arch>
</guest>
<os>
<loader dev="hd"/>
</os>
<drive disk="mydisk1" target="hda"/>
<drive disk="mydisk2" target="hdb"/>
<drive disk="mydisk3" target="hdc"/>
</boot>
<devices>
<vcpu>1</vcpu>
<memory>262144</memory>
<interface/>
<graphics/>
</devices>
</domain>
<storage>
<disk id="mydisk1" file="image-kernel.xml" use="system" format="qcow2"/>
<disk id="mydisk2" file="image.xml" use="system" format="qcow"/>
<disk id="mydisk3" file="image-format.xml" use="system" format="vmdk"/>
</storage>
</image>

View File

@ -1,37 +0,0 @@
<image>
<name>test-image</name>
<label>A simple test image</label>
<domain>
<boot type='xen'>
<guest>
<os_type>xen</os_type>
<arch>i686</arch>
<features><pae/></features>
</guest>
<os>
<kernel>/foo/kernel</kernel>
<initrd>/foo/initrd</initrd>
<cmdline>ro quiet</cmdline>
</os>
<drive disk="root.raw" target="xvda"/>
<drive disk="data.raw" target="xvdb"/>
<drive disk="scratch.raw" target="xvdc"/>
</boot>
<devices>
<vcpu>7</vcpu>
<memory>262144</memory>
<interface/>
<graphics/>
</devices>
</domain>
<storage>
<disk file="disk.img"/>
<disk size="4096" use="system">
<partition file="boot.img"/>
<partition file="root.img"/>
</disk>
<disk file="root.raw" format="raw" size="4096" use="scratch"/>
<disk file="data.raw" format="raw" size='2048' use="scratch"/>
<disk file="scratch.raw" format="raw" size='100' use='scratch'/>
</storage>
</image>

View File

@ -1,48 +0,0 @@
<image>
<name>test-image</name>
<label>A simple test image</label>
<domain>
<boot type='xen'>
<guest>
<os_type>xen</os_type>
<arch>i686</arch>
<features><pae/></features>
</guest>
<os>
<loader>pygrub</loader>
</os>
<drive disk="root.raw" target="xvda"/>
<drive disk="data.raw" target="xvdb"/>
<drive disk="scratch.raw" target="xvdc"/>
</boot>
<boot type="hvm">
<guest>
<arch>i686</arch>
<features><pae/></features>
</guest>
<os>
<type>hvm</type>
<loader dev="hd"/>
</os>
<drive disk="root.raw" target="hda"/>
<drive disk="data.raw" target="hdb"/>
<drive disk="scratch.raw" target="hdd"/>
</boot>
<devices>
<vcpu>7</vcpu>
<memory>262144</memory>
<interface/>
<graphics/>
</devices>
</domain>
<storage>
<disk file="disk.img"/>
<disk size="4096" use="system">
<partition file="boot.img"/>
<partition file="root.img"/>
</disk>
<disk file="root.raw" format="raw" size="4096" use="scratch"/>
<disk file="data.raw" format="raw" size='2048' use="scratch"/>
<disk file="scratch.raw" format="raw" size='100' use='scratch'/>
</storage>
</image>

View File

@ -1,40 +0,0 @@
<domain type="kvm">
<name>TestGuest</name>
<uuid>12345678-1234-1234-1234-123456789012</uuid>
<memory>409600</memory>
<currentMemory>204800</currentMemory>
<vcpu>5</vcpu>
<os>
<type arch="i686">hvm</type>
<boot dev="hd"/>
</os>
<features>
<acpi/>
<apic/>
</features>
<clock offset="utc"/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<emulator>/usr/lib/xen/bin/qemu-dm</emulator>
<disk type="file" device="disk">
<driver name="qemu" type="qcow2"/>
<source file="/tmp/tests/image-xml/image-kernel.xml"/>
<target dev="hda" bus="ide"/>
</disk>
<disk type="file" device="disk">
<driver name="qemu" type="qcow"/>
<source file="/tmp/tests/image-xml/image.xml"/>
<target dev="hdb" bus="ide"/>
</disk>
<disk type="file" device="disk">
<driver name="qemu" type="vmdk"/>
<source file="/tmp/tests/image-xml/image-format.xml"/>
<target dev="hdc" bus="ide"/>
</disk>
<input type="mouse" bus="ps2"/>
<graphics type="vnc" port="-1" keymap="ja"/>
<console type="pty"/>
</devices>
</domain>

View File

@ -1,38 +0,0 @@
<domain type="test">
<name>TestGuest</name>
<uuid>12345678-1234-1234-1234-123456789012</uuid>
<memory>409600</memory>
<currentMemory>204800</currentMemory>
<vcpu>5</vcpu>
<os>
<type arch="i686">hvm</type>
<boot dev="hd"/>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<clock offset="utc"/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<emulator>/usr/lib/xen/bin/qemu-dm</emulator>
<disk type="file" device="disk">
<source file="/tmp/tests/image-xml/root.raw"/>
<target dev="hda" bus="ide"/>
</disk>
<disk type="file" device="disk">
<source file="/tmp/tests/image-xml/data.raw"/>
<target dev="hdb" bus="ide"/>
</disk>
<disk type="file" device="disk">
<source file="/tmp/tests/image-xml/scratch.raw"/>
<target dev="hdd" bus="ide"/>
</disk>
<input type="mouse" bus="ps2"/>
<graphics type="vnc" port="-1" keymap="ja"/>
<console type="pty"/>
</devices>
</domain>

View File

@ -1,35 +0,0 @@
<domain type="test">
<name>TestGuest</name>
<uuid>12345678-1234-1234-1234-123456789012</uuid>
<memory>409600</memory>
<currentMemory>204800</currentMemory>
<vcpu>5</vcpu>
<os>
<type arch="i686">xen</type>
<kernel>/foo/kernel</kernel>
<initrd>/foo/initrd</initrd>
<cmdline>ro quiet</cmdline>
</os>
<features>
<pae/>
</features>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<disk type="file" device="disk">
<source file="/tmp/tests/image-xml/root.raw"/>
<target dev="xvda" bus="xen"/>
</disk>
<disk type="file" device="disk">
<source file="/tmp/tests/image-xml/data.raw"/>
<target dev="xvdb" bus="xen"/>
</disk>
<disk type="file" device="disk">
<source file="/tmp/tests/image-xml/scratch.raw"/>
<target dev="xvdc" bus="xen"/>
</disk>
<input type="mouse" bus="xen"/>
<graphics type="vnc" port="-1" keymap="ja"/>
</devices>
</domain>

View File

@ -1,30 +0,0 @@
<domain type="test">
<name>TestGuest</name>
<uuid>12345678-1234-1234-1234-123456789012</uuid>
<memory>409600</memory>
<currentMemory>204800</currentMemory>
<vcpu>5</vcpu>
<bootloader>/usr/bin/pygrub</bootloader>
<features>
<pae/>
</features>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<disk type="file" device="disk">
<source file="/tmp/tests/image-xml/root.raw"/>
<target dev="xvda" bus="xen"/>
</disk>
<disk type="file" device="disk">
<source file="/tmp/tests/image-xml/data.raw"/>
<target dev="xvdb" bus="xen"/>
</disk>
<disk type="file" device="disk">
<source file="/tmp/tests/image-xml/scratch.raw"/>
<target dev="xvdc" bus="xen"/>
</disk>
<input type="mouse" bus="xen"/>
<graphics type="vnc" port="-1" keymap="ja"/>
</devices>
</domain>

View File

@ -1,49 +0,0 @@
<image>
<name>test-image</name>
<label>A simple test image</label>
<domain>
<boot type='xen'>
<guest>
<os_type>xen</os_type>
<arch>i686</arch>
<features><pae/></features>
</guest>
<os>
<loader>pygrub</loader>
</os>
<drive disk="root.raw" target="xvda"/>
<drive disk="data.raw" target="xvdb"/>
<drive disk="scratch.raw" target="xvdc"/>
</boot>
<boot type="hvm">
<guest>
<arch>i686</arch>
<features><pae/></features>
</guest>
<os>
<type>hvm</type>
<loader dev="hd"/>
</os>
<drive disk="root.raw" target="hda"/>
<drive disk="data.raw" target="hdb"/>
<drive disk="scratch.raw" target="hdd"/>
</boot>
<devices>
<vcpu>7</vcpu>
<memory>262144</memory>
<interface/>
<interface/>
<graphics/>
</devices>
</domain>
<storage>
<disk file="disk.img"/>
<disk size="4096" use="system">
<partition file="boot.img"/>
<partition file="root.img"/>
</disk>
<disk file="root.raw" format="raw" size="4096" use="system"/>
<disk file="data.raw" format="raw" size='2048' use="data"/>
<disk file="scratch.raw" format="raw" size='100' use='scratch'/>
</storage>
</image>

View File

@ -1,110 +0,0 @@
# Copyright (C) 2013 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
import os
import unittest
from virtinst import virtimage
from tests import utils
qemuuri = "__virtinst_test__test:///default,caps=%s/tests/capabilities-xml/capabilities-kvm.xml,qemu,predictable" % os.getcwd()
# pylint: disable=protected-access
# Access to protected member, needed to unittest stuff
class TestImageParser(unittest.TestCase):
basedir = "tests/image-xml/"
conn = utils.open_testdefault()
qemuconn = utils.openconn(qemuuri)
def testImageParsing(self):
f = open(os.path.join(self.basedir, "image.xml"), "r")
xml = f.read()
f.close()
img = virtimage.parse(xml, ".")
self.assertEqual("test-image", img.name)
self.assertTrue(img.domain)
self.assertEqual(5, len(img.storage))
self.assertEqual(2, len(img.domain.boots))
self.assertEqual(1, img.domain.interface)
boot = img.domain.boots[0]
self.assertEqual("xvdb", boot.drives[1].target)
def testMultipleNics(self):
f = open(os.path.join(self.basedir, "image2nics.xml"), "r")
xml = f.read()
f.close()
img = virtimage.parse(xml, ".")
self.assertEqual(2, img.domain.interface)
def testBadArch(self):
"""Makes sure we sanitize i386->i686"""
image = virtimage.parse_file(self.basedir + "image-bad-arch.xml")
virtimage.ImageInstaller(self.conn, image, 0)
self.assertTrue(True)
def testStorageFormat(self):
self._image2XMLhelper("image-format.xml", "image-format-out.xml",
qemu=True)
def _image2XMLhelper(self, image_xml, output_xmls, qemu=False):
image2guestdir = self.basedir + "image2guest/"
image = virtimage.parse_file(self.basedir + image_xml)
if type(output_xmls) is not list:
output_xmls = [output_xmls]
conn = qemu and self.qemuconn or self.conn
gtype = qemu and "qemu" or "xen"
for idx in range(len(output_xmls)):
fname = output_xmls[idx]
inst = virtimage.ImageInstaller(conn, image, boot_index=idx)
capsguest, capsdomain = inst.get_caps_guest()
if capsguest.os_type == "hvm":
g = utils.get_basic_fullyvirt_guest(typ=gtype)
else:
g = utils.get_basic_paravirt_guest()
utils.set_conn(conn)
g.os.os_type = capsguest.os_type
g.type = capsdomain.hypervisor_type
g.os.arch = capsguest.arch
g.installer = inst
# pylint: disable=unpacking-non-sequence
ignore, actual_out = g.start_install(return_xml=True, dry=True)
actual_out = g.get_install_xml(install=False)
expect_file = os.path.join(image2guestdir + fname)
actual_out = actual_out.replace(os.getcwd(), "/tmp")
utils.diff_compare(actual_out, expect_file)
utils.reset_conn()
def testImage2XML(self):
# Build guest XML from the image xml
self._image2XMLhelper("image.xml", ["image-xenpv32.xml",
"image-xenfv32.xml"])
self._image2XMLhelper("image-kernel.xml", ["image-xenpv32-kernel.xml"])
if __name__ == "__main__":
unittest.main()

View File

@ -82,7 +82,7 @@ class TestMisc(unittest.TestCase):
"""
Make sure virtinst doesn't pull in any gnome modules
"""
files = ["virt-install", "virt-clone", "virt-convert", "virt-image"]
files = ["virt-install", "virt-clone", "virt-convert"]
files += _find_py("virtinst")
files += _find_py("virtconv")
files += _find_py("virtcli")

View File

@ -1,172 +0,0 @@
#!/usr/bin/python2 -tt
#
# Create a virtual machine from an XML image description
#
# Copyright 2007, 2014 Red Hat, Inc.
# David Lutterkort <dlutter@redhat.com>
#
# 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 argparse
import logging
import os
import sys
import time
import urlgrabber.progress as progress
import virtinst.cli as cli
from virtinst.cli import fail, print_stdout, print_stderr
from virtinst import virtimage
# Option parsing
def parse_args():
parser = cli.setupParser(
"%(prog)s image.xml [OPTIONS]",
_("Create a virtual machine from a virt-image(5) image descriptor."),
introspection_epilog=True)
cli.add_connect_option(parser)
parser.add_argument("image", metavar="image.xml", nargs='?',
help=_("virt-image(5) image descriptor"))
geng = parser.add_argument_group(_("General Options"))
geng.add_argument("-n", "--name", help=_("Name of the guest instance"))
geng.add_argument("-u", "--uuid", help=argparse.SUPPRESS)
cli.add_memory_option(geng, backcompat=True)
cli.vcpu_cli_options(geng)
cli.add_distro_options(geng)
cli.add_old_feature_options(geng)
cli.network_option_group(parser)
cli.graphics_option_group(parser)
misc = parser.add_argument_group(_("Miscellaneous Options"))
misc.add_argument("--boot", type=int,
help=_("The zero-based index of the boot record to use"))
misc.add_argument("--skip-checksum", action="store_true",
help=_("Skip disk checksum verification process"))
cli.add_misc_options(misc, prompt=True, replace=True, printxml=True,
noreboot=True)
return parser.parse_args()
def main(conn=None):
cli.earlyLogging()
options = parse_args()
options.quiet = options.xmlonly or options.quiet
cli.setupLogging("virt-image", options.debug, options.quiet)
cli.set_prompt(options.prompt)
cli.convert_old_features(options)
parsermap = cli.build_parser_map(options,
only=["memory", "vcpus", "cpu", "network", "graphics", "features"])
if cli.check_option_introspection(options, parsermap):
return 0
if not options.image:
fail(_("You need to provide an image XML descriptor"))
if conn is None:
conn = cli.getConnection(options.connect)
try:
image = virtimage.parse_file(options.image)
except RuntimeError, msg:
fail("%s '%s': %s" % (_("Cannot parse"), options.image, msg))
if options.boot is not None:
nboots = len(image.domain.boots)
if options.boot < 0 or options.boot >= nboots:
fail(_("The index for --boot must be between 0 and %d") %
(nboots - 1))
# Build the Installer instance
installer = virtimage.ImageInstaller(conn, image, boot_index=options.boot)
guest = conn.caps.build_virtinst_guest(conn, *installer.get_caps_guest())
guest.installer = installer
cli.convert_old_memory(options)
cli.convert_old_networks(options, image.domain.interface)
cli.convert_old_graphics(guest, options,
default_override=bool(image.domain.graphics))
cli.convert_old_cpuset(options)
if not options.vcpus:
options.vcpus = image.domain.vcpu or ""
if not options.memory and image.domain.memory:
options.memory = image.domain.memory
guest.replace = options.replace
cli.set_os_variant(guest, options.distro_type, options.distro_variant)
name = options.name or image.name
if not name:
fail(cli.name_missing)
guest.name = name
if options.uuid:
guest.uuid = options.uuid
cli.parse_option_strings(parsermap, options, guest, None)
guest.add_default_devices()
msg = _("\nvirt-image is planned for removal in the near future. "
"If you are depending on this tool, please contact the developers "
"at virt-tools-list@redhat.com\n")
logging.warning(msg)
if "VIRTINST_TEST_SUITE" not in os.environ:
if options.quiet:
print msg
time.sleep(3)
# we've got everything -- try to start the install
if options.xmlonly:
start_xml, final_xml = guest.start_install(return_xml=True)
print_stdout(start_xml or final_xml, do_force=True)
return 0
meter = progress.TextMeter(fo=sys.stdout)
if not options.skip_checksum:
for disk in image.storage.values():
disk.check_disk_signature(meter=meter)
try:
print_stdout("\n")
print_stdout(_("Creating guest %s...") % guest.name)
guest.start_install(meter=meter, noboot=options.noreboot)
except RuntimeError:
raise
except Exception, e:
fail(e, do_exit=False)
cli.install_fail(guest)
return 0
if __name__ == "__main__":
try:
sys.exit(main())
except SystemExit, sys_e:
sys.exit(sys_e.code)
except KeyboardInterrupt:
print_stderr(_("Installation aborted at user request"))
except Exception, main_e:
fail(main_e)

View File

@ -88,7 +88,6 @@ Requires: virt-manager-common = %{verrel}
Provides: virt-install
Provides: virt-clone
Provides: virt-image
Provides: virt-convert
Provides: virt-xml
Obsoletes: python-virtinst
@ -193,18 +192,14 @@ fi
%{_mandir}/man1/virt-clone.1*
%{_mandir}/man1/virt-convert.1*
%{_mandir}/man1/virt-xml.1*
%{_mandir}/man1/virt-image.1*
%{_mandir}/man5/virt-image.5*
%{_datadir}/%{name}/virt-install
%{_datadir}/%{name}/virt-clone
%{_datadir}/%{name}/virt-image
%{_datadir}/%{name}/virt-convert
%{_datadir}/%{name}/virt-xml
%{_bindir}/virt-install
%{_bindir}/virt-clone
%{_bindir}/virt-image
%{_bindir}/virt-convert
%{_bindir}/virt-xml

View File

@ -653,7 +653,7 @@ def add_gfx_option(devg):
def graphics_option_group(parser):
"""
Register vnc + sdl options for virt-install and virt-image
Register vnc + sdl options for virt-install
"""
vncg = parser.add_argument_group(_("Graphics Configuration"))
add_gfx_option(vncg)
@ -674,7 +674,7 @@ def graphics_option_group(parser):
def network_option_group(parser):
"""
Register common network options for virt-install and virt-image
Register common network options for virt-install
"""
netg = parser.add_argument_group(_("Networking Configuration"))

View File

@ -1,429 +0,0 @@
# Sample code to parse an image XML description and
# spit out libvirt XML
#
# Copyright 2007, 2013, 2014 Red Hat, Inc.
# David Lutterkort <dlutter@redhat.com>
#
# 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 urlgrabber
from virtinst import CapabilitiesParser
from virtinst import Installer
from virtinst import VirtualDisk
from virtinst import util
class Image(object):
"""The toplevel object representing a VM image"""
def __init__(self, node=None, base=None, filename=None):
self.storage = {}
self.domain = None
if filename is None:
self.filename = None
else:
self.filename = os.path.abspath(filename)
if base is None:
if filename is not None:
self.base = os.path.dirname(filename)
if self.base == '':
self.base = "."
else:
self.base = "."
else:
self.base = base
self.name = None
self.label = None
self.descr = None
self.version = None
self.release = None
if node is not None:
self.parseXML(node)
def abspath(self, p):
"""Turn P into an absolute path. Relative paths are taken relative
to self.BASE"""
return os.path.abspath(os.path.join(self.base, p))
def parseXML(self, node):
self.name = xpathString(node, "name")
self.label = xpathString(node, "label")
self.descr = xpathString(node, "description")
self.version = xpathString(node, "name/@version")
self.release = xpathString(node, "name/@release")
for d in node.xpathEval("storage/disk"):
disk = Disk(d)
if disk.file is None:
disk.id = "disk%d.img" % len(self.storage)
disk.file = "disk%d.img" % (len(self.storage) + 1)
if disk.id in self.storage:
raise RuntimeError("Disk file '%s' defined twice" % disk.file)
self.storage[disk.id] = disk
lm = node.xpathEval("domain")
if len(lm) == 1:
self.domain = Domain(lm[0])
else:
raise RuntimeError(_("Expected exactly one 'domain' element"))
# Connect the disk maps to the disk definitions
for boot in self.domain.boots:
for d in boot.drives:
if d.disk_id not in self.storage:
raise RuntimeError(_("Disk entry for '%s' not found")
% d.disk_id)
d.disk = self.storage[d.disk_id]
class Domain(object):
"""The description of a virtual domain as part of an image"""
def __init__(self, node=None):
self.boots = []
self.vcpu = None
self.memory = None
self.interface = 0
self.graphics = None
if node is not None:
self.parseXML(node)
def parseXML(self, node):
self.boots = [Boot(b) for b in node.xpathEval("boot")]
self.vcpu = xpathString(node, "devices/vcpu", 1)
tmpmem = xpathString(node, "devices/memory")
self.interface = int(node.xpathEval("count(devices/interface)"))
self.graphics = node.xpathEval("count(devices/graphics)") > 0
if tmpmem is not None:
try:
self.memory = int(tmpmem)
except ValueError:
raise RuntimeError(_("Memory must be an integer, "
"but is '%s'") % self.memory)
else:
tmpmem = 0
class ImageFeatures(CapabilitiesParser.Features):
def __init__(self, node=None):
CapabilitiesParser.Features.__init__(self, node)
def _extractFeature(self, feature, d, n):
state = xpathString(n, "@state", "on")
if state == "on":
d[feature] = CapabilitiesParser.FEATURE_ON
elif state == "off":
d[feature] = CapabilitiesParser.FEATURE_OFF
else:
raise RuntimeError("The state for feature %s must be "
"either 'on' or 'off', but is '%s'" %
(feature, state))
class Boot(object):
"""The overall description of how the image can be booted, including
required capabilities of the host and mapping of disks into the VM"""
def __init__(self, node=None):
# 'xen' or 'hvm'
self.type = None
# Either 'pygrub' or nothing; might have others in the future
# For HVM, figure outhte right loader based on the guest
self.loader = None
# Only used for hvm
self.bootdev = None
self.kernel = None
self.initrd = None
self.cmdline = None
self.drives = []
self.arch = None
self.features = ImageFeatures()
if node is not None:
self.parseXML(node)
def parseXML(self, node):
self.type = xpathString(node, "@type")
self.loader = xpathString(node, "os/loader")
self.bootdev = xpathString(node, "os/loader/@dev")
self.kernel = xpathString(node, "os/kernel")
self.initrd = xpathString(node, "os/initrd")
self.cmdline = xpathString(node, "os/cmdline")
self.arch = util.sanitize_arch(xpathString(node, "guest/arch"))
fl = node.xpathEval("guest/features")
if len(fl) > 1:
raise RuntimeError("Expected at most one <features> element "
"in %s boot descriptor for %s" %
(self.type, self.arch))
elif len(fl) == 1:
self.features = ImageFeatures(fl[0])
for d in node.xpathEval("drive"):
self.drives.append(Drive(d))
validate(self.type is not None,
"The boot type must be provided")
validate(self.type == "hvm" or self.type == "xen",
"Boot type must be 'xen' or 'hvm', but is %s" % self.type)
validate(self.arch is not None, "Missing guest arch")
validate(self.loader is None or self.loader == "pygrub",
"Invalid loader %s" % self.loader)
validate([None, "hd", "cdrom"].count(self.bootdev) > 0,
"Invalid bootdev %s" % self.bootdev)
# We should make sure that kernel/initrd/cmdline are only used for pv
# and without a loader
class Drive(object):
"""The mapping of a disk from the storage section to a virtual drive
in a guest"""
def __init__(self, node=None):
self.disk_id = None
self.target = None
self.disk = None # Will point to the underlying Disk object
if node:
self.parseXML(node)
def parseXML(self, node):
self.disk_id = xpathString(node, "@disk")
self.target = xpathString(node, "@target")
class Disk(object):
FORMAT_RAW = "raw"
FORMAT_ISO = "iso"
FORMAT_QCOW = "qcow"
FORMAT_QCOW2 = "qcow2"
FORMAT_VMDK = "vmdk"
FORMAT_VDI = "vdi"
USE_SYSTEM = "system"
USE_USER = "user"
USE_SCRATCH = "scratch"
def __init__(self, node=None):
self.id = None
self.file = None
self.format = None
self.size = None
self.use = None
self.csum = {}
if node is not None:
self.parseXML(node)
def parseXML(self, node):
self.file = xpathString(node, "@file")
self.id = xpathString(node, "@id", self.file)
self.format = xpathString(node, "@format", Disk.FORMAT_RAW)
self.size = xpathString(node, "@size")
self.use = xpathString(node, "@use", Disk.USE_SYSTEM)
for d in node.xpathEval("checksum"):
csumtype = xpathString(d, "@type")
csumvalue = xpathString(d, "")
self.csum[csumtype] = csumvalue
formats = [Disk.FORMAT_RAW,
Disk.FORMAT_QCOW,
Disk.FORMAT_QCOW2,
Disk.FORMAT_VMDK,
Disk.FORMAT_ISO,
Disk.FORMAT_VDI]
validate(formats.count(self.format) > 0,
_("The format for disk %s must be one of %s") %
(self.file, ",".join(formats)))
def check_disk_signature(self, meter=None):
try:
import hashlib
sha = None
except:
import sha
hashlib = None
if meter is None:
meter = urlgrabber.progress.BaseMeter()
m = None
if hashlib:
if "sha256" in self.csum:
csumvalue = self.csum["sha256"]
m = hashlib.sha256()
elif "sha1" in self.csum:
csumvalue = self.csum["sha1"]
m = hashlib.sha1()
else:
if "sha1" in self.csum:
csumvalue = self.csum["sha1"]
m = sha.new()
if not m:
return
meter_ct = 0
disk_size = os.path.getsize(self.file)
meter.start(size=disk_size,
text=_("Checking disk signature for %s" % self.file))
f = file(self.file)
while 1:
chunk = f.read(65536)
if not chunk:
break
meter.update(meter_ct)
meter_ct = meter_ct + 65536
m.update(chunk)
checksum = m.hexdigest()
if checksum != csumvalue:
logging.debug(_("Disk signature for %s does not match "
"Expected: %s Received: %s" % (self.file,
csumvalue, checksum)))
raise ValueError(_("Disk signature for %s does not "
"match" % self.file))
def validate(cond, msg):
if not cond:
raise RuntimeError(msg)
def xpathString(node, path, default=None):
result = node.xpathEval("string(%s)" % path)
if len(result) == 0:
result = default
return result
def parse(xml, filename):
"""Parse the XML description of a VM image into a data structure. Returns
an object of class Image. BASE should be the directory where the disk
image files for this image can be found"""
def cb(x):
return Image(x, filename=filename)
return util.parse_node_helper(xml, "image", cb, RuntimeError)
def parse_file(filename):
f = open(filename, "r")
xml = f.read()
f.close()
return parse(xml, filename=filename)
class ImageInstaller(Installer):
"""
Installer for virt-image-based guests
"""
_has_install_phase = False
def __init__(self, conn, image, boot_index=None):
Installer.__init__(self, conn)
self._image = image
# Set boot _boot_caps/_boot_parameters
if boot_index is None:
self._boot_caps = match_boots(self.conn.caps,
self.image.domain.boots)
if self._boot_caps is None:
raise RuntimeError(_("Could not find suitable boot "
"descriptor for this host"))
else:
if (boot_index < 0 or
(boot_index + 1) > len(image.domain.boots)):
raise ValueError(_("boot_index out of range."))
self._boot_caps = image.domain.boots[boot_index]
# Set up internal caps.guest object
self._guest, self._domain = self.conn.caps.guest_lookup(
os_type=self.boot_caps.type, arch=self.boot_caps.arch)
# Custom ImageInstaller methods
def get_caps_guest(self):
return self._guest, self._domain
def get_image(self):
return self._image
image = property(get_image)
def get_boot_caps(self):
return self._boot_caps
boot_caps = property(get_boot_caps)
# General Installer methods
def _prepare(self, guest, meter, scratchdir):
ignore = scratchdir
ignore = meter
self._make_disks()
for f in ['pae', 'acpi', 'apic']:
if self.boot_caps.features[f] & CapabilitiesParser.FEATURE_ON:
setattr(guest.features, f, True)
elif self.boot_caps.features[f] & CapabilitiesParser.FEATURE_OFF:
setattr(guest.features, f, False)
guest.os.kernel = self.boot_caps.kernel
guest.os.initrd = self.boot_caps.initrd
guest.os.kernel_args = self.boot_caps.cmdline
# Private methods
def _get_bootdev(self, isinstall, guest):
return self.boot_caps.bootdev
def _make_disks(self):
for drive in self.boot_caps.drives:
path = self.image.abspath(drive.disk.file)
size = None
if drive.disk.size is not None:
size = float(drive.disk.size) / 1024
# FIXME: This is awkward; the image should be able to express
# whether the disk is expected to be there or not independently
# of its classification, especially for user disks
# FIXME: We ignore the target for the mapping in m.target
if (drive.disk.use == Disk.USE_SYSTEM and
not os.path.exists(path)):
raise RuntimeError(_("System disk %s does not exist") % path)
device = VirtualDisk.DEVICE_DISK
if drive.disk.format == Disk.FORMAT_ISO:
device = VirtualDisk.DEVICE_CDROM
disk = VirtualDisk(self.conn)
disk.path = path
disk.device = device
disk.target = drive.target
disk.set_create_storage(size=size, fmt=drive.disk.format)
disk.validate()
self.install_devices.append(disk)
def match_boots(capabilities, boots):
for b in boots:
for g in capabilities.guests:
if b.type == g.os_type and b.arch == g.arch:
found = True
for bf in b.features.names():
if not b.features[bf] & g.features[bf]:
found = False
break
if found:
return b
return None