2013-03-18 05:06:52 +08:00
|
|
|
#!/usr/bin/python -tt
|
|
|
|
#
|
|
|
|
# Create a virtual machine from an XML image description
|
|
|
|
#
|
|
|
|
# Copyright 2007 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 sys
|
|
|
|
import urlgrabber.progress as progress
|
|
|
|
|
|
|
|
import virtinst.cli as cli
|
|
|
|
from virtinst.cli import fail, print_stdout, print_stderr
|
2013-08-09 09:00:37 +08:00
|
|
|
from virtinst import virtimage
|
2013-03-18 05:06:52 +08:00
|
|
|
|
|
|
|
import optparse
|
|
|
|
from optparse import OptionGroup
|
|
|
|
|
|
|
|
|
|
|
|
### General input gathering functions
|
|
|
|
|
|
|
|
def get_networks(domain, guest, options):
|
|
|
|
nnics = domain.interface
|
|
|
|
networks, macs = cli.digest_networks(guest, options, numnics=nnics)
|
|
|
|
|
|
|
|
if nnics > len(networks):
|
|
|
|
fail(_("The image requires %i network interface.") % nnics)
|
|
|
|
|
|
|
|
cli.get_networks(guest, networks, macs)
|
|
|
|
|
2013-04-14 02:34:52 +08:00
|
|
|
|
2013-03-18 05:06:52 +08:00
|
|
|
def get_graphics(image, guest, options):
|
|
|
|
graphics = cli.digest_graphics(guest, options,
|
|
|
|
default_override=bool(image.graphics))
|
|
|
|
cli.get_graphics(guest, graphics)
|
|
|
|
|
|
|
|
### Option parsing
|
2013-04-14 02:34:52 +08:00
|
|
|
|
|
|
|
|
2013-03-18 05:06:52 +08:00
|
|
|
def parse_args():
|
2013-07-01 03:03:53 +08:00
|
|
|
parser = cli.setupParser(
|
|
|
|
"%prog image.xml [OPTIONS]",
|
|
|
|
_("Create a virtual machine from a virt-image(5) image descriptor."))
|
2013-03-18 05:06:52 +08:00
|
|
|
cli.add_connect_option(parser)
|
|
|
|
|
|
|
|
geng = OptionGroup(parser, _("General Options"))
|
|
|
|
geng.add_option("-n", "--name", dest="name",
|
|
|
|
help=_("Name of the guest instance"))
|
|
|
|
geng.add_option("-r", "--ram", type="int", dest="memory",
|
|
|
|
help=_("Memory to allocate for guest instance in "
|
|
|
|
"megabytes"))
|
|
|
|
geng.add_option("-u", "--uuid", dest="uuid",
|
|
|
|
help=_("UUID for the guest."))
|
|
|
|
cli.vcpu_cli_options(geng)
|
|
|
|
geng.add_option("", "--os-type", dest="distro_type",
|
|
|
|
help=_("The OS type being installed, e.g. "
|
|
|
|
"'linux', 'unix', 'windows'"))
|
|
|
|
geng.add_option("", "--os-variant", dest="distro_variant",
|
|
|
|
help=_("The OS variant being installed, "
|
|
|
|
"e.g. 'fedora6', 'rhel5', 'solaris10', 'win2k'"))
|
|
|
|
parser.add_option_group(geng)
|
|
|
|
|
|
|
|
fulg = OptionGroup(parser, _("Full Virtualization specific options"))
|
|
|
|
fulg.add_option("", "--noapic", action="store_true", dest="noapic",
|
|
|
|
default=False,
|
|
|
|
help=_("Disables APIC for fully virtualized guest"))
|
|
|
|
fulg.add_option("", "--noacpi", action="store_true", dest="noacpi",
|
|
|
|
default=False,
|
|
|
|
help=_("Disables ACPI for fully virtualized guest"))
|
|
|
|
parser.add_option_group(fulg)
|
|
|
|
|
|
|
|
netg = cli.network_option_group(parser)
|
|
|
|
parser.add_option_group(netg)
|
|
|
|
|
|
|
|
vncg = cli.graphics_option_group(parser)
|
|
|
|
parser.add_option_group(vncg)
|
|
|
|
|
|
|
|
misc = OptionGroup(parser, _("Miscellaneous Options"))
|
|
|
|
misc.add_option("-p", "--print", action="store_true", dest="print_only",
|
|
|
|
help=_("Print the libvirt XML, but do not start the "
|
|
|
|
"domain"))
|
|
|
|
misc.add_option("", "--boot", type="int", dest="boot",
|
|
|
|
help=_("The zero-based index of the boot record to use"))
|
|
|
|
misc.add_option("", "--replace", action="store_true", dest="replace",
|
|
|
|
default=False,
|
|
|
|
help=_("Overwrite, or destroy, an existing image with "
|
|
|
|
"the same name"))
|
|
|
|
misc.add_option("", "--noreboot", action="store_true", dest="noreboot",
|
|
|
|
help=_("Don't boot guest after completing install."))
|
|
|
|
misc.add_option("", "--skip-checksum", action="store_true",
|
|
|
|
dest="skipchecksum",
|
|
|
|
help=_("Skip disk checksum verification process"))
|
|
|
|
misc.add_option("-d", "--debug", action="store_true", dest="debug",
|
|
|
|
help=_("Print debugging information"))
|
|
|
|
misc.add_option("", "--prompt", action="store_true", dest="prompt",
|
|
|
|
default=False,
|
|
|
|
help=optparse.SUPPRESS_HELP)
|
|
|
|
misc.add_option("", "--force", action="store_true", dest="force",
|
|
|
|
default=False,
|
|
|
|
help=optparse.SUPPRESS_HELP)
|
|
|
|
misc.add_option("-q", "--quiet", action="store_true", dest="quiet",
|
|
|
|
help=_("Suppress non-error output"))
|
|
|
|
parser.add_option_group(misc)
|
|
|
|
|
|
|
|
(options, args) = parser.parse_args()
|
|
|
|
|
|
|
|
if len(args) < 1:
|
|
|
|
parser.error(_("You need to provide an image XML descriptor"))
|
|
|
|
options.image = args[0]
|
|
|
|
|
|
|
|
return options
|
|
|
|
|
2013-04-14 02:34:52 +08:00
|
|
|
|
2013-03-18 05:06:52 +08:00
|
|
|
def main(conn=None):
|
|
|
|
cli.earlyLogging()
|
|
|
|
options = parse_args()
|
|
|
|
|
|
|
|
options.quiet = options.print_only or options.quiet
|
|
|
|
cli.setupLogging("virt-image", options.debug, options.quiet)
|
|
|
|
cli.set_prompt(False)
|
|
|
|
|
|
|
|
if conn is None:
|
|
|
|
conn = cli.getConnection(options.connect)
|
|
|
|
|
|
|
|
try:
|
2013-08-09 09:00:37 +08:00
|
|
|
image = virtimage.parse_file(options.image)
|
2013-07-07 02:12:13 +08:00
|
|
|
except RuntimeError, msg:
|
2013-04-14 02:34:52 +08:00
|
|
|
fail("%s '%s': %s" % (_("Cannot parse"), options.image, msg))
|
2013-03-18 05:06:52 +08:00
|
|
|
|
|
|
|
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
|
2013-08-09 09:00:37 +08:00
|
|
|
installer = virtimage.ImageInstaller(conn, image, boot_index=options.boot)
|
2013-07-17 19:53:47 +08:00
|
|
|
guest = conn.caps.build_virtinst_guest(conn, *installer.get_caps_guest())
|
|
|
|
guest.installer = installer
|
2013-03-18 05:06:52 +08:00
|
|
|
|
|
|
|
# now let's get some of the common questions out of the way
|
|
|
|
guest.replace = options.replace
|
|
|
|
cli.get_name(options.name, guest, image.name)
|
|
|
|
cli.get_memory(options.memory, guest, image.domain.memory)
|
|
|
|
cli.get_uuid(options.uuid, guest)
|
|
|
|
cli.get_vcpus(guest, options.vcpus, options.check_cpu, image.domain.vcpu)
|
|
|
|
cli.get_cpuset(guest, options.cpuset, guest.memory)
|
|
|
|
cli.parse_cpu(guest, options.cpu)
|
|
|
|
get_networks(image.domain, guest, options)
|
|
|
|
|
|
|
|
get_graphics(image.domain, guest, options)
|
|
|
|
cli.get_video(guest)
|
|
|
|
|
|
|
|
cli.set_os_variant(guest, options.distro_type, options.distro_variant)
|
|
|
|
|
2013-07-17 19:53:47 +08:00
|
|
|
if guest.os.is_hvm():
|
2013-03-18 05:06:52 +08:00
|
|
|
if options.noacpi:
|
|
|
|
guest.features["acpi"] = False
|
|
|
|
if options.noapic:
|
|
|
|
guest.features["apic"] = False
|
|
|
|
|
2013-07-17 03:59:27 +08:00
|
|
|
if not guest.get_devices("input"):
|
|
|
|
guest.add_default_input_device()
|
|
|
|
if not guest.get_devices("console") and not guest.get_devices("serial"):
|
|
|
|
guest.add_default_console_device()
|
2013-03-18 05:06:52 +08:00
|
|
|
|
|
|
|
# we've got everything -- try to start the install
|
|
|
|
if options.print_only:
|
|
|
|
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.skipchecksum:
|
|
|
|
for disk in image.storage.values():
|
|
|
|
disk.check_disk_signature(meter=meter)
|
|
|
|
|
|
|
|
try:
|
|
|
|
print_stdout("\n")
|
|
|
|
print_stdout(_("Creating guest %s...") % guest.name)
|
|
|
|
|
2013-08-09 23:25:05 +08:00
|
|
|
guest.start_install(meter=meter, noboot=options.noreboot)
|
2013-03-18 05:06:52 +08:00
|
|
|
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)
|