diff --git a/tests/xmlparse.py b/tests/xmlparse.py index 13356e819..047410263 100644 --- a/tests/xmlparse.py +++ b/tests/xmlparse.py @@ -517,27 +517,27 @@ class XMLParseTest(unittest.TestCase): check = self._make_checker(serial1) check("type", "null", "udp") - check("bind_host", None, "example.com") - check("bind_service", None, 66) - check("connect_host", None, "example.com.uk") - check("connect_service", None, 77) + check("source.bind_host", None, "example.com") + check("source.bind_service", None, 66) + check("source.connect_host", None, "example.com.uk") + check("source.connect_service", None, 77) check = self._make_checker(serial2) check("type", "tcp") check("protocol", "telnet", "raw") - check("source_mode", "bind", "connect") + check("source.mode", "bind", "connect") check = self._make_checker(parallel1) - check("source_mode", "bind") - check("source_path", "/tmp/foobar", None) + check("source.mode", "bind") + check("source.path", "/tmp/foobar", None) check("type", "unix", "pty") check = self._make_checker(parallel2) check("type", "udp") - check("bind_service", 1111, 1357) - check("bind_host", "my.bind.host", "my.foo.host") - check("connect_service", 2222, 7777) - check("connect_host", "my.source.host", "source.foo.host") + check("source.bind_service", 1111, 1357) + check("source.bind_host", "my.bind.host", "my.foo.host") + check("source.connect_service", 2222, 7777) + check("source.connect_host", "my.source.host", "source.foo.host") check = self._make_checker(console1) check("type", "pty") @@ -545,8 +545,8 @@ class XMLParseTest(unittest.TestCase): check = self._make_checker(console2) check("type", "file") - check("source_path", "/tmp/foo.img", None) - check("source_path", None, "/root/foo") + check("source.path", "/tmp/foo.img", None) + check("source.path", None, "/root/foo") check("target_type", "virtio") check("target_state", None, "connected") @@ -563,7 +563,7 @@ class XMLParseTest(unittest.TestCase): check = self._make_checker(channel3) check("type", "spiceport") - check("source_channel", "org.spice-space.webdav.0", "test.1") + check("source.channel", "org.spice-space.webdav.0", "test.1") check("target_type", "virtio") check("target_name", "org.spice-space.webdav.0", "test.2") self.assertEqual(channel3.get_xml_id(), "./devices/channel[3]") diff --git a/virtManager/addhardware.py b/virtManager/addhardware.py index 82332cc5d..da51b3f10 100644 --- a/virtManager/addhardware.py +++ b/virtManager/addhardware.py @@ -1337,8 +1337,8 @@ class vmmAddHardware(vmmGObjectUI): dev = char_class(self.conn.get_backend()) dev.type = devtype - dev.source_path = source_path - dev.source_channel = source_channel + dev.source.path = source_path + dev.source.channel = source_channel dev.target_name = target_name dev.target_type = target_type return dev diff --git a/virtManager/details.py b/virtManager/details.py index c3f8915b8..c99c5dde8 100644 --- a/virtManager/details.py +++ b/virtManager/details.py @@ -2388,14 +2388,15 @@ class vmmDetails(vmmGObjectUI): return ret connect_str = build_host_str( - chardev.connect_host, chardev.connect_service) - bind_str = build_host_str(chardev.bind_host, chardev.bind_service) + chardev.source.connect_host, chardev.source.connect_service) + bind_str = build_host_str( + chardev.source.bind_host, chardev.source.bind_service) target_type = show_target_type and chardev.target_type or None # Device type specific properties, only show if apply to the cur dev show_ui("char-source-host", connect_str) show_ui("char-bind-host", bind_str) - show_ui("char-source-path", chardev.source_path) + show_ui("char-source-path", chardev.source.path) show_ui("char-target-type", target_type) show_ui("char-target-name", chardev.target_name) show_ui("char-target-state", chardev.target_state) diff --git a/virtManager/serialcon.py b/virtManager/serialcon.py index 12ec33b94..02976151a 100644 --- a/virtManager/serialcon.py +++ b/virtManager/serialcon.py @@ -303,7 +303,7 @@ class vmmSerialConsole(vmmGObject): devs = self.vm.get_serialcon_devices() for dev in devs: port = dev.get_xml_idx() - path = dev.source_path + path = dev.source.path if port == self.target_port: if path != self.lastpath: diff --git a/virtinst/cli.py b/virtinst/cli.py index 7fd0a457b..a01bc2471 100644 --- a/virtinst/cli.py +++ b/virtinst/cli.py @@ -3334,12 +3334,12 @@ class _ParserChar(VirtCLIParser): def set_host_cb(self, inst, val, virtarg): if ("bind_host" not in self.optdict and self.optdict.get("mode", None) == "bind"): - inst.set_friendly_bind(val) + inst.source.set_friendly_bind(val) else: - inst.set_friendly_connect(val) + inst.source.set_friendly_connect(val) def set_bind_cb(self, inst, val, virtarg): - inst.set_friendly_bind(val) + inst.source.set_friendly_bind(val) def set_target_cb(self, inst, val, virtarg): inst.set_friendly_target(val) @@ -3363,7 +3363,7 @@ class _ParserChar(VirtCLIParser): VirtCLIParser._init_class(**kwargs) cls.add_arg("char_type", "type") - cls.add_arg("path", "source_path") + cls.add_arg("path", "source.path") cls.add_arg("protocol", "protocol") cls.add_arg("target_type", "target_type") cls.add_arg("name", "target_name") @@ -3373,9 +3373,9 @@ class _ParserChar(VirtCLIParser): cb=cls.set_bind_cb) cls.add_arg("target_address", None, lookup_cb=None, cb=cls.set_target_cb) - cls.add_arg("mode", "source_mode") - cls.add_arg("source.master", "source_master") - cls.add_arg("source.slave", "source_slave") + cls.add_arg("mode", "source.mode") + cls.add_arg("source.master", "source.master") + cls.add_arg("source.slave", "source.slave") cls.add_arg("log.file", "log_file") cls.add_arg("log.append", "log_append", is_onoff=True) diff --git a/virtinst/cloner.py b/virtinst/cloner.py index 3132713c8..21a41c1d0 100644 --- a/virtinst/cloner.py +++ b/virtinst/cloner.py @@ -426,9 +426,9 @@ class Cloner(object): # new guest name for channel in self._guest.devices.channel: if (channel.type == DeviceChannel.TYPE_UNIX and - channel.target_name and channel.source_path and - channel.target_name in channel.source_path): - channel.source_path = None + channel.target_name and channel.source.path and + channel.target_name in channel.source.path): + channel.source.path = None if self._guest.os.nvram: self._prepare_nvram() diff --git a/virtinst/devices/char.py b/virtinst/devices/char.py index b9fca580d..6b4e5821e 100644 --- a/virtinst/devices/char.py +++ b/virtinst/devices/char.py @@ -5,7 +5,47 @@ # See the COPYING file in the top-level directory. from .device import Device -from ..xmlbuilder import XMLProperty +from ..xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty +from .. import util + + +def _set_host_helper(obj, hostparam, portparam, val): + def parse_host(val): + host, ignore, port = (val or "").partition(":") + return host or None, port or None + + host, port = parse_host(val) + if not host: + host = "127.0.0.1" + if host: + util.set_prop_path(obj, hostparam, host) + if port: + util.set_prop_path(obj, portparam, port) + + +class CharSource(XMLBuilder): + XML_NAME = "source" + _XML_PROP_ORDER = ["bind_host", "bind_service", + "mode", "connect_host", "connect_service", + "path", "channel"] + + def set_friendly_connect(self, val): + _set_host_helper(self, "connect_host", "connect_service", val) + def set_friendly_bind(self, val): + _set_host_helper(self, "bind_host", "bind_service", val) + + path = XMLProperty("./@path") + channel = XMLProperty("./@channel") + master = XMLProperty("./@master") + slave = XMLProperty("./@slave") + mode = XMLProperty("./@mode") + + # Convenience source helpers for setting connect/bind host and service + connect_host = XMLProperty("./../source[@mode='connect']/@host") + connect_service = XMLProperty( + "./../source[@mode='connect']/@service", is_int=True) + bind_host = XMLProperty("./../source[@mode='bind']/@host") + bind_service = XMLProperty("./../source[@mode='bind']/@service", is_int=True) class _DeviceChar(Device): @@ -93,40 +133,14 @@ class _DeviceChar(Device): return desc - def _set_host_helper(self, hostparam, portparam, val): - def parse_host(val): - host, ignore, port = (val or "").partition(":") - return host or None, port or None - - host, port = parse_host(val) - if not host: - host = "127.0.0.1" - if host: - setattr(self, hostparam, host) - if port: - setattr(self, portparam, port) - - def set_friendly_connect(self, val): - self._set_host_helper("connect_host", "connect_service", val) - def set_friendly_bind(self, val): - self._set_host_helper("bind_host", "bind_service", val) def set_friendly_target(self, val): - self._set_host_helper("target_address", "target_port", val) + _set_host_helper(self, "target_address", "target_port", val) - - _XML_PROP_ORDER = ["type", - "bind_host", "bind_service", - "source_mode", "connect_host", "connect_service", - "source_path", "source_channel", + _XML_PROP_ORDER = ["type", "source", "target_type", "target_name", "target_state"] type = XMLProperty("./@type") - - source_path = XMLProperty("./source/@path") - source_channel = XMLProperty("./source/@channel") - source_master = XMLProperty("./source/@master") - source_slave = XMLProperty("./source/@slave") - source_mode = XMLProperty("./source/@mode") + source = XMLChildProperty(CharSource, is_single=True) target_address = XMLProperty("./target/@address") target_port = XMLProperty("./target/@port", is_int=True) @@ -138,27 +152,15 @@ class _DeviceChar(Device): log_file = XMLProperty("./log/@file") log_append = XMLProperty("./log/@append", is_onoff=True) - # Convenience source helpers for setting connect/bind host and service - connect_host = XMLProperty("./source[@mode='connect']/@host") - connect_service = XMLProperty( - "./source[@mode='connect']/@service", is_int=True) - bind_host = XMLProperty("./source[@mode='bind']/@host") - bind_service = XMLProperty("./source[@mode='bind']/@service", is_int=True) - - - ####################### - # Remaining XML props # - ####################### - ################## # Default config # ################## def set_defaults(self, _guest): - if (not self.source_mode and + if (not self.source.mode and self.type in [self.TYPE_UNIX, self.TYPE_TCP]): - self.source_mode = "bind" + self.source.mode = "bind" if not self.target_type and self.DEVICE_TYPE == "channel": self.target_type = "virtio" if not self.target_name and self.type == self.TYPE_SPICEVMC: diff --git a/virtinst/xmlapi.py b/virtinst/xmlapi.py index 566c98fec..de5dc8248 100644 --- a/virtinst/xmlapi.py +++ b/virtinst/xmlapi.py @@ -59,7 +59,13 @@ class _XPath(object): """ def __init__(self, fullxpath): self.fullxpath = fullxpath - self.segments = [_XPathSegment(s) for s in self.fullxpath.split("/")] + self.segments = [] + for s in self.fullxpath.split("/"): + if s == "..": + # Resolve and flatten .. in xpaths + self.segments = self.segments[:-1] + continue + self.segments.append(_XPathSegment(s)) self.is_prop = self.segments[-1].is_prop self.propname = (self.is_prop and self.segments[-1].nodename or None)