#!/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 optparse
import sys

import urlgrabber.progress as progress

import virtinst
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 image.xml [OPTIONS]",
        _("Create a virtual machine from a virt-image(5) image descriptor."))
    cli.add_connect_option(parser)

    geng = optparse.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)
    cli.add_distro_options(geng)
    cli.add_old_feature_options(geng)
    parser.add_option_group(geng)

    netg = cli.network_option_group(parser)
    parser.add_option_group(netg)

    vncg = cli.graphics_option_group(parser)
    parser.add_option_group(vncg)

    misc = optparse.OptionGroup(parser, _("Miscellaneous Options"))
    misc.add_option("--boot", type="int", dest="boot",
                    help=_("The zero-based index of the boot record to use"))
    misc.add_option("--skip-checksum", action="store_true",
                    dest="skipchecksum",
                    help=_("Skip disk checksum verification process"))

    cli.add_misc_options(misc, prompt=True, replace=True, printxml=True,
                         noreboot=True)
    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


def main(conn=None):
    cli.earlyLogging()
    options = parse_args()

    options.quiet = options.xmlonly or options.quiet
    cli.setupLogging("virt-image", options.debug, options.quiet)

    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_networks(guest, options, image.domain.interface)
    cli.convert_old_graphics(guest, options,
        default_override=bool(image.domain.graphics))
    cli.convert_old_features(options)

    guest.replace = options.replace
    cli.get_name(guest, options.name or image.name)
    cli.get_memory(guest, options.memory or (image.domain.memory and
                                             int(image.domain.memory)))
    cli.get_uuid(guest, options.uuid)
    cli.get_vcpus(guest, options.vcpus or image.domain.vcpu or "",
                  options.check_cpu)
    cli.get_cpuset(guest, options.cpuset)
    cli.parse_cpu(guest, options.cpu)
    cli.get_networks(guest, options.network)
    cli.get_graphics(guest, options.graphics)
    cli.set_os_variant(guest, options.distro_type, options.distro_variant)
    cli.parse_features(guest, getattr(options, "features", None))

    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()
    if not guest.get_devices("video") and guest.get_devices("graphics"):
        guest.add_device(virtinst.VirtualVideoDevice(guest.conn))

    # 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.skipchecksum:
        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)
