cli: Make option handling more consistent

This commit is contained in:
Cole Robinson 2013-09-27 16:52:41 -04:00
parent a900ca14e3
commit 6013622da4
3 changed files with 123 additions and 237 deletions

View File

@ -20,44 +20,24 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
import optparse
import sys
import urlgrabber.progress as progress
import virtinst.cli as cli
from virtinst.cli import fail, print_stdout, print_stderr
from virtinst import virtimage
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)
def get_graphics(image, guest, options):
graphics = cli.digest_graphics(guest, options,
default_override=bool(image.graphics))
cli.get_graphics(guest, graphics)
### 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 = OptionGroup(parser, _("General Options"))
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",
@ -69,7 +49,8 @@ def parse_args():
cli.add_distro_options(geng)
parser.add_option_group(geng)
fulg = OptionGroup(parser, _("Full Virtualization specific options"))
fulg = optparse.OptionGroup(parser,
_("Full Virtualization specific options"))
fulg.add_option("", "--noapic", action="store_true", dest="noapic",
default=False,
help=_("Disables APIC for fully virtualized guest"))
@ -84,7 +65,7 @@ def parse_args():
vncg = cli.graphics_option_group(parser)
parser.add_option_group(vncg)
misc = OptionGroup(parser, _("Miscellaneous Options"))
misc = optparse.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"))
@ -150,18 +131,21 @@ def main(conn=None):
# 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.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)
get_networks(image.domain, guest, options)
cli.set_os_variant(guest, options.distro_type, options.distro_variant)
get_graphics(image.domain, guest, options)
cli.get_networks(guest, options, numnics=image.domain.interface)
cli.get_graphics(guest, options,
default_override=bool(image.domain.graphics))
cli.get_video(guest)
cli.set_os_variant(guest, options.distro_type, options.distro_variant)
if guest.os.is_hvm():
if options.noacpi:

View File

@ -117,39 +117,6 @@ def check_cdrom_option_error(options):
# Device validation wrappers #
##############################
def get_graphics(guest, options):
graphics = cli.digest_graphics(guest, options)
cli.get_graphics(guest, graphics)
def get_chardevs(char_type, opts, guest, cb):
for optstr in cli.listify(opts):
try:
dev = cb(guest, optstr)
guest.add_device(dev)
except Exception, e:
fail(_("Error in %(chartype)s device parameters: %(err)s") %
{"chartype": char_type, "err": str(e)})
def get_watchdog(watchdogs, guest):
for optstr in cli.listify(watchdogs):
try:
dev = cli.parse_watchdog(guest, optstr)
guest.add_device(dev)
except Exception, e:
fail(_("Error in watchdog device parameters: %s") % str(e))
def get_filesystems(filesystems, guest):
for optstr in cli.listify(filesystems):
try:
dev = cli.parse_filesystem(guest, optstr)
guest.add_device(dev)
except Exception, e:
fail(_("Error in filesystem device parameters: %s") % str(e))
def get_disk(diskopts, size, sparse, guest, is_file_path):
try:
dev = None
@ -188,11 +155,6 @@ def get_disks(guest, file_paths, disk_paths, size, sparse, need_storage):
get_disk(disklist[idx], sizelist[idx], sparse, guest, is_file_path)
def get_networks(guest, options):
networks, macs = cli.digest_networks(guest, options)
cli.get_networks(guest, networks, macs)
########################
# Virt type validation #
########################
@ -493,7 +455,7 @@ def build_guest_instance(conn, options):
guest.installer = build_installer(options, conn, guest.os.os_type)
# Guest configuration
cli.get_uuid(options.uuid, guest)
cli.get_uuid(guest, options.uuid)
cli.get_vcpus(guest, options.vcpus, options.check_cpu)
cli.parse_numatune(guest, options.numatune)
cli.parse_cpu(guest, options.cpu)
@ -504,23 +466,21 @@ def build_guest_instance(conn, options):
guest.features.acpi = not options.noacpi
guest.features.apic = not options.noapic
# Non-default devices
cli.get_controller(guest, options.controller)
cli.get_redirdev(guest, options.redirdev)
cli.get_memballoon(guest, options.memballoon)
if not options.nonetworks:
get_networks(guest, options)
get_graphics(guest, options)
cli.get_networks(guest, options, not options.nonetworks and 1 or 0)
cli.get_graphics(guest, options)
cli.get_video(guest, options.video)
get_watchdog(options.watchdog, guest)
get_filesystems(options.filesystems, guest)
cli.get_sound(options.sound, options.soundhw, guest)
get_chardevs("serial", options.serials, guest, cli.parse_serial)
get_chardevs("parallel", options.parallels, guest, cli.parse_parallel)
get_chardevs("channel", options.channels, guest, cli.parse_channel)
get_chardevs("console", options.consoles, guest, cli.parse_console)
cli.get_hostdevs(options.hostdevs, guest)
cli.get_watchdog(guest, options.watchdog)
cli.get_filesystems(guest, options.filesystems)
cli.get_sound(guest, options.sound, options.oldsound)
cli.get_serials(guest, options.serials)
cli.get_parallels(guest, options.parallels)
cli.get_channels(guest, options.channels)
cli.get_consoles(guest, options.consoles)
cli.get_hostdevs(guest, options.hostdevs)
cli.get_smartcard(guest, options.smartcard)
cli.get_tpm(guest, options.tpm)
cli.get_rng(guest, options.rng)
@ -541,8 +501,11 @@ def build_guest_instance(conn, options):
need_storage, need_install = validate_required_options(options, guest)
# Actually set required options
cli.get_name(options.name, guest)
cli.get_memory(options.memory, guest)
cli.get_name(guest, options.name)
cli.get_memory(guest, options.memory)
# Needs to come after setting memory
cli.get_cpuset(guest, options.cpuset)
if not options.nodisks:
get_disks(guest, options.file_paths, options.diskopts,
options.disksize, options.sparse, need_storage)
@ -552,9 +515,6 @@ def build_guest_instance(conn, options):
# this after setting guest.installer at least
check_option_collisions(options, guest)
# Needs to come after setting memory
cli.get_cpuset(guest, options.cpuset, guest.memory)
# Warnings
if options.pxe and not supports_pxe(guest):
logging.warn(_("The guest's network configuration does not support "
@ -970,9 +930,8 @@ def parse_args():
cli.add_device_options(devg)
# Deprecated
devg.add_option("", "--sound", action="store_true", dest="sound",
default=False,
help=optparse.SUPPRESS_HELP)
devg.add_option("", "--sound", action="store_true", dest="oldsound",
default=False, help=optparse.SUPPRESS_HELP)
parser.add_option_group(devg)
virg = optparse.OptionGroup(parser, _("Virtualization Platform Options"))

View File

@ -578,16 +578,13 @@ name_missing = _("--name is required")
ram_missing = _("--ram amount in MB is required")
def get_name(name, guest, image_name=None):
def get_name(guest, name):
prompt_txt = _("What is the name of your virtual machine?")
err_txt = name_missing
if name is None:
name = image_name
prompt_loop(prompt_txt, err_txt, name, guest, "name")
def get_memory(memory, guest, image_memory=None):
def get_memory(guest, memory):
prompt_txt = _("How much RAM should be allocated (in megabytes)?")
err_txt = ram_missing
@ -598,51 +595,42 @@ def get_memory(memory, guest, image_memory=None):
"of RAM.") % MIN_RAM)
guest.memory = mem * 1024
if memory is None and image_memory is not None:
memory = int(image_memory)
prompt_loop(prompt_txt, err_txt, memory, guest, "memory",
func=check_memory)
def get_uuid(uuid, guest):
if uuid:
try:
guest.uuid = uuid
except ValueError, e:
fail(e)
def get_uuid(guest, uuid):
if not uuid:
return
try:
guest.uuid = uuid
except ValueError, e:
fail(e)
def get_vcpus(guest, vcpus, check_cpu, image_vcpus=None):
"""
@param vcpus: value of the option '--vcpus' (str or None)
@param check_cpu: Whether to check that the number virtual cpus requested
does not exceed physical CPUs (bool)
@param guest: virtinst.Guest instance (object)
@param image_vcpus: ? (It's not used currently and should be None.)
"""
def get_vcpus(guest, vcpus, check_cpu):
if vcpus is None:
if image_vcpus is not None:
vcpus = image_vcpus
else:
vcpus = ""
vcpus = ""
parse_vcpu(guest, vcpus, image_vcpus)
parse_vcpu(guest, vcpus)
if not check_cpu:
return
if check_cpu:
hostinfo = guest.conn.getInfo()
pcpus = hostinfo[4] * hostinfo[5] * hostinfo[6] * hostinfo[7]
hostinfo = guest.conn.getInfo()
pcpus = hostinfo[4] * hostinfo[5] * hostinfo[6] * hostinfo[7]
if guest.vcpus > pcpus:
msg = _("You have asked for more virtual CPUs (%d) than there "
"are physical CPUs (%d) on the host. This will work, "
"but performance will be poor. ") % (guest.vcpus, pcpus)
askmsg = _("Are you sure? (yes or no)")
if guest.vcpus > pcpus:
msg = _("You have asked for more virtual CPUs (%d) than there "
"are physical CPUs (%d) on the host. This will work, "
"but performance will be poor. ") % (guest.vcpus, pcpus)
askmsg = _("Are you sure? (yes or no)")
if not prompt_for_yes_or_no(msg, askmsg):
nice_exit()
if not prompt_for_yes_or_no(msg, askmsg):
nice_exit()
def get_cpuset(guest, cpuset, memory):
def get_cpuset(guest, cpuset):
memory = guest.memory
conn = guest.conn
if cpuset and cpuset != "auto":
guest.cpuset = cpuset
@ -672,7 +660,7 @@ def _default_network_opts(guest):
return opts
def digest_networks(guest, options, numnics=1):
def _digest_networks(guest, options, numnics):
macs = listify(options.mac)
networks = listify(options.network)
bridges = listify(options.bridge)
@ -700,7 +688,9 @@ def digest_networks(guest, options, numnics=1):
return networks, macs
def get_networks(guest, networks, macs):
def get_networks(guest, options, numnics):
networks, macs = _digest_networks(guest, options, numnics)
for idx in range(len(networks)):
mac = macs[idx]
netstr = networks[idx]
@ -730,7 +720,7 @@ def set_os_variant(obj, distro_type, distro_variant):
obj.os_variant = distkey
def digest_graphics(guest, options, default_override=None):
def _digest_graphics(guest, options, default_override):
vnc = options.vnc
vncport = options.vncport
vnclisten = options.vnclisten
@ -762,7 +752,8 @@ def digest_graphics(guest, options, default_override=None):
logging.debug("Container guest, defaulting to nographics")
nographics = True
elif "DISPLAY" in os.environ.keys():
logging.debug("DISPLAY is set: looking for pre-configured graphics")
logging.debug("DISPLAY is set: looking for "
"pre-configured graphics")
if cliconfig.default_graphics in ["spice", "vnc", "sdl"]:
logging.debug("Defaulting graphics to pre-configured %s",
cliconfig.default_graphics.upper())
@ -790,7 +781,9 @@ def digest_graphics(guest, options, default_override=None):
return [optstr]
def get_graphics(guest, graphics):
def get_graphics(guest, options, default_override=None):
graphics = _digest_graphics(guest, options, default_override)
for optstr in graphics:
try:
dev = parse_graphics(guest, optstr)
@ -802,100 +795,24 @@ def get_graphics(guest, graphics):
def get_video(guest, video_models=None):
video_models = video_models or []
if guest.get_devices(VirtualGraphics.VIRTUAL_DEV_GRAPHICS):
if not video_models:
video_models.append(None)
video_models = [None]
for model in video_models:
for model in listify(video_models):
guest.add_device(parse_video(guest, model))
def get_sound(old_sound_bool, sound_opts, guest):
if not sound_opts:
def get_sound(guest, sounds, old_sound_bool):
if not sounds:
if old_sound_bool:
guest.add_device(VirtualAudio(guest.conn))
return
for opts in listify(sound_opts):
for opts in listify(sounds):
guest.add_device(parse_sound(guest, opts))
def get_hostdevs(hostdevs, guest):
if not hostdevs:
return
for devname in hostdevs:
guest.add_device(parse_hostdev(guest, devname))
def get_smartcard(guest, sc_opts):
for sc in listify(sc_opts):
try:
dev = parse_smartcard(guest, sc)
except Exception, e:
fail(_("Error in smartcard device parameters: %s") % str(e))
if dev:
guest.add_device(dev)
def get_tpm(guest, tpm_opts):
for tpm in listify(tpm_opts):
try:
dev = parse_tpm(guest, tpm)
except Exception, e:
fail(_("Error in TPM device parameters: %s") % str(e))
if dev:
guest.add_device(dev)
def get_rng(guest, rng_opts):
for rng in listify(rng_opts):
try:
dev = parse_rng(guest, rng)
except Exception, e:
fail(_("Error in RNG device parameters: %s") % str(e))
if dev:
guest.add_device(dev)
def get_controller(guest, sc_opts):
for sc in listify(sc_opts):
try:
dev = parse_controller(guest, sc)
except Exception, e:
fail(_("Error in controller device parameters: %s") % str(e))
if dev:
guest.add_device(dev)
def get_redirdev(guest, sc_opts):
for sc in listify(sc_opts):
try:
dev = parse_redirdev(guest, sc)
except Exception, e:
fail(_("Error in redirdev device parameters: %s") % str(e))
if dev:
guest.add_device(dev)
def get_memballoon(guest, sc_opts):
for sc in listify(sc_opts):
try:
dev = parse_memballoon(guest, sc)
except Exception, e:
fail(_("Error in memballoon device parameters: %s") % str(e))
if dev:
guest.add_device(dev)
#############################
# Common CLI option/group #
#############################
@ -985,7 +902,7 @@ def add_device_options(devg):
devg.add_option("", "--host-device", dest="hostdevs", action="append",
help=_("Configure physical host devices attached to the "
"guest"))
devg.add_option("", "--soundhw", dest="soundhw", action="append",
devg.add_option("", "--soundhw", dest="sound", action="append",
help=_("Configure guest sound device emulation"))
devg.add_option("", "--watchdog", dest="watchdog", action="append",
help=_("Configure a guest watchdog device"))
@ -1041,6 +958,24 @@ def add_distro_options(g):
# (for options like --disk, --network, etc. #
#############################################
def _handle_dev_opts(devtype, cb, guest, opts):
for optstr in listify(opts):
try:
dev = cb(guest, optstr)
if dev:
guest.add_device(dev)
except Exception, e:
logging.debug("Exception parsing devtype=%s optstr=%s",
devtype, optstr, exc_info=True)
fail(_("Error in %(devtype)s device parameters: %(err)s") %
{"devtype": devtype, "err": str(e)})
def _make_handler(devtype, parsefunc):
return lambda *args, **kwargs: _handle_dev_opts(devtype, parsefunc,
*args, **kwargs)
def get_opt_param(opts, dictnames, val=None):
if type(dictnames) is not list:
dictnames = [dictnames]
@ -1160,19 +1095,18 @@ def parse_numatune(guest, optstring):
# --vcpu parsing #
##################
def parse_vcpu(guest, optstring, default_vcpus=None):
def parse_vcpu(guest, optstring):
"""
Helper to parse --vcpu string
@param guest: virtinst.Guest instance (object)
@param optstring: value of the option '--vcpus' (str)
@param default_vcpus: ? (it should be None at present.)
"""
if not optstring:
return
opts = parse_optstr(optstring, remove_first="vcpus")
vcpus = opts.get("vcpus") or default_vcpus
vcpus = opts.get("vcpus")
if vcpus is not None:
opts["vcpus"] = vcpus
@ -1567,9 +1501,6 @@ def parse_network(guest, optstring, dev=None, mac=None):
######################
def parse_graphics(guest, optstring, dev=None):
if optstring is None:
return None
def sanitize_keymap(keymap):
from virtinst import hostkeymap
@ -1622,9 +1553,6 @@ def parse_graphics(guest, optstring, dev=None):
########################
def parse_controller(guest, optstring, dev=None):
if optstring is None:
return None
if optstring == "usb2":
for dev in virtinst.VirtualController.get_usb2_controllers(guest.conn):
guest.add_device(dev)
@ -1651,6 +1579,8 @@ def parse_controller(guest, optstring, dev=None):
return dev
get_controller = _make_handler("controller", parse_controller)
#######################
# --smartcard parsing #
@ -1678,15 +1608,14 @@ def parse_smartcard(guest, optstring, dev=None):
return dev
get_smartcard = _make_handler("smartcard", parse_smartcard)
######################
# --redirdev parsing #
######################
def parse_redirdev(guest, optstring, dev=None):
if optstring is None:
return None
# Peel the mode off the front
opts = parse_optstr(optstring, remove_first="bus")
server = get_opt_param(opts, "server")
@ -1717,15 +1646,14 @@ def parse_redirdev(guest, optstring, dev=None):
return dev
get_redirdev = _make_handler("redirdev", parse_redirdev)
#################
# --tpm parsing #
#################
def parse_tpm(guest, optstring, dev=None):
if optstring is None:
return None
# Peel the type off the front
opts = parse_optstr(optstring, remove_first="type")
if opts.get("type") == "none":
@ -1745,11 +1673,14 @@ def parse_tpm(guest, optstring, dev=None):
return dev
get_tpm = _make_handler("tpm", parse_tpm)
#################
# --rng parsing #
#################
def parse_rng(guest, optstring, dev=None):
if optstring is None:
return None
opts = parse_optstr(optstring, remove_first="type")
dev_type = opts.get("type")
if dev_type == "none":
@ -1778,6 +1709,8 @@ def parse_rng(guest, optstring, dev=None):
return dev
get_rng = _make_handler("rng", parse_rng)
######################
# --watchdog parsing #
@ -1805,15 +1738,14 @@ def parse_watchdog(guest, optstring, dev=None):
return dev
get_watchdog = _make_handler("watchdog", parse_watchdog)
########################
# --memballoon parsing #
########################
def parse_memballoon(guest, optstring, dev=None):
if optstring is None:
return None
# Peel the mode off the front
opts = parse_optstr(optstring, remove_first="model")
@ -1826,6 +1758,8 @@ def parse_memballoon(guest, optstring, dev=None):
return dev
get_memballoon = _make_handler("memballoon", parse_memballoon)
######################################################
# --serial, --parallel, --channel, --console parsing #
@ -1907,6 +1841,11 @@ def _parse_char(optstring, dev_type, dev=None):
return dev
get_serials = _make_handler("serial", parse_serial)
get_parallels = _make_handler("parallel", parse_parallel)
get_channels = _make_handler("channel", parse_channel)
get_consoles = _make_handler("console", parse_console)
########################
# --filesystem parsing #
@ -1954,6 +1893,8 @@ def parse_video(guest, optstr, dev=None):
raise ValueError(_("Unknown options %s") % opts.keys())
return dev
get_filesystems = _make_handler("filesystem", parse_filesystem)
#####################
# --soundhw parsing #
@ -1981,3 +1922,5 @@ def parse_hostdev(guest, optstr, dev=None):
return virtinst.VirtualHostDevice.device_from_node(guest.conn,
name=optstr,
dev=dev)
get_hostdevs = _make_handler("hostdev", parse_hostdev)