summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCole Robinson <crobinso@redhat.com>2016-06-14 07:37:21 -0400
committerCole Robinson <crobinso@redhat.com>2016-06-14 10:51:50 -0400
commit984b3687257a0978db0227a92a9fbb04ae26ae8e (patch)
tree2ce0c15f7123679e58552ac5dcb5ce4720bea618
parent8a0fd7927f88d372e4f461d760c11118b71ff2f1 (diff)
downloadvirt-manager-984b3687257a0978db0227a92a9fbb04ae26ae8e.tar.gz
cli: Rework VirtCLIParser instantiation
Only initialize VirtCLIParser at actual parse time. The data that's passed to __init__ is the particular data for that parse task, like the option string, and the Guest object we are editing. As a result we can drop the whole parsermap handling, since the parserlist is immutable. There's a bunch of other reworks mixed in like dropping the VirtOptionString abstraction...
-rwxr-xr-xvirt-install12
-rwxr-xr-xvirt-xml95
-rw-r--r--virtinst/cli.py783
3 files changed, 443 insertions, 447 deletions
diff --git a/virt-install b/virt-install
index 6d1aa960..0bfe2e52 100755
--- a/virt-install
+++ b/virt-install
@@ -572,7 +572,7 @@ def build_installer(options, conn, virt_type):
return installer
-def build_guest_instance(conn, options, parsermap):
+def build_guest_instance(conn, options):
guest = get_guest(conn, options)
logging.debug("Received virt method '%s'", guest.type)
@@ -603,10 +603,7 @@ def build_guest_instance(conn, options, parsermap):
guest.description = options.description
validate_required_options(options, guest)
-
- # We don't want to auto-parse --disk, but we wanted it for earlier
- # parameter introspection
- cli.parse_option_strings(parsermap, options, guest, None)
+ cli.parse_option_strings(options, guest, None)
# Extra disk validation
for disk in guest.get_devices("disk"):
@@ -1033,8 +1030,7 @@ def main(conn=None):
cli.parse_check(options.check)
cli.set_prompt(options.prompt)
- parsermap = cli.build_parser_map(options)
- if cli.check_option_introspection(options, parsermap):
+ if cli.check_option_introspection(options):
return 0
if conn is None:
@@ -1047,7 +1043,7 @@ def main(conn=None):
if options.xmlonly not in [False, "1", "2", "3", "all"]:
fail(_("--print-step must be 1, 2, 3, or all"))
- guest = build_guest_instance(conn, options, parsermap)
+ guest = build_guest_instance(conn, options)
continue_inst = guest.get_continue_inst()
if options.xmlonly or options.dry:
diff --git a/virt-xml b/virt-xml
index e2b52f6e..74762ab7 100755
--- a/virt-xml
+++ b/virt-xml
@@ -112,8 +112,8 @@ def get_domain_and_guest(conn, domstr):
# Change logic #
################
-def _find_objects_to_edit(guest, action_name, editval, parserobj):
- objlist = guest.list_children_for_class(parserobj.objclass)
+def _find_objects_to_edit(guest, action_name, editval, parserclass):
+ objlist = guest.list_children_for_class(parserclass.objclass)
idx = None
if editval is None:
@@ -129,11 +129,11 @@ def _find_objects_to_edit(guest, action_name, editval, parserobj):
if not objlist:
fail(_("No --%s objects found in the XML") %
- parserobj.cli_arg_name)
+ parserclass.cli_arg_name)
if len(objlist) < abs(idx):
fail(_("--edit %s requested but there's only %s "
"--%s object in the XML") %
- (idx, len(objlist), parserobj.cli_arg_name))
+ (idx, len(objlist), parserclass.cli_arg_name))
if idx > 0:
idx -= 1
@@ -145,7 +145,8 @@ def _find_objects_to_edit(guest, action_name, editval, parserobj):
else:
# Lookup device by the passed prop string
- inst = parserobj.lookup_child_from_option_string(guest, editval)
+ parserobj = parserclass(guest, editval)
+ inst = parserobj.lookup_child_from_option_string()
if not inst:
fail(_("No matching objects found for --%s %s") %
(action_name, editval))
@@ -170,11 +171,11 @@ def check_action_collision(options):
", ".join(["--" + c for c in collisions]))
-def check_xmlopt_collision(options, parsermap):
+def check_xmlopt_collision(options):
collisions = []
- for cli_arg_name, parserobj in parsermap.items():
- if getattr(options, cli_arg_name):
- collisions.append(parserobj)
+ for parserclass in cli.VIRT_PARSERS:
+ if getattr(options, parserclass.cli_arg_name):
+ collisions.append(parserclass)
if len(collisions) == 0:
fail(_("No change specified."))
@@ -186,36 +187,34 @@ def check_xmlopt_collision(options, parsermap):
return collisions[0]
-def action_edit(guest, options, parsermap, parserobj):
- if parserobj.objclass:
- inst = _find_objects_to_edit(guest, "edit", options.edit, parserobj)
+def action_edit(guest, options, parserclass):
+ if parserclass.objclass:
+ inst = _find_objects_to_edit(guest, "edit", options.edit, parserclass)
else:
inst = guest
if options.edit and options.edit != '1' and options.edit != 'all':
fail(_("'--edit %s' doesn't make sense with --%s, "
"just use empty '--edit'") %
- (options.edit, parserobj.cli_arg_name))
+ (options.edit, parserclass.cli_arg_name))
- return cli.parse_option_strings(parsermap, options,
- guest, inst, update=True)
+ return cli.parse_option_strings(options, guest, inst, update=True)
-def action_add_device(guest, options, parsermap, parserobj):
- if (not parserobj.objclass or
- guest.child_class_is_singleton(parserobj.objclass)):
- fail(_("Cannot use --add-device with --%s") % parserobj.cli_arg_name)
- return cli.parse_option_strings(parsermap, options, guest, None)
+def action_add_device(guest, options, parserclass):
+ if (not parserclass.objclass or
+ guest.child_class_is_singleton(parserclass.objclass)):
+ fail(_("Cannot use --add-device with --%s") % parserclass.cli_arg_name)
+ return cli.parse_option_strings(options, guest, None)
-def action_remove_device(guest, options, parsermap, parserobj):
- ignore = parsermap
- if (not parserobj.objclass or
- guest.child_class_is_singleton(parserobj.objclass)):
+def action_remove_device(guest, options, parserclass):
+ if (not parserclass.objclass or
+ guest.child_class_is_singleton(parserclass.objclass)):
fail(_("Cannot use --remove-device with --%s") %
- parserobj.cli_arg_name)
+ parserclass.cli_arg_name)
devs = _find_objects_to_edit(guest, "remove-device",
- getattr(options, parserobj.cli_arg_name)[-1], parserobj)
+ getattr(options, parserclass.cli_arg_name)[-1], parserclass)
devs = util.listify(devs)
for dev in util.listify(devs):
@@ -223,19 +222,20 @@ def action_remove_device(guest, options, parsermap, parserobj):
return devs
-def action_build_xml(conn, options, parsermap, parserobj):
+def action_build_xml(conn, options, parserclass):
guest = virtinst.Guest(conn)
ret_inst = None
inst = None
- if parserobj.objclass:
- inst = parserobj.objclass(conn)
- elif parserobj.clear_attr:
- ret_inst = getattr(guest, parserobj.clear_attr)
+ if parserclass.objclass:
+ inst = parserclass.objclass(conn)
+ elif parserclass.clear_attr:
+ ret_inst = getattr(guest, parserclass.clear_attr)
else:
- fail(_("--build-xml not supported for --%s") % parserobj.cli_arg_name)
+ fail(_("--build-xml not supported for --%s") %
+ parserclass.cli_arg_name)
- ret = cli.parse_option_strings(parsermap, options, guest, inst)
+ ret = cli.parse_option_strings(options, guest, inst)
if ret_inst:
return ret_inst
return ret
@@ -302,19 +302,19 @@ def update_changes(domain, devs, action, confirm):
print_stdout("")
-def prepare_changes(xmlobj, options, parsermap, parserobj):
+def prepare_changes(xmlobj, options, parserclass):
origxml = xmlobj.get_xml_config()
if options.edit != -1:
- devs = action_edit(xmlobj, options, parsermap, parserobj)
+ devs = action_edit(xmlobj, options, parserclass)
action = "update"
elif options.add_device:
- devs = action_add_device(xmlobj, options, parsermap, parserobj)
+ devs = action_add_device(xmlobj, options, parserclass)
action = "hotplug"
elif options.remove_device:
- devs = action_remove_device(xmlobj, options, parsermap, parserobj)
+ devs = action_remove_device(xmlobj, options, parserclass)
action = "hotunplug"
newxml = xmlobj.get_xml_config()
@@ -408,8 +408,7 @@ def main(conn=None):
options.quiet = False
cli.setupLogging("virt-xml", options.debug, options.quiet)
- parsermap = cli.build_parser_map(options)
- if cli.check_option_introspection(options, parsermap):
+ if cli.check_option_introspection(options):
return 0
options.stdinxml = None
@@ -445,31 +444,29 @@ def main(conn=None):
inactive_xmlobj = _make_guest(conn, options.stdinxml)
check_action_collision(options)
- parserobj = check_xmlopt_collision(options, parsermap)
+ parserclass = check_xmlopt_collision(options)
- if options.update and not parserobj.objclass:
+ if options.update and not parserclass.objclass:
fail(_("Don't know how to --update for --%s") %
- (parserobj.cli_arg_name))
+ (parserclass.cli_arg_name))
if options.build_xml:
- devs = action_build_xml(conn, options, parsermap, parserobj)
- for dev in util.listify(devs):
+ devs = action_build_xml(conn, options, parserclass)
+ for dev in devs:
print_stdout(dev.get_xml_config())
return 0
if options.update and active_xmlobj:
- devs, action = prepare_changes(active_xmlobj, options,
- parsermap, parserobj)
+ devs, action = prepare_changes(active_xmlobj, options, parserclass)
update_changes(domain, devs, action, options.confirm)
if options.define:
- devs, action = prepare_changes(inactive_xmlobj, options,
- parsermap, parserobj)
+ devs, action = prepare_changes(inactive_xmlobj, options, parserclass)
define_changes(conn, inactive_xmlobj, devs, action, options.confirm)
if not options.update and active_xmlobj:
print_stdout(
_("Changes will take effect after the next domain shutdown."))
if not options.update and not options.define:
- prepare_changes(inactive_xmlobj, options, parsermap, parserobj)
+ prepare_changes(inactive_xmlobj, options, parserclass)
return 0
diff --git a/virtinst/cli.py b/virtinst/cli.py
index ea601ff2..038cdaea 100644
--- a/virtinst/cli.py
+++ b/virtinst/cli.py
@@ -771,8 +771,8 @@ class _SetterCBData(object):
Structure holding all the data we want to pass to the cli
cb callbacks. Makes it simpler to add new fields in the future.
"""
- def __init__(self, opts, cliname):
- self.opts = opts
+ def __init__(self, optdict, cliname):
+ self.optdict = optdict
self.cliname = cliname
@@ -822,16 +822,31 @@ class _VirtCLIArgument(object):
self.lookup_cb = lookup_cb
self.is_novalue = is_novalue
- def _lookup_val(self, opts, inst, support_cb, is_lookup):
+ def _pop_opt(self, optdict, key):
"""
- Find the value in 'opts' thats associated with this Argument,
+ Basically optdict.pop(key, None) with is_novalue wrapped in
+ """
+ if key not in optdict:
+ return None
+
+ ret = optdict.pop(key)
+ if ret is None:
+ if not self.is_novalue:
+ raise RuntimeError("Option '%s' had no value set." % key)
+ ret = ""
+
+ return ret
+
+ def _lookup_val(self, optdict, inst, support_cb, is_lookup):
+ """
+ Find the value in 'optdict' thats associated with this Argument,
and perform some other misc checking
"""
val = None
for cliname in self.aliases + [self.cliname]:
# We iterate over all values unconditionally, so they are
- # removed from opts
- foundval = opts.get_opt_param(cliname, self.is_novalue)
+ # removed from optdict
+ foundval = self._pop_opt(optdict, cliname)
if foundval is not None:
val = foundval
if val is None:
@@ -847,15 +862,15 @@ class _VirtCLIArgument(object):
return 0
return val
- def parse_param(self, opts, inst, support_cb):
+ def parse_param(self, optdict, inst, support_cb):
"""
Process the cli param against the pass inst.
So if we are VirtCLIArgument for --disk device=, and the user
specified --disk device=foo, we grab 'device=foo' from the
- parsed 'opts', and set inst.device = foo
+ parsed 'optdict', and set inst.device = foo
"""
- val = self._lookup_val(opts, inst, support_cb, False)
+ val = self._lookup_val(optdict, inst, support_cb, False)
if val is 0:
return
@@ -866,22 +881,22 @@ class _VirtCLIArgument(object):
raise RuntimeError("programming error: obj=%s does not have "
"member=%s" % (inst, self.attrname))
- cbdata = _SetterCBData(opts, self.cliname)
+ cbdata = _SetterCBData(optdict, self.cliname)
if self.cb:
self.cb(inst, val, cbdata)
else:
exec( # pylint: disable=exec-used
"inst." + self.attrname + " = val")
- def lookup_param(self, opts, inst):
+ def lookup_param(self, optdict, inst):
"""
See if the passed value matches our Argument, like via virt-xml
So if this Argument is for --disk device=, and the user
specified virt-xml --edit device=floppy --disk ..., we grab
- device=floppy from 'opts', then return 'inst.device == floppy'
+ device=floppy from 'optdict', then return 'inst.device == floppy'
"""
- val = self._lookup_val(opts, inst, None, True)
+ val = self._lookup_val(optdict, inst, None, True)
if val is 0:
return
@@ -892,7 +907,7 @@ class _VirtCLIArgument(object):
{"device_type": getattr(inst, "virtual_device_type", ""),
"property_name": self.cliname})
- cbdata = _SetterCBData(opts, self.cliname)
+ cbdata = _SetterCBData(optdict, self.cliname)
if self.lookup_cb:
return self.lookup_cb(inst, val, cbdata)
else:
@@ -938,101 +953,64 @@ def parse_optstr_tuples(optstr):
return ret
-class _VirtOptionString(object):
- def __init__(self, optstr, virtargs, remove_first):
- """
- Helper class for parsing opt strings of the form
- opt1=val1,opt2=val2,...
-
- @optstr: The full option string
- @virtargs: A list of VirtCLIArguments
- @remove_first: List of parameters to peel off the front of
- option string, and store in the returned dict.
- remove_first=["char_type"] for --serial pty,foo=bar
- maps to {"char_type", "pty", "foo" : "bar"}
- """
- self.fullopts = optstr
-
- # @optsdict: A dictionary of the mapping {cliname: val}
- self.optsdict = self._parse_optstr(virtargs, remove_first)
-
- def get_opt_param(self, key, is_novalue=False):
- """
- Basically self.optsdict.pop(key, None) with a little extra
- error reporting wrapped in
- """
- if key not in self.optsdict:
- return None
-
- ret = self.optsdict.pop(key)
- if ret is None:
- if not is_novalue:
- raise RuntimeError("Option '%s' had no value set." % key)
- ret = ""
-
- return ret
-
- def check_leftover_opts(self):
- if not self.optsdict:
- return
- raise fail(_("Unknown options %s") % self.optsdict.keys())
-
-
- ###########################
- # Actual parsing routines #
- ###########################
+def _parse_optstr_to_dict(optstr, virtargs, remove_first):
+ """
+ Parse the passed argument string into an OrderedDict WRT
+ the passed list of VirtCLIArguments and their special handling.
- def _parse_optstr(self, virtargs, remove_first):
- optsdict = collections.OrderedDict()
- opttuples = parse_optstr_tuples(self.fullopts or "")
+ So for --disk path=foo,size=5, optstr is 'path=foo,size=5', and
+ we return {"path": "foo", "size": "5"}
+ """
+ optsdict = collections.OrderedDict()
+ opttuples = parse_optstr_tuples(optstr)
- def _add_opt(virtarg, cliname, val):
- if (cliname not in optsdict and
- virtarg and
- virtarg.is_list):
- optsdict[cliname] = []
+ def _add_opt(virtarg, cliname, val):
+ if (cliname not in optsdict and
+ virtarg and
+ virtarg.is_list):
+ optsdict[cliname] = []
- if type(optsdict.get(cliname)) is list:
- optsdict[cliname].append(val)
- else:
- optsdict[cliname] = val
+ if type(optsdict.get(cliname)) is list:
+ optsdict[cliname].append(val)
+ else:
+ optsdict[cliname] = val
+
+ def _lookup_virtarg(cliname):
+ for virtarg in virtargs:
+ if virtarg.match_name(cliname):
+ return virtarg
+
+ # Splice in remove_first names upfront
+ remove_first = util.listify(remove_first)[:]
+ for idx, (cliname, val) in enumerate(opttuples):
+ if val is not None or not remove_first:
+ break
+ opttuples[idx] = (remove_first.pop(0), cliname)
+
+ commaopt = []
+ virtarg = None
+ for cliname, val in opttuples:
+ virtarg = _lookup_virtarg(cliname)
+ if commaopt:
+ if not virtarg:
+ commaopt[1] += "," + cliname
+ if val:
+ commaopt[1] += "=" + val
+ continue
- def _lookup_virtarg(cliname):
- for virtarg in virtargs:
- if virtarg.match_name(cliname):
- return virtarg
+ _add_opt(virtarg, commaopt[0], commaopt[1])
+ commaopt = []
- # Splice in remove_first names upfront
- remove_first = util.listify(remove_first)[:]
- for idx, (cliname, val) in enumerate(opttuples):
- if val is not None or not remove_first:
- break
- opttuples[idx] = (remove_first.pop(0), cliname)
-
- commaopt = []
- virtarg = None
- for cliname, val in opttuples:
- virtarg = _lookup_virtarg(cliname)
- if commaopt:
- if not virtarg:
- commaopt[1] += "," + cliname
- if val:
- commaopt[1] += "=" + val
- continue
-
- _add_opt(virtarg, commaopt[0], commaopt[1])
- commaopt = []
-
- if (virtarg and virtarg.can_comma):
- commaopt = [cliname, val]
- continue
+ if (virtarg and virtarg.can_comma):
+ commaopt = [cliname, val]
+ continue
- _add_opt(virtarg, cliname, val)
+ _add_opt(virtarg, cliname, val)
- if commaopt:
- _add_opt(virtarg, commaopt[0], commaopt[1])
+ if commaopt:
+ _add_opt(virtarg, commaopt[0], commaopt[1])
- return optsdict
+ return optsdict
class VirtCLIParser(object):
@@ -1046,7 +1024,10 @@ class VirtCLIParser(object):
crazy stuff.
Class parameters:
- @remove_first: Passed to _VirtOptionString
+ @remove_first: List of parameters to peel off the front of the
+ option string, and store in the optdict. So:
+ remove_first=["char_type"] for --serial pty,foo=bar
+ maps to {"char_type", "pty", "foo" : "bar"}
@check_none: If the parsed option string is just 'none', return None
@support_cb: An extra support check function for further validation.
Called before the virtinst object is altered. Take arguments
@@ -1064,105 +1045,123 @@ class VirtCLIParser(object):
support_cb = None
clear_attr = None
cli_arg_name = None
- _class_args = None
+ _virtargs = []
@classmethod
def add_arg(cls, *args, **kwargs):
"""
Add a VirtCLIArgument for this class.
"""
- if not cls._class_args:
- cls._class_args = []
- cls._class_args.append(_VirtCLIArgument(*args, **kwargs))
-
+ if not cls._virtargs:
+ cls._virtargs = [_VirtCLIArgument(None, "clearxml",
+ cb=cls._clearxml_cb,
+ is_onoff=True)]
+ cls._virtargs.append(_VirtCLIArgument(*args, **kwargs))
- def __init__(self):
- self.guest = None
-
- self._params = [_VirtCLIArgument(None, "clearxml",
- cb=self._clearxml_cb,
- is_onoff=True)]
- self._params += (self._class_args or [])
-
- def _clearxml_cb(self, inst, val, cbdata):
+ @classmethod
+ def _clearxml_cb(cls, inst, val, cbdata):
"""
Callback that handles virt-xml clearxml=yes|no magic
"""
ignore = cbdata
- if not self.objclass and not self.clear_attr:
+ if not cls.objclass and not cls.clear_attr:
raise RuntimeError("Don't know how to clearxml --%s" %
- self.cli_arg_name)
+ cls.cli_arg_name)
if val is not True:
return
clear_inst = inst
- if self.clear_attr:
- clear_inst = getattr(inst, self.clear_attr)
+ if cls.clear_attr:
+ clear_inst = getattr(inst, cls.clear_attr)
# If there's any opts remaining, leave the root stub element
- # in place, so virt-xml updates are done in place.
+ # in place with leave_stub=True, so virt-xml updates are done
+ # in place.
#
- # So --edit --cpu clearxml=yes should remove the entire <cpu>
+ # Example: --edit --cpu clearxml=yes should remove the <cpu>
# block. But --edit --cpu clearxml=yes,model=foo should leave
# a <cpu> stub in place, so that it gets model=foo in place,
# otherwise the newly created cpu block gets appened to the
# end of the domain XML, which gives an ugly diff
- clear_inst.clear(leave_stub=bool(cbdata.opts.optsdict))
+ clear_inst.clear(leave_stub=bool(cbdata.optdict))
- def print_introspection(self):
+ @classmethod
+ def print_introspection(cls):
"""
Print out all _param names, triggered via ex. --disk help
"""
- print "--%s options:" % self.cli_arg_name
- for arg in sorted(self._params, key=lambda p: p.cliname):
+ print "--%s options:" % cls.cli_arg_name
+ for arg in sorted(cls._virtargs, key=lambda p: p.cliname):
print " %s" % arg.cliname
print
- def parse(self, guest, optlist, inst, validate=True):
- 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 occurrence, eg. from virt-xml
- optlist = [optlist[-1]]
+ def __init__(self, guest, optstr):
+ self.guest = guest
+ self.optstr = optstr
+ self.optdict = _parse_optstr_to_dict(self.optstr,
+ self._virtargs,
+ self.remove_first)
- ret = []
- for optstr in optlist:
- new_object = False
- optinst = inst
- if self.objclass and not inst:
- if guest.child_class_is_singleton(self.objclass):
- optinst = guest.list_children_for_class(
- self.objclass)[0]
- else:
- new_object = True
- optinst = self.objclass(guest.conn) # pylint: disable=not-callable
-
- try:
- objs = self._parse_single_optstr(guest, optstr, optinst)
- for obj in util.listify(objs):
- if not new_object:
- break
- if validate:
- obj.validate()
- guest.add_child(obj)
+ def _parse(self, inst):
+ """
+ Subclasses can hook into this to do any pre/post processing
+ of the inst, or self.optdict
+ """
+ for param in self._virtargs:
+ param.parse_param(self.optdict, inst, self.support_cb)
- ret += util.listify(objs)
- except Exception, e:
- logging.debug("Exception parsing inst=%s optstr=%s",
- inst, optstr, exc_info=True)
- fail(_("Error: --%(cli_arg_name)s %(options)s: %(err)s") %
- {"cli_arg_name": self.cli_arg_name,
- "options": optstr, "err": str(e)})
+ # Check leftover opts
+ if self.optdict:
+ fail(_("Unknown options %s") % self.optdict.keys())
+ return inst
- if not ret:
+ def parse(self, inst, validate=True):
+ """
+ Main entry point. Iterate over self._virtargs, and serialize
+ self.optdict into 'inst'.
+
+ For virt-xml, 'inst' is the virtinst object we are editing,
+ ex. a VirtualDisk from a parsed Guest object.
+ For virt-install, 'inst' is None, and we will create a new
+ inst from self.objclass, or edit a singleton object in place
+ like Guest.features/DomainFeatures
+ """
+ if not self.optstr:
return None
- if len(ret) == 1:
- return ret[0]
+ if self.check_none and self.optstr == "none":
+ return None
+
+ new_object = False
+ if self.objclass and not inst:
+ if self.guest.child_class_is_singleton(self.objclass):
+ inst = self.guest.list_children_for_class(self.objclass)[0]
+ else:
+ new_object = True
+ inst = self.objclass( # pylint: disable=not-callable
+ self.guest.conn)
+
+ ret = []
+ try:
+ objs = self._parse(inst or self.guest)
+ for obj in util.listify(objs):
+ if not new_object:
+ break
+ if validate:
+ obj.validate()
+ self.guest.add_child(obj)
+
+ ret += util.listify(objs)
+ except Exception, e:
+ logging.debug("Exception parsing inst=%s optstr=%s",
+ inst, self.optstr, exc_info=True)
+ fail(_("Error: --%(cli_arg_name)s %(options)s: %(err)s") %
+ {"cli_arg_name": self.cli_arg_name,
+ "options": self.optstr, "err": str(e)})
+
return ret
- def lookup_child_from_option_string(self, guest, optstr):
+ def lookup_child_from_option_string(self):
"""
Given a passed option string, search the guests' child list
for all objects which match the passed options.
@@ -1170,49 +1169,34 @@ class VirtCLIParser(object):
Used only by virt-xml --edit lookups
"""
ret = []
- objlist = guest.list_children_for_class(self.objclass)
+ objlist = self.guest.list_children_for_class(self.objclass)
for inst in objlist:
try:
- opts = _VirtOptionString(optstr, self._params,
- self.remove_first)
- valid = True
- for param in self._params:
- if param.lookup_param(opts, inst) is False:
- valid = False
+ optdict = self.optdict.copy()
+ valid = False
+ for param in self._virtargs:
+ paramret = param.lookup_param(optdict, inst)
+ if paramret is True:
+ valid = True
break
if valid:
ret.append(inst)
except Exception, e:
logging.debug("Exception parsing inst=%s optstr=%s",
- inst, optstr, exc_info=True)
+ inst, self.optstr, exc_info=True)
fail(_("Error: --%(cli_arg_name)s %(options)s: %(err)s") %
{"cli_arg_name": self.cli_arg_name,
- "options": optstr, "err": str(e)})
+ "options": self.optstr, "err": str(e)})
return ret
- def _parse_single_optstr(self, guest, optstr, inst):
- if not optstr:
- return None
- if self.check_none and optstr == "none":
- return None
- if not inst:
- inst = guest
+VIRT_PARSERS = []
- try:
- self.guest = guest
- opts = _VirtOptionString(optstr, self._params, self.remove_first)
- return self._parse(opts, inst)
- finally:
- self.guest = None
-
- def _parse(self, opts, inst):
- for param in self._params:
- param.parse_param(opts, inst, self.support_cb)
- opts.check_leftover_opts()
- return inst
+
+def _register_virt_parser(parserclass):
+ VIRT_PARSERS.append(parserclass)
###################
@@ -1246,8 +1230,8 @@ ParseCLICheck.add_arg("all_checks", "all", is_onoff=True)
def parse_check(checkstr):
# Overwrite this for each parse
- parser = ParseCLICheck()
- parser.parse(None, checkstr, get_global_state())
+ parser = ParseCLICheck(None, checkstr)
+ parser.parse(get_global_state())
######################
@@ -1255,8 +1239,9 @@ def parse_check(checkstr):
######################
class ParserMetadata(VirtCLIParser):
- pass
+ cli_arg_name = "metadata"
+_register_virt_parser(ParserMetadata)
ParserMetadata.add_arg("name", "name", can_comma=True)
ParserMetadata.add_arg("title", "title", can_comma=True)
ParserMetadata.add_arg("uuid", "uuid")
@@ -1268,8 +1253,9 @@ ParserMetadata.add_arg("description", "description", can_comma=True)
####################
class ParserEvents(VirtCLIParser):
- pass
+ cli_arg_name = "events"
+_register_virt_parser(ParserEvents)
ParserEvents.add_arg("on_poweroff", "on_poweroff")
ParserEvents.add_arg("on_reboot", "on_reboot")
ParserEvents.add_arg("on_crash", "on_crash")
@@ -1281,9 +1267,11 @@ ParserEvents.add_arg("on_lockfailure", "on_lockfailure")
######################
class ParserResource(VirtCLIParser):
+ cli_arg_name = "resource"
objclass = DomainResource
remove_first = "partition"
+_register_virt_parser(ParserResource)
ParserResource.add_arg("partition", "partition")
@@ -1292,9 +1280,11 @@ ParserResource.add_arg("partition", "partition")
######################
class ParserNumatune(VirtCLIParser):
+ cli_arg_name = "numatune"
objclass = DomainNumatune
remove_first = "nodeset"
+_register_virt_parser(ParserNumatune)
ParserNumatune.add_arg("memory_nodeset", "nodeset", can_comma=True)
ParserNumatune.add_arg("memory_mode", "mode")
@@ -1304,6 +1294,7 @@ ParserNumatune.add_arg("memory_mode", "mode")
####################
class ParserMemory(VirtCLIParser):
+ cli_arg_name = "memory"
remove_first = "memory"
@staticmethod
@@ -1311,6 +1302,7 @@ class ParserMemory(VirtCLIParser):
setattr(inst, cbdata.cliname, int(val) * 1024)
+_register_virt_parser(ParserMemory)
ParserMemory.add_arg("memory", "memory", cb=ParserMemory.set_memory_cb)
ParserMemory.add_arg("maxmemory", "maxmemory", cb=ParserMemory.set_memory_cb)
ParserMemory.add_arg("memoryBacking.hugepages", "hugepages", is_onoff=True)
@@ -1321,9 +1313,11 @@ ParserMemory.add_arg("memoryBacking.hugepages", "hugepages", is_onoff=True)
#####################
class ParserMemorytune(VirtCLIParser):
+ cli_arg_name = "memtune"
objclass = DomainMemorytune
remove_first = "soft_limit"
+_register_virt_parser(ParserMemorytune)
ParserMemorytune.add_arg("hard_limit", "hard_limit")
ParserMemorytune.add_arg("soft_limit", "soft_limit")
ParserMemorytune.add_arg("swap_hard_limit", "swap_hard_limit")
@@ -1335,9 +1329,11 @@ ParserMemorytune.add_arg("min_guarantee", "min_guarantee")
#######################
class ParserBlkiotune(VirtCLIParser):
+ cli_arg_name = "blkiotune"
objclass = DomainBlkiotune
remove_first = "weight"
+_register_virt_parser(ParserBlkiotune)
ParserBlkiotune.add_arg("weight", "weight")
ParserBlkiotune.add_arg("device_path", "device_path")
ParserBlkiotune.add_arg("device_weight", "device_weight")
@@ -1348,8 +1344,10 @@ ParserBlkiotune.add_arg("device_weight", "device_weight")
###########################
class ParserMemorybacking(VirtCLIParser):
+ cli_arg_name = "memorybacking"
objclass = DomainMemorybacking
+_register_virt_parser(ParserMemorybacking)
ParserMemorybacking.add_arg("hugepages", "hugepages", is_onoff=True)
ParserMemorybacking.add_arg("page_size", "size")
ParserMemorybacking.add_arg("page_unit", "unit")
@@ -1358,66 +1356,12 @@ ParserMemorybacking.add_arg("nosharepages", "nosharepages", is_onoff=True)
ParserMemorybacking.add_arg("locked", "locked", is_onoff=True)
-###################
-# --vcpus parsing #
-###################
-
-class ParserVCPU(VirtCLIParser):
- remove_first = "vcpus"
-
- @staticmethod
- def set_vcpus_cb(inst, val, cbdata):
- attrname = (("maxvcpus" in cbdata.opts.optsdict) and
- "curvcpus" or "vcpus")
- setattr(inst, attrname, val)
-
- @staticmethod
- def set_cpuset_cb(inst, val, cbdata):
- if not val:
- return
- if val != "auto":
- inst.cpuset = val
- return
-
- # Previously we did our own one-time cpuset placement
- # based on current NUMA memory availability, but that's
- # pretty dumb unless the conditions on the host never change.
- # So instead use newer vcpu placement=, but only if it's
- # supported.
- if not inst.conn.check_support(
- inst.conn.SUPPORT_CONN_VCPU_PLACEMENT):
- logging.warning("vcpu placement=auto not supported, skipping.")
- return
-
- inst.vcpu_placement = "auto"
-
- def _parse(self, opts, inst):
- set_from_top = ("maxvcpus" not in opts.optsdict and
- "vcpus" not in opts.optsdict)
-
- ret = VirtCLIParser._parse(self, opts, inst)
-
- if set_from_top:
- inst.vcpus = inst.cpu.vcpus_from_topology()
- return ret
-
-
-ParserVCPU.add_arg("cpu.sockets", "sockets")
-ParserVCPU.add_arg("cpu.cores", "cores")
-ParserVCPU.add_arg("cpu.threads", "threads")
-
-ParserVCPU.add_arg(None, "vcpus", cb=ParserVCPU.set_vcpus_cb)
-ParserVCPU.add_arg("vcpus", "maxvcpus")
-
-ParserVCPU.add_arg(None, "cpuset", can_comma=True, cb=ParserVCPU.set_cpuset_cb)
-ParserVCPU.add_arg("vcpu_placement", "placement")
-
-
#################
# --cpu parsing #
#################
class ParserCPU(VirtCLIParser):
+ cli_arg_name = "cpu"
objclass = CPU
remove_first = "model"
@@ -1450,9 +1394,9 @@ class ParserCPU(VirtCLIParser):
else:
inst.add_feature(feature_name, policy)
- def _parse(self, opts, inst):
+ def _parse(self, inst):
# Convert +feature, -feature into expected format
- for key, value in opts.optsdict.items():
+ for key, value in self.optdict.items():
policy = None
if value or len(key) == 1:
continue
@@ -1463,14 +1407,15 @@ class ParserCPU(VirtCLIParser):
policy = "disable"
if policy:
- del(opts.optsdict[key])
- if opts.optsdict.get(policy) is None:
- opts.optsdict[policy] = []
- opts.optsdict[policy].append(key[1:])
+ del(self.optdict[key])
+ if self.optdict.get(policy) is None:
+ self.optdict[policy] = []
+ self.optdict[policy].append(key[1:])
- return VirtCLIParser._parse(self, opts, inst)
+ return VirtCLIParser._parse(self, inst)
+_register_virt_parser(ParserCPU)
ParserCPU.add_arg(None, "model", cb=ParserCPU.set_model_cb)
ParserCPU.add_arg("mode", "mode")
ParserCPU.add_arg("match", "match")
@@ -1483,11 +1428,69 @@ ParserCPU.add_arg(None, "disable", is_list=True, cb=ParserCPU.set_feature_cb)
ParserCPU.add_arg(None, "forbid", is_list=True, cb=ParserCPU.set_feature_cb)
+###################
+# --vcpus parsing #
+###################
+
+class ParserVCPU(VirtCLIParser):
+ cli_arg_name = "vcpus"
+ remove_first = "vcpus"
+
+ @staticmethod
+ def set_vcpus_cb(inst, val, cbdata):
+ attrname = (("maxvcpus" in cbdata.optdict) and
+ "curvcpus" or "vcpus")
+ setattr(inst, attrname, val)
+
+ @staticmethod
+ def set_cpuset_cb(inst, val, cbdata):
+ if not val:
+ return
+ if val != "auto":
+ inst.cpuset = val
+ return
+
+ # Previously we did our own one-time cpuset placement
+ # based on current NUMA memory availability, but that's
+ # pretty dumb unless the conditions on the host never change.
+ # So instead use newer vcpu placement=, but only if it's
+ # supported.
+ if not inst.conn.check_support(
+ inst.conn.SUPPORT_CONN_VCPU_PLACEMENT):
+ logging.warning("vcpu placement=auto not supported, skipping.")
+ return
+
+ inst.vcpu_placement = "auto"
+
+ def _parse(self, inst):
+ set_from_top = ("maxvcpus" not in self.optdict and
+ "vcpus" not in self.optdict)
+
+ ret = VirtCLIParser._parse(self, inst)
+
+ if set_from_top:
+ inst.vcpus = inst.cpu.vcpus_from_topology()
+ return ret
+
+
+_register_virt_parser(ParserVCPU)
+ParserVCPU.add_arg("cpu.sockets", "sockets")
+ParserVCPU.add_arg("cpu.cores", "cores")
+ParserVCPU.add_arg("cpu.threads", "threads")
+
+ParserVCPU.add_arg(None, "vcpus", cb=ParserVCPU.set_vcpus_cb)
+ParserVCPU.add_arg("vcpus", "maxvcpus")
+
+ParserVCPU.add_arg(None, "cpuset", can_comma=True, cb=ParserVCPU.set_cpuset_cb)
+ParserVCPU.add_arg("vcpu_placement", "placement")
+
+
##################
# --boot parsing #
##################
class ParserBoot(VirtCLIParser):
+ cli_arg_name = "boot"
clear_attr = "os"
@staticmethod
@@ -1505,23 +1508,24 @@ class ParserBoot(VirtCLIParser):
def noset_cb(inst, val, cbdata):
pass
- def _parse(self, opts, inst):
+ def _parse(self, inst):
# Build boot order
boot_order = []
- for cliname in opts.optsdict.keys():
+ for cliname in self.optdict.keys():
if cliname not in inst.os.BOOT_DEVICES:
continue
- del(opts.optsdict[cliname])
+ del(self.optdict[cliname])
if cliname not in boot_order:
boot_order.append(cliname)
if boot_order:
inst.os.bootorder = boot_order
- VirtCLIParser._parse(self, opts, inst)
+ VirtCLIParser._parse(self, inst)
+_register_virt_parser(ParserBoot)
# UEFI depends on these bits, so set them first
ParserBoot.add_arg("os.arch", "arch")
ParserBoot.add_arg("type", "domain_type")
@@ -1556,12 +1560,13 @@ for _bootdev in OSXML.BOOT_DEVICES:
###################
class ParserIdmap(VirtCLIParser):
+ cli_arg_name = "idmap"
objclass = IdMap
+_register_virt_parser(ParserIdmap)
ParserIdmap.add_arg("uid_start", "uid_start")
ParserIdmap.add_arg("uid_target", "uid_target")
ParserIdmap.add_arg("uid_count", "uid_count")
-
ParserIdmap.add_arg("gid_start", "gid_start")
ParserIdmap.add_arg("gid_target", "gid_target")
ParserIdmap.add_arg("gid_count", "gid_count")
@@ -1572,8 +1577,10 @@ ParserIdmap.add_arg("gid_count", "gid_count")
######################
class ParserSecurity(VirtCLIParser):
+ cli_arg_name = "security"
objclass = Seclabel
+_register_virt_parser(ParserSecurity)
ParserSecurity.add_arg("type", "type")
ParserSecurity.add_arg("model", "model")
ParserSecurity.add_arg("relabel", "relabel", is_onoff=True)
@@ -1586,8 +1593,10 @@ ParserSecurity.add_arg("baselabel", "label", can_comma=True)
######################
class ParserFeatures(VirtCLIParser):
+ cli_arg_name = "features"
objclass = DomainFeatures
+_register_virt_parser(ParserFeatures)
ParserFeatures.add_arg("acpi", "acpi", is_onoff=True)
ParserFeatures.add_arg("apic", "apic", is_onoff=True)
ParserFeatures.add_arg("pae", "pae", is_onoff=True)
@@ -1615,6 +1624,7 @@ ParserFeatures.add_arg("gic_version", "gic_version")
###################
class ParserClock(VirtCLIParser):
+ cli_arg_name = "clock"
objclass = Clock
@staticmethod
@@ -1634,6 +1644,7 @@ class ParserClock(VirtCLIParser):
setattr(timerobj, attrname, val)
+_register_virt_parser(ParserClock)
ParserClock.add_arg("offset", "offset")
for _tname in Clock.TIMER_NAMES:
@@ -1648,8 +1659,10 @@ for _tname in Clock.TIMER_NAMES:
################
class ParserPM(VirtCLIParser):
+ cli_arg_name = "pm"
objclass = PM
+_register_virt_parser(ParserPM)
ParserPM.add_arg("suspend_to_mem", "suspend_to_mem", is_onoff=True)
ParserPM.add_arg("suspend_to_disk", "suspend_to_disk", is_onoff=True)
@@ -1714,6 +1727,7 @@ def _generate_new_volume_name(guest, poolobj, fmt):
class ParserDisk(VirtCLIParser):
+ cli_arg_name = "disk"
objclass = VirtualDisk
remove_first = "path"
@@ -1721,8 +1735,8 @@ class ParserDisk(VirtCLIParser):
def noset_cb(inst, val, cbdata):
ignore = inst, val, cbdata
- def _parse(self, opts, inst):
- if opts.fullopts == "none":
+ def _parse(self, inst):
+ if self.optstr == "none":
return
def parse_size(val):
@@ -1737,26 +1751,26 @@ class ParserDisk(VirtCLIParser):
if val is None:
return
if val == "ro":
- opts.optsdict["readonly"] = "on"
+ self.optdict["readonly"] = "on"
elif val == "sh":
- opts.optsdict["shareable"] = "on"
+ self.optdict["shareable"] = "on"
elif val == "rw":
# It's default. Nothing to do.
pass
else:
fail(_("Unknown '%s' value '%s'") % ("perms", val))
- has_path = "path" in opts.optsdict
- backing_store = opts.get_opt_param("backing_store")
- poolname = opts.get_opt_param("pool")
- volname = opts.get_opt_param("vol")
- size = parse_size(opts.get_opt_param("size"))
- fmt = opts.get_opt_param("format")
- sparse = _on_off_convert("sparse", opts.get_opt_param("sparse"))
- convert_perms(opts.get_opt_param("perms"))
- has_type_volume = ("source_pool" in opts.optsdict or
- "source_volume" in opts.optsdict)
- has_type_network = ("source_protocol" in opts.optsdict)
+ has_path = "path" in self.optdict
+ backing_store = self.optdict.pop("backing_store", None)
+ poolname = self.optdict.pop("pool", None)
+ volname = self.optdict.pop("vol", None)
+ size = parse_size(self.optdict.pop("size", None))
+ fmt = self.optdict.pop("format", None)
+ sparse = _on_off_convert("sparse", self.optdict.pop("sparse", None))
+ convert_perms(self.optdict.pop("perms", None))
+ has_type_volume = ("source_pool" in self.optdict or
+ "source_volume" in self.optdict)
+ has_type_network = ("source_protocol" in self.optdict)
optcount = sum([bool(p) for p in [has_path, poolname, volname,
has_type_volume, has_type_network]])
@@ -1774,7 +1788,7 @@ class ParserDisk(VirtCLIParser):
logging.debug("Parsed --disk volume as: pool=%s vol=%s",
poolname, volname)
- VirtCLIParser._parse(self, opts, inst)
+ VirtCLIParser._parse(self, inst)
# Generate and fill in the disk source info
newvolname = None
@@ -1812,6 +1826,7 @@ class ParserDisk(VirtCLIParser):
return inst
+_register_virt_parser(ParserDisk)
_add_device_address_args(ParserDisk)
# These are all handled specially in _parse
@@ -1862,6 +1877,7 @@ ParserDisk.add_arg("sgio", "sgio")
#####################
class ParserNetwork(VirtCLIParser):
+ cli_arg_name = "network"
objclass = VirtualNetworkInterface
remove_first = "type"
@@ -1895,21 +1911,22 @@ class ParserNetwork(VirtCLIParser):
val = "down"
inst.link_state = val
- def _parse(self, opts, inst):
- if opts.fullopts == "none":
+ def _parse(self, inst):
+ if self.optstr == "none":
return
- if "type" not in opts.optsdict:
- if "network" in opts.optsdict:
- opts.optsdict["type"] = VirtualNetworkInterface.TYPE_VIRTUAL
- opts.optsdict["source"] = opts.optsdict.pop("network")
- elif "bridge" in opts.optsdict:
- opts.optsdict["type"] = VirtualNetworkInterface.TYPE_BRIDGE
- opts.optsdict["source"] = opts.optsdict.pop("bridge")
+ if "type" not in self.optdict:
+ if "network" in self.optdict:
+ self.optdict["type"] = VirtualNetworkInterface.TYPE_VIRTUAL
+ self.optdict["source"] = self.optdict.pop("network")
+ elif "bridge" in self.optdict:
+ self.optdict["type"] = VirtualNetworkInterface.TYPE_BRIDGE
+ self.optdict["source"] = self.optdict.pop("bridge")
- return VirtCLIParser._parse(self, opts, inst)
+ return VirtCLIParser._parse(self, inst)
+_register_virt_parser(ParserNetwork)
_add_device_address_args(ParserNetwork)
ParserNetwork.add_arg("type", "type", cb=ParserNetwork.set_type_cb)
ParserNetwork.add_arg("source", "source")
@@ -1947,6 +1964,7 @@ ParserNetwork.add_arg("virtualport.interfaceid", "virtualport_interfaceid")
######################
class ParserGraphics(VirtCLIParser):
+ cli_arg_name = "graphics"
objclass = VirtualGraphics
remove_first = "type"
@@ -1987,12 +2005,12 @@ class ParserGraphics(VirtCLIParser):
else:
inst.listen = val
- def _parse(self, opts, inst):
- if opts.fullopts == "none":
+ def _parse(self, inst):
+ if self.optstr == "none":
self.guest.skip_default_graphics = True
return
- ret = VirtCLIParser._parse(self, opts, inst)
+ ret = VirtCLIParser._parse(self, inst)
if inst.conn.is_qemu() and inst.gl:
if inst.type != "spice":
@@ -2003,6 +2021,7 @@ class ParserGraphics(VirtCLIParser):
return ret
+_register_virt_parser(ParserGraphics)
_add_device_address_args(ParserGraphics)
ParserGraphics.add_arg(None, "type", cb=ParserGraphics.set_type_cb)
ParserGraphics.add_arg("port", "port")
@@ -2029,6 +2048,7 @@ ParserGraphics.add_arg("gl", "gl", is_onoff=True)
########################
class ParserController(VirtCLIParser):
+ cli_arg_name = "controller"
objclass = VirtualController
remove_first = "type"
@@ -2037,16 +2057,17 @@ class ParserController(VirtCLIParser):
ignore = cbdata
inst.address.set_addrstr(val)
- def _parse(self, opts, inst):
- if opts.fullopts == "usb2":
+ def _parse(self, inst):
+ if self.optstr == "usb2":
return VirtualController.get_usb2_controllers(inst.conn)
- elif opts.fullopts == "usb3":
+ elif self.optstr == "usb3":
inst.type = "usb"
inst.model = "nec-xhci"
return inst
- return VirtCLIParser._parse(self, opts, inst)
+ return VirtCLIParser._parse(self, inst)
+_register_virt_parser(ParserController)
_add_device_address_args(ParserController)
ParserController.add_arg("type", "type")
ParserController.add_arg("model", "model")
@@ -2061,9 +2082,11 @@ ParserController.add_arg(None, "address", cb=ParserController.set_server_cb)
###################
class ParserInput(VirtCLIParser):
+ cli_arg_name = "input"
objclass = VirtualInputDevice
remove_first = "type"
+_register_virt_parser(ParserInput)
_add_device_address_args(ParserInput)
ParserInput.add_arg("type", "type")
ParserInput.add_arg("bus", "bus")
@@ -2074,10 +2097,12 @@ ParserInput.add_arg("bus", "bus")
#######################
class ParserSmartcard(VirtCLIParser):
+ cli_arg_name = "smartcard"
objclass = VirtualSmartCardDevice
remove_first = "mode"
check_none = True
+_register_virt_parser(ParserSmartcard)
_add_device_address_args(ParserSmartcard)
ParserSmartcard.add_arg("mode", "mode")
ParserSmartcard.add_arg("type", "type")
@@ -2088,6 +2113,7 @@ ParserSmartcard.add_arg("type", "type")
######################
class ParserRedir(VirtCLIParser):
+ cli_arg_name = "redirdev"
objclass = VirtualRedirDevice
remove_first = "bus"
@@ -2096,12 +2122,13 @@ class ParserRedir(VirtCLIParser):
ignore = cbdata
inst.parse_friendly_server(val)
- def _parse(self, opts, inst):
- if opts.fullopts == "none":
+ def _parse(self, inst):
+ if self.optstr == "none":
self.guest.skip_default_usbredir = True
return
- return VirtCLIParser._parse(self, opts, inst)
+ return VirtCLIParser._parse(self, inst)
+_register_virt_parser(ParserRedir)
_add_device_address_args(ParserRedir)
ParserRedir.add_arg("bus", "bus")
ParserRedir.add_arg("type", "type")
@@ -2114,15 +2141,17 @@ ParserRedir.add_arg(None, "server", cb=ParserRedir.set_server_cb)
#################
class ParserTPM(VirtCLIParser):
+ cli_arg_name = "tpm"
objclass = VirtualTPMDevice
remove_first = "type"
check_none = True
- def _parse(self, opts, inst):
- if (opts.optsdict.get("type", "").startswith("/")):
- opts.optsdict["path"] = opts.optsdict.pop("type")
- return VirtCLIParser._parse(self, opts, inst)
+ def _parse(self, inst):
+ if (self.optdict.get("type", "").startswith("/")):
+ self.optdict["path"] = self.optdict.pop("type")
+ return VirtCLIParser._parse(self, inst)
+_register_virt_parser(ParserTPM)
_add_device_address_args(ParserTPM)
ParserTPM.add_arg("type", "type")
ParserTPM.add_arg("model", "model")
@@ -2134,6 +2163,7 @@ ParserTPM.add_arg("device_path", "path")
#################
class ParserRNG(VirtCLIParser):
+ cli_arg_name = "rng"
objclass = VirtualRNGDevice
remove_first = "type"
check_none = True
@@ -2167,18 +2197,19 @@ class ParserRNG(VirtCLIParser):
elif cbdata.cliname == "backend_type":
inst.cli_backend_type = val
- def _parse(self, opts, inst):
+ def _parse(self, inst):
inst.cli_backend_mode = "connect"
inst.cli_backend_type = "udp"
- if opts.optsdict.get("type", "").startswith("/"):
+ if self.optdict.get("type", "").startswith("/"):
# Allow --rng /dev/random
- opts.optsdict["device"] = opts.optsdict.pop("type")
- opts.optsdict["type"] = "random"
+ self.optdict["device"] = self.optdict.pop("type")
+ self.optdict["type"] = "random"
- return VirtCLIParser._parse(self, opts, inst)
+ return VirtCLIParser._parse(self, inst)
+_register_virt_parser(ParserRNG)
_add_device_address_args(ParserRNG)
ParserRNG.add_arg("type", "type")
@@ -2201,9 +2232,11 @@ ParserRNG.add_arg("rate_period", "rate_period")
######################
class ParserWatchdog(VirtCLIParser):
+ cli_arg_name = "watchdog"
objclass = VirtualWatchdog
remove_first = "model"
+_register_virt_parser(ParserWatchdog)
_add_device_address_args(ParserWatchdog)
ParserWatchdog.add_arg("model", "model")
ParserWatchdog.add_arg("action", "action")
@@ -2214,9 +2247,11 @@ ParserWatchdog.add_arg("action", "action")
########################
class ParserMemballoon(VirtCLIParser):
+ cli_arg_name = "memballoon"
objclass = VirtualMemballoon
remove_first = "model"
+_register_virt_parser(ParserMemballoon)
_add_device_address_args(ParserMemballoon)
ParserMemballoon.add_arg("model", "model")
@@ -2226,6 +2261,7 @@ ParserMemballoon.add_arg("model", "model")
###################
class ParserPanic(VirtCLIParser):
+ cli_arg_name = "panic"
objclass = VirtualPanicDevice
remove_first = "iobase"
@@ -2236,6 +2272,7 @@ class ParserPanic(VirtCLIParser):
return
inst.iobase = val
+_register_virt_parser(ParserPanic)
_add_device_address_args(ParserPanic)
ParserPanic.add_arg(None, "iobase", cb=ParserPanic.set_iobase_cb)
@@ -2261,8 +2298,8 @@ class _ParserChar(VirtCLIParser):
@staticmethod
def set_host_cb(inst, val, cbdata):
- if ("bind_host" not in cbdata.opts.optsdict and
- cbdata.opts.optsdict.get("mode", None) == "bind"):
+ if ("bind_host" not in cbdata.optdict and
+ cbdata.optdict.get("mode", None) == "bind"):
inst.set_friendly_bind(val)
else:
inst.set_friendly_source(val)
@@ -2277,15 +2314,15 @@ class _ParserChar(VirtCLIParser):
ignore = cbdata
inst.set_friendly_target(val)
- def _parse(self, opts, inst):
- if opts.fullopts == "none" and inst.virtual_device_type == "console":
+ def _parse(self, inst):
+ if self.optstr == "none" and inst.virtual_device_type == "console":
self.guest.skip_default_console = True
return
- if opts.fullopts == "none" and inst.virtual_device_type == "channel":
+ if self.optstr == "none" and inst.virtual_device_type == "channel":
self.guest.skip_default_channel = True
return
- return VirtCLIParser._parse(self, opts, inst)
+ return VirtCLIParser._parse(self, inst)
_add_device_address_args(_ParserChar)
@@ -2302,19 +2339,27 @@ _ParserChar.add_arg("source_mode", "mode")
class ParserSerial(_ParserChar):
+ cli_arg_name = "serial"
objclass = VirtualSerialDevice
+_register_virt_parser(ParserSerial)
class ParserParallel(_ParserChar):
+ cli_arg_name = "parallel"
objclass = VirtualParallelDevice
+_register_virt_parser(ParserParallel)
class ParserChannel(_ParserChar):
+ cli_arg_name = "channel"
objclass = VirtualChannelDevice
+_register_virt_parser(ParserChannel)
class ParserConsole(_ParserChar):
+ cli_arg_name = "console"
objclass = VirtualConsoleDevice
+_register_virt_parser(ParserConsole)
########################
@@ -2322,9 +2367,11 @@ class ParserConsole(_ParserChar):
########################
class ParserFilesystem(VirtCLIParser):
+ cli_arg_name = "filesystem"
objclass = VirtualFilesystem
remove_first = ["source", "target"]
+_register_virt_parser(ParserFilesystem)
_add_device_address_args(ParserFilesystem)
ParserFilesystem.add_arg("type", "type")
ParserFilesystem.add_arg("accessmode", "accessmode", aliases=["mode"])
@@ -2337,11 +2384,12 @@ ParserFilesystem.add_arg("target", "target")
###################
class ParserVideo(VirtCLIParser):
+ cli_arg_name = "video"
objclass = VirtualVideoDevice
remove_first = "model"
- def _parse(self, opts, inst):
- ret = VirtCLIParser._parse(self, opts, inst)
+ def _parse(self, inst):
+ ret = VirtCLIParser._parse(self, inst)
if inst.conn.is_qemu() and inst.accel3d:
if inst.model != "virtio":
@@ -2354,6 +2402,7 @@ class ParserVideo(VirtCLIParser):
return ret
+_register_virt_parser(ParserVideo)
_add_device_address_args(ParserVideo)
ParserVideo.add_arg("model", "model", ignore_default=True)
ParserVideo.add_arg("accel3d", "accel3d", is_onoff=True)
@@ -2368,15 +2417,17 @@ ParserVideo.add_arg("vgamem", "vgamem")
###################
class ParserSound(VirtCLIParser):
+ cli_arg_name = "sound"
objclass = VirtualAudio
remove_first = "model"
- def _parse(self, opts, inst):
- if opts.fullopts == "none":
+ def _parse(self, inst):
+ if self.optstr == "none":
self.guest.skip_default_sound = True
return
- return VirtCLIParser._parse(self, opts, inst)
+ return VirtCLIParser._parse(self, inst)
+_register_virt_parser(ParserSound)
_add_device_address_args(ParserSound)
ParserSound.add_arg("model", "model", ignore_default=True)
@@ -2386,6 +2437,7 @@ ParserSound.add_arg("model", "model", ignore_default=True)
#####################
class ParserHostdev(VirtCLIParser):
+ cli_arg_name = "hostdev"
objclass = VirtualHostDevice
remove_first = "name"
@@ -2401,6 +2453,7 @@ class ParserHostdev(VirtCLIParser):
nodedev = NodeDevice.lookupNodedevFromString(inst.conn, val)
return nodedev.compare_to_hostdev(inst)
+_register_virt_parser(ParserHostdev)
_add_device_address_args(ParserHostdev)
ParserHostdev.add_arg(None, "name",
cb=ParserHostdev.set_name_cb,
@@ -2411,66 +2464,12 @@ ParserHostdev.add_arg("rom_bar", "rom_bar", is_onoff=True)
###########################
-# Register parser classes #
+# Public virt parser APIs #
###########################
-def build_parser_map(options):
- """
- Build a dictionary with mapping of cli-name->parserinstance, so
- --vcpus -> ParserVCPU object.
- """
- parsermap = {}
- def register_parser(cli_arg_name, parserclass):
- if not hasattr(options, cli_arg_name):
- raise RuntimeError("programming error: cliname=%s class=%s" %
- (parserobj.cli_arg_name, parserclass))
- parserclass.cli_arg_name = cli_arg_name
- parserobj = parserclass()
- parsermap[parserobj.cli_arg_name] = parserobj
-
- register_parser("metadata", ParserMetadata)
- register_parser("events", ParserEvents)
- register_parser("resource", ParserResource)
- register_parser("memory", ParserMemory)
- register_parser("memtune", ParserMemorytune)
- register_parser("vcpus", ParserVCPU)
- register_parser("cpu", ParserCPU)
- register_parser("numatune", ParserNumatune)
- register_parser("blkiotune", ParserBlkiotune)
- register_parser("memorybacking", ParserMemorybacking)
- register_parser("idmap", ParserIdmap)
- register_parser("boot", ParserBoot)
- register_parser("security", ParserSecurity)
- register_parser("features", ParserFeatures)
- register_parser("clock", ParserClock)
- register_parser("pm", ParserPM)
- register_parser("disk", ParserDisk)
- register_parser("network", ParserNetwork)
- register_parser("graphics", ParserGraphics)
- register_parser("controller", ParserController)
- register_parser("input", ParserInput)
- 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("sound", ParserSound)
- register_parser("hostdev", ParserHostdev)
- register_parser("panic", ParserPanic)
-
- return parsermap
-
-
-def parse_option_strings(parsermap, options, guest, instlist, update=False):
+def parse_option_strings(options, guest, instlist, update=False):
"""
- Iterate over the parsermap, and launch the associated parser
+ Iterate over VIRT_PARSERS, and launch the associated parser
function for every value that was filled in on 'options', which
came from argparse/the command line.
@@ -2481,34 +2480,38 @@ def parse_option_strings(parsermap, options, guest, instlist, update=False):
instlist = [None]
ret = []
- for cli_arg_name in dir(options):
- if cli_arg_name not in parsermap:
+ for parserclass in VIRT_PARSERS:
+ optlist = util.listify(getattr(options, parserclass.cli_arg_name))
+ if not optlist:
continue
- optstr = getattr(options, cli_arg_name)
- if optstr is None:
- continue
+ for inst in instlist:
+ if inst and optlist:
+ # If an object is passed in, we are updating it in place, and
+ # only use the last command line occurrence, eg. from virt-xml
+ optlist = [optlist[-1]]
- for inst in util.listify(instlist):
- parseret = parsermap[cli_arg_name].parse(
- guest, optstr, inst, validate=not update)
- ret += util.listify(parseret)
+ for optstr in optlist:
+ parserobj = parserclass(guest, optstr)
+ parseret = parserobj.parse(inst, validate=not update)
+ ret += util.listify(parseret)
return ret
-def check_option_introspection(options, parsermap):
+def check_option_introspection(options):
"""
Check if the user requested option introspection with ex: '--disk=?'
"""
ret = False
- for cli_arg_name in dir(options):
- if cli_arg_name not in parsermap:
+ for parserclass in VIRT_PARSERS:
+ optlist = util.listify(getattr(options, parserclass.cli_arg_name))
+ if not optlist:
continue
- for optstr in util.listify(getattr(options, cli_arg_name)):
+ for optstr in optlist:
if optstr == "?" or optstr == "help":
- parsermap[cli_arg_name].print_introspection()
+ parserclass.print_introspection()
ret = True
return ret