From cff08223baacc938be2edd770dcddbbc2a265622 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Tue, 9 Dec 2014 08:22:51 -0500 Subject: [PATCH] util: Move uri_split to its own URISplit class Does what uri_split did, but wraps it all up in an object that makes handling the data easier, and makes it easy to extend. --- virtManager/connection.py | 52 ++++++------------- virtManager/manager.py | 19 +++---- virtManager/migrate.py | 26 ++-------- virtinst/__init__.py | 1 + virtinst/connection.py | 49 ++++++------------ virtinst/uri.py | 105 ++++++++++++++++++++++++++++++++++++++ virtinst/util.py | 35 ------------- 7 files changed, 154 insertions(+), 133 deletions(-) create mode 100644 virtinst/uri.py diff --git a/virtManager/connection.py b/virtManager/connection.py index 91d3a13bc..645823ce9 100644 --- a/virtManager/connection.py +++ b/virtManager/connection.py @@ -22,7 +22,6 @@ from gi.repository import GObject import logging import os -import re import socket import time import traceback @@ -359,36 +358,17 @@ class vmmConnection(vmmGObject): @show_kvm: Show hv as QEMU/KVM. Only works if connection is active though """ - def match_whole_string(orig, reg): - match = re.match(reg, orig) - if not match: - return False + uriinfo = virtinst.URISplit(self.get_uri()) - return ((match.end() - match.start()) == len(orig)) - - def is_ip_addr(orig): - return match_whole_string(orig, "[0-9.]+") - - (scheme, username, hostname, - path, ignore, ignore) = util.uri_split(self.get_uri()) - hostname, port = self.get_backend().get_uri_host_port() - port = port or "" - - hv = "" rest = "" - transport = "" - port = "" - if scheme.count("+"): - transport = scheme.split("+")[1] - scheme = scheme.split("+")[0] + if uriinfo.hostname: + hostname = uriinfo.hostname + if show_user and uriinfo.username: + hostname = uriinfo.username + "@" + hostname + if uriinfo.port: + hostname += ":" + uriinfo.port - if hostname: - if show_user and username: - hostname = username + "@" + hostname - if port: - hostname += ":" + port - - if shorthost and not is_ip_addr(hostname): + if shorthost and not uriinfo.host_is_ipv4_string: rest = hostname.split(".")[0] else: rest = hostname @@ -411,21 +391,21 @@ class vmmConnection(vmmGObject): "xenapi" : "XenAPI", } - hv = scheme - if scheme in pretty_map: - hv = pretty_map[scheme] + hv = uriinfo.scheme + if hv in pretty_map: + hv = pretty_map[hv] if hv == "QEMU" and show_kvm and self.caps.is_kvm_available(): hv += "/KVM" - if show_transport and transport: - hv += "+" + transport + if show_transport and uriinfo.transport: + hv += "+" + uriinfo.transport - if path and path != "/system" and path != "/": - if path == "/session": + if uriinfo.path and uriinfo.path != "/system" and uriinfo.path != "/": + if uriinfo.path == "/session": hv += " Usermode" else: - hv += " %s" % os.path.basename(path) + hv += " %s" % os.path.basename(uriinfo.path) if self._backend.fake_name(): hv = self._backend.fake_name() diff --git a/virtManager/manager.py b/virtManager/manager.py index 8f362bf85..bfff04fe7 100644 --- a/virtManager/manager.py +++ b/virtManager/manager.py @@ -26,6 +26,7 @@ from gi.repository import Gdk from gi.repository import GdkPixbuf from virtinst import util +from virtinst import URISplit from . import vmmenu from . import uiutil @@ -703,8 +704,8 @@ class vmmManager(vmmGObjectUI): connrows = [row for row in self.rows.values() if row[ROW_IS_CONN]] for row in connrows: conn = row[ROW_HANDLE] - connsplit = util.uri_split(conn.get_uri()) - scheme = connsplit[0] + connuriinfo = URISplit(conn.get_uri()) + scheme = connuriinfo.scheme show_transport = False show_user = False @@ -713,15 +714,15 @@ class vmmManager(vmmGObjectUI): checkconn = checkrow[ROW_HANDLE] if conn is checkconn: continue - checkconnsplit = util.uri_split(checkconn.get_uri()) - checkscheme = checkconnsplit[0] + checkuriinfo = URISplit(checkconn.get_uri()) + checkscheme = checkuriinfo.scheme - if ((scheme.split("+")[0] == checkscheme.split("+")[0]) and - connsplit[2] == checkconnsplit[2] and - connsplit[3] == checkconnsplit[3]): + if (scheme == checkscheme and + connuriinfo.hostname == checkuriinfo.hostname and + connuriinfo.path == checkuriinfo.path): show_transport = True - if ("+" in scheme and "+" in checkscheme and - scheme.split("+")[1] == checkscheme.split("+")[1]): + if (connuriinfo.transport and + connuriinfo.transport == checkuriinfo.transport): show_user = True newname = conn.get_pretty_desc( diff --git a/virtManager/migrate.py b/virtManager/migrate.py index 980b75dad..87e784373 100644 --- a/virtManager/migrate.py +++ b/virtManager/migrate.py @@ -28,6 +28,7 @@ from gi.repository import Gtk import libvirt from virtinst import util +from virtinst import URISplit from . import uiutil from .baseclass import vmmGObjectUI @@ -35,18 +36,6 @@ from .asyncjob import vmmAsyncJob from .domain import vmmDomain -def uri_join(uri_tuple): - scheme, user, host, path, query, fragment = uri_tuple - - user = (user and (user + "@") or "") - host = host or "" - path = path or "/" - query = (query and ("?" + query) or "") - fragment = (fragment and ("#" + fragment) or "") - - return "%s://%s%s%s%s%s" % (scheme, user, host, path, fragment, query) - - class vmmMigrateDialog(vmmGObjectUI): def __init__(self, vm, engine): vmmGObjectUI.__init__(self, "migrate.ui", "vmm-migrate") @@ -267,16 +256,11 @@ class vmmMigrateDialog(vmmGObjectUI): return self.edit_uri(srcuri, desthost, None) def edit_uri(self, uri, hostname, port): - split = list(util.uri_split(uri)) + uriinfo = URISplit(uri) - hostname = hostname or split[2] - if port: - if hostname.count(":"): - hostname = hostname.split(":")[0] - hostname += ":%s" % port - - split[2] = hostname - return uri_join(tuple(split)) + uriinfo.hostname = hostname or uriinfo.hostname + uriinfo.port = port or uriinfo.port + return uriinfo.rebuild_uri() def build_migrate_uri(self, destconn, srcuri): conn = self.conn diff --git a/virtinst/__init__.py b/virtinst/__init__.py index e41605453..aaf6eeea8 100644 --- a/virtinst/__init__.py +++ b/virtinst/__init__.py @@ -36,6 +36,7 @@ stable_defaults = _cliconfig.stable_defaults from . import util from virtinst import support +from virtinst.uri import URISplit from virtinst.osxml import OSXML from virtinst.domainfeatures import DomainFeatures diff --git a/virtinst/connection.py b/virtinst/connection.py index 73b3494bb..988b77303 100644 --- a/virtinst/connection.py +++ b/virtinst/connection.py @@ -26,6 +26,7 @@ from . import pollhelpers from . import support from . import util from . import capabilities as CapabilitiesParser +from . import URISplit from .cli import VirtOptionString from .guest import Guest from .nodedev import NodeDevice @@ -81,7 +82,7 @@ class VirtualConnection(object): self._test_opts = {} self._libvirtconn = None - self._urisplits = util.uri_split(self._uri) + self._urisplits = URISplit(self._uri) self._caps = None self._support_cache = {} @@ -162,7 +163,7 @@ class VirtualConnection(object): self._libvirtconn = conn if not self._open_uri: self._uri = self._libvirtconn.getURI() - self._urisplits = util.uri_split(self._uri) + self._urisplits = URISplit(self._uri) def set_keep_alive(self, interval, count): if hasattr(self._libvirtconn, "setKeepAlive"): @@ -335,56 +336,40 @@ class VirtualConnection(object): def is_remote(self): return (hasattr(self, "_virtinst__fake_conn_remote") or - self._urisplits[2]) + self._urisplits.hostname) def get_uri_hostname(self): - return self._urisplits[2] or "localhost" + return self._urisplits.hostname or "localhost" def get_uri_host_port(self): - hostname = self.get_uri_hostname() - port = None - - if hostname.startswith("[") and "]" in hostname: - if "]:" in hostname: - hostname, port = hostname.rsplit(":", 1) - hostname = "".join(hostname[1:].split("]", 1)) - elif ":" in hostname: - hostname, port = hostname.split(":", 1) - return hostname, port + return self.get_uri_hostname(), self._urisplits.port def get_uri_transport(self): - scheme = self._urisplits[0] - username = self._urisplits[1] - offset = scheme.find("+") - if offset != -1: - return [scheme[offset + 1:], username] + if self._urisplits.transport: + return [self._urisplits.transport, self._urisplits.username] return [None, None] def get_uri_driver(self): - scheme = self._urisplits[0] - offset = scheme.find("+") - if offset > 0: - return scheme[:offset] - return scheme + return self._urisplits.scheme def is_session_uri(self): - return self._urisplits[3] == "/session" + return self._urisplits.path == "/session" def is_qemu(self): - return self._urisplits[0].startswith("qemu") + return self._urisplits.scheme.startswith("qemu") def is_qemu_system(self): - return (self.is_qemu() and self._urisplits[3] == "/system") + return (self.is_qemu() and self._urisplits.path == "/system") def is_qemu_session(self): return (self.is_qemu() and self.is_session_uri()) def is_test(self): - return self._urisplits[0].startswith("test") + return self._urisplits.scheme.startswith("test") def is_xen(self): - return (self._urisplits[0].startswith("xen") or - self._urisplits[0].startswith("libxl")) + return (self._urisplits.scheme.startswith("xen") or + self._urisplits.scheme.startswith("libxl")) def is_lxc(self): - return self._urisplits[0].startswith("lxc") + return self._urisplits.scheme.startswith("lxc") def is_openvz(self): - return self._urisplits[0].startswith("openvz") + return self._urisplits.scheme.startswith("openvz") def is_container(self): return self.is_lxc() or self.is_openvz() diff --git a/virtinst/uri.py b/virtinst/uri.py new file mode 100644 index 000000000..c76f7ffb0 --- /dev/null +++ b/virtinst/uri.py @@ -0,0 +1,105 @@ +# +# Copyright 2014 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA. +# + +import re + + +class URISplit(object): + """ + Parse an arbitrary URI into its individual parts + """ + def __init__(self, uri): + self.uri = uri + + (self.scheme, self.username, self.hostname, + self.path, self.query, self.fragment) = self._split(self.uri) + + self.transport = '' + if "+" in self.scheme: + self.scheme, self.transport = self.scheme.rsplit("+", 1) + + self.port = '' + self.is_ipv6 = False + if self.hostname.startswith("[") and "]" in self.hostname: + if "]:" in self.hostname: + self.hostname, self.port = self.hostname.rsplit(":", 1) + self.hostname = "".join(self.hostname[1:].split("]", 1)) + self.is_ipv6 = True + elif ":" in self.hostname: + self.hostname, self.port = self.hostname.split(":", 1) + + self.host_is_ipv4_string = bool(re.match(self.hostname, "[0-9.]+")) + + + ################### + # Private helpers # + ################### + + def _split(self, uri): + def splitnetloc(url, start=0): + for c in '/?#': # the order is important! + delim = url.find(c, start) + if delim >= 0: + break + else: + delim = len(url) + return url[start:delim], url[delim:] + + username = netloc = query = fragment = '' + i = uri.find(":") + if i > 0: + scheme, uri = uri[:i].lower(), uri[i + 1:] + if uri[:2] == '//': + netloc, uri = splitnetloc(uri, 2) + offset = netloc.find("@") + if offset > 0: + username = netloc[0:offset] + netloc = netloc[offset + 1:] + if '#' in uri: + uri, fragment = uri.split('#', 1) + if '?' in uri: + uri, query = uri.split('?', 1) + else: + scheme = uri.lower() + return scheme, username, netloc, uri, query, fragment + + + ############## + # Public API # + ############## + + def rebuild_uri(self): + ret = self.scheme + if self.transport: + ret += "+" % self.transport + ret += "://" + if self.username: + ret += self.username + "@" + if self.hostname: + host = self.hostname + if self.is_ipv6: + host = "[%s]" % self.hostname + ret += host + if self.port: + ret += ":" + self.port + if self.query: + ret += "?" + self.query + if self.fragment: + ret += "#" + self.fragment + return ret diff --git a/virtinst/util.py b/virtinst/util.py index a29d730a1..54e09e9d0 100644 --- a/virtinst/util.py +++ b/virtinst/util.py @@ -365,41 +365,6 @@ def xml_escape(xml): return xml -def uri_split(uri): - """ - Parse a libvirt hypervisor uri into it's individual parts - @returns: tuple of the form (scheme (ex. 'qemu', 'xen+ssh'), username, - hostname, path (ex. '/system'), query, - fragment) - """ - def splitnetloc(url, start=0): - for c in '/?#': # the order is important! - delim = url.find(c, start) - if delim >= 0: - break - else: - delim = len(url) - return url[start:delim], url[delim:] - - username = netloc = query = fragment = '' - i = uri.find(":") - if i > 0: - scheme, uri = uri[:i].lower(), uri[i + 1:] - if uri[:2] == '//': - netloc, uri = splitnetloc(uri, 2) - offset = netloc.find("@") - if offset > 0: - username = netloc[0:offset] - netloc = netloc[offset + 1:] - if '#' in uri: - uri, fragment = uri.split('#', 1) - if '?' in uri: - uri, query = uri.split('?', 1) - else: - scheme = uri.lower() - return scheme, username, netloc, uri, query, fragment - - def is_error_nosupport(err): """ Check if passed exception indicates that the called libvirt command isn't