cli: Centralize most option handling dispatch

Rather than require tools to do multiple parse_* calls. This infrastructure
will help with virt-xml as well.
This commit is contained in:
Cole Robinson 2014-01-21 14:28:47 -05:00
parent 269339f29f
commit 54b73f4502
3 changed files with 90 additions and 100 deletions

View File

@ -75,6 +75,7 @@ def main(conn=None):
options.quiet = options.xmlonly or options.quiet
cli.setupLogging("virt-image", options.debug, options.quiet)
cli.set_prompt(False)
if conn is None:
conn = cli.getConnection(options.connect)
@ -100,21 +101,23 @@ def main(conn=None):
cli.convert_old_graphics(guest, options,
default_override=bool(image.domain.graphics))
cli.convert_old_features(options)
if not options.vcpus:
options.vcpus = image.domain.vcpu or ""
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)))
if options.uuid:
guest.uuid = options.uuid
cli.parse_vcpus(guest, options.vcpus or image.domain.vcpu or "")
cli.get_cpuset(guest, options.cpuset)
cli.parse_cpu(guest, options.cpu)
cli.parse_network(guest, options.network)
cli.parse_graphics(guest, options.graphics)
cli.set_os_variant(guest, options.distro_type, options.distro_variant)
cli.parse_features(guest, getattr(options, "features", None))
parsermap = cli.build_parser_map(options,
only=["vcpus", "cpu", "network", "graphics", "features"])
cli.parse_option_strings(parsermap, options, guest, None)
cli.get_cpuset(guest, options.cpuset)
if not guest.get_devices("input"):
guest.add_default_input_device()

View File

@ -506,35 +506,10 @@ def build_guest_instance(conn, options):
guest.os.init = options.init
if options.uuid:
guest.uuid = options.uuid
cli.parse_vcpus(guest, options.vcpus)
cli.parse_numatune(guest, options.numatune)
cli.parse_cpu(guest, options.cpu)
cli.parse_security(guest, options.security)
cli.parse_boot(guest, options.boot)
cli.parse_features(guest, options.features)
cli.parse_clock(guest, options.clock)
guest.description = options.description
# Non-default devices
cli.parse_controller(guest, options.controller)
cli.parse_redirdev(guest, options.redirdev)
cli.parse_memballoon(guest, options.memballoon)
cli.parse_network(guest, options.network)
cli.parse_graphics(guest, options.graphics)
cli.parse_video(guest, options.video)
cli.parse_watchdog(guest, options.watchdog)
cli.parse_filesystem(guest, options.filesystem)
cli.parse_sound(guest, options.soundhw)
cli.parse_serial(guest, options.serial)
cli.parse_parallel(guest, options.parallel)
cli.parse_channel(guest, options.channel)
cli.parse_console(guest, options.console)
cli.parse_hostdev(guest, options.host_device)
cli.parse_smartcard(guest, options.smartcard)
cli.parse_tpm(guest, options.tpm)
cli.parse_rng(guest, options.rng)
cli.parse_panic(guest, options.panic)
parsermap = cli.build_parser_map(options, skip=["disk"])
cli.parse_option_strings(parsermap, options, guest, None)
guest.add_default_input_device()
guest.add_default_console_device()

View File

@ -1096,10 +1096,12 @@ class VirtCLIParser(object):
"""
devclass = None
def __init__(self):
def __init__(self, cli_arg_name):
"""
These values should be set by subclasses in _init_params
@cli_arg_name: The command line argument this maps to, so
"host-device" for --host-device
@guest: Will be set parse(), the toplevel virtinst.Guest object
@remove_first: Passed to VirtOptionString
@check_none: If the parsed option string is just 'none', return None
@ -1107,6 +1109,11 @@ class VirtCLIParser(object):
Called before the virtinst object is altered. Take arguments
(inst, attrname, cliname)
"""
self.cli_arg_name = cli_arg_name
# This is the name of the variable that argparse will set in
# the result of parse_args()
self.option_variable_name = cli_arg_name.replace("-", "_")
self.guest = None
self.remove_first = None
self.check_none = False
@ -1125,13 +1132,12 @@ class VirtCLIParser(object):
self._params.append(_VirtCLIArgument(*args, **kwargs))
def parse(self, guest, optlist, inst=None, validate=True):
# XXX: review
optlist = util.listify(optlist)
editting = bool(inst)
if editting and optlist:
# If an object is passed in, we are updating it in place, and
# only use the last command line occurence
# only use the last command line occurence, eg. from virt-xml
optlist = [optlist[-1]]
ret = []
@ -1156,8 +1162,9 @@ class VirtCLIParser(object):
except Exception, e:
logging.debug("Exception parsing inst=%s optstr=%s",
inst, optstr, exc_info=True)
fail(_("Error in %(options)s: %(err)s") %
{"options": optstr, "err": str(e)})
fail(_("Error: --%(cli_arg_name)s %(options)s: %(err)s") %
{"cli_arg_name": self.cli_arg_name,
"options": optstr, "err": str(e)})
if not ret:
return None
@ -1207,8 +1214,6 @@ class ParserNumatune(VirtCLIParser):
self.set_param("numatune.memory_nodeset", "nodeset", can_comma=True)
self.set_param("numatune.memory_mode", "mode")
parse_numatune = ParserNumatune().parse
##################
# --vcpu parsing #
@ -1241,8 +1246,6 @@ class ParserVCPU(VirtCLIParser):
inst.vcpus = inst.cpu.vcpus_from_topology()
return ret
parse_vcpus = ParserVCPU().parse
#################
# --cpu parsing #
@ -1299,9 +1302,6 @@ class ParserCPU(VirtCLIParser):
return VirtCLIParser._parse(self, optsobj, inst)
parse_cpu = ParserCPU().parse
##################
# --boot parsing #
##################
@ -1339,8 +1339,6 @@ class ParserBoot(VirtCLIParser):
VirtCLIParser._parse(self, opts, inst)
parse_boot = ParserBoot().parse
######################
# --security parsing #
@ -1354,9 +1352,6 @@ class ParserSecurity(VirtCLIParser):
is_onoff=True)
parse_security = ParserSecurity().parse
######################
# --features parsing #
######################
@ -1383,8 +1378,6 @@ class ParserFeatures(VirtCLIParser):
self.set_param("features.hyperv_spinlocks_retries",
"hyperv_spinlocks_retries")
parse_features = ParserFeatures().parse
###################
# --clock parsing #
@ -1417,9 +1410,6 @@ class ParserClock(VirtCLIParser):
self.set_param(None, tname + "_tickpolicy", setter_cb=set_timer)
parse_clock = ParserClock().parse
##########################
# Guest <device> parsing #
##########################
@ -1561,7 +1551,7 @@ class ParserDisk(VirtCLIParser):
return inst
parse_disk = ParserDisk().parse
parse_disk = ParserDisk("disk").parse
#####################
@ -1602,9 +1592,6 @@ class ParserNetwork(VirtCLIParser):
return VirtCLIParser._parse(self, optsobj, inst)
parse_network = ParserNetwork().parse
######################
# --graphics parsing #
######################
@ -1649,9 +1636,6 @@ class ParserGraphics(VirtCLIParser):
self.set_param("passwdValidTo", "passwordvalidto")
parse_graphics = ParserGraphics().parse
########################
# --controller parsing #
########################
@ -1678,9 +1662,6 @@ class ParserController(VirtCLIParser):
return VirtCLIParser._parse(self, opts, inst)
parse_controller = ParserController().parse
#######################
# --smartcard parsing #
#######################
@ -1695,9 +1676,6 @@ class ParserSmartcard(VirtCLIParser):
self.set_param("type", "type")
parse_smartcard = ParserSmartcard().parse
######################
# --redirdev parsing #
######################
@ -1712,8 +1690,6 @@ class ParserRedir(VirtCLIParser):
self.set_param("type", "type")
self.set_param("parse_friendly_server", "server")
parse_redirdev = ParserRedir().parse
#################
# --tpm parsing #
@ -1735,9 +1711,6 @@ class ParserTPM(VirtCLIParser):
return VirtCLIParser._parse(self, opts, inst)
parse_tpm = ParserTPM().parse
#################
# --rng parsing #
#################
@ -1807,9 +1780,6 @@ class ParserRNG(VirtCLIParser):
return VirtCLIParser._parse(self, optsobj, inst)
parse_rng = ParserRNG().parse
######################
# --watchdog parsing #
######################
@ -1823,9 +1793,6 @@ class ParserWatchdog(VirtCLIParser):
self.set_param("action", "action")
parse_watchdog = ParserWatchdog().parse
########################
# --memballoon parsing #
########################
@ -1838,9 +1805,6 @@ class ParserMemballoon(VirtCLIParser):
self.set_param("model", "model")
parse_memballoon = ParserMemballoon().parse
###################
# --panic parsing #
###################
@ -1859,9 +1823,6 @@ class ParserPanic(VirtCLIParser):
self.set_param(None, "iobase", setter_cb=set_iobase_cb)
parse_panic = ParserPanic().parse
######################################################
# --serial, --parallel, --channel, --console parsing #
######################################################
@ -1904,22 +1865,18 @@ class _ParserChar(VirtCLIParser):
class ParserSerial(_ParserChar):
devclass = virtinst.VirtualSerialDevice
parse_serial = ParserSerial().parse
class ParserParallel(_ParserChar):
devclass = virtinst.VirtualParallelDevice
parse_parallel = ParserParallel().parse
class ParserChannel(_ParserChar):
devclass = virtinst.VirtualChannelDevice
parse_channel = ParserChannel().parse
class ParserConsole(_ParserChar):
devclass = virtinst.VirtualConsoleDevice
parse_console = ParserConsole().parse
########################
@ -1937,9 +1894,6 @@ class ParserFilesystem(VirtCLIParser):
self.set_param("target", "target")
parse_filesystem = ParserFilesystem().parse
###################
# --video parsing #
###################
@ -1952,9 +1906,6 @@ class ParserVideo(VirtCLIParser):
self.set_param("model", "model", ignore_default=True)
parse_video = ParserVideo().parse
#####################
# --soundhw parsing #
#####################
@ -1967,9 +1918,6 @@ class ParserSound(VirtCLIParser):
self.set_param("model", "model", ignore_default=True)
parse_sound = ParserSound().parse
#####################
# --hostdev parsing #
#####################
@ -1989,4 +1937,68 @@ class ParserHostdev(VirtCLIParser):
self.set_param("driver_name", "driver_name")
parse_hostdev = ParserHostdev().parse
###########################
# Register parser classes #
###########################
def build_parser_map(options, skip=None, only=None):
"""
Build a dictionary with mapping of cli-name->parserinstance, so
--vcpus -> ParserVCPU object.
"""
parsermap = {}
def register_parser(cli_arg_name, parserclass):
if cli_arg_name in util.listify(skip):
return
if only and cli_arg_name not in util.listify(only):
return
parserobj = parserclass(cli_arg_name)
if not hasattr(options, parserobj.option_variable_name):
raise RuntimeError("programming error: unknown option=%s "
"cliname=%s class=%s" %
(parserobj.option_variable_name,
parserobj.cli_arg_name, parserclass))
parsermap[parserobj.option_variable_name] = parserobj
register_parser("vcpus", ParserVCPU)
register_parser("cpu", ParserCPU)
register_parser("numatune", ParserNumatune)
register_parser("boot", ParserBoot)
register_parser("security", ParserSecurity)
register_parser("features", ParserFeatures)
register_parser("clock", ParserClock)
register_parser("disk", ParserDisk)
register_parser("network", ParserNetwork)
register_parser("graphics", ParserGraphics)
register_parser("controller", ParserController)
register_parser("smartcard", ParserSmartcard)
register_parser("redirdev", ParserRedir)
register_parser("tpm", ParserTPM)
register_parser("rng", ParserRNG)
register_parser("watchdog", ParserWatchdog)
register_parser("memballoon", ParserMemballoon)
register_parser("serial", ParserSerial)
register_parser("parallel", ParserParallel)
register_parser("channel", ParserChannel)
register_parser("console", ParserConsole)
register_parser("filesystem", ParserFilesystem)
register_parser("video", ParserVideo)
register_parser("soundhw", ParserSound)
register_parser("host-device", ParserHostdev)
register_parser("panic", ParserPanic)
return parsermap
def parse_option_strings(parsermap, options, guest, inst):
"""
Iterate over the parsermap, and launch the associated parser
function for every value that was filled in on 'options', which
came from argparse/the command line.
"""
for option_variable_name in dir(options):
if option_variable_name not in parsermap:
continue
parsermap[option_variable_name].parse(
guest, getattr(options, option_variable_name), inst)