mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-02-25 18:55:27 -06:00
console: Track graphics conn parameters in a class
So we don't need to pass around large argument lists.
This commit is contained in:
parent
86f0c134ca
commit
a455ba72b6
@ -55,6 +55,51 @@ def has_property(obj, setting):
|
||||
return False
|
||||
return True
|
||||
|
||||
class ConnectionInfo(object):
|
||||
"""
|
||||
Holds all the bits needed to make a connection to a graphical console
|
||||
"""
|
||||
def __init__(self, conn, gdev):
|
||||
self.gtype = gdev.type
|
||||
self.gport = gdev.port and str(gdev.port) or None
|
||||
self.gsocket = gdev.socket
|
||||
self.gaddr = gdev.listen or "127.0.0.1"
|
||||
|
||||
self.transport, self.connuser = conn.get_transport()
|
||||
self._connhost = conn.get_uri_hostname() or "127.0.0.1"
|
||||
|
||||
self._connport = None
|
||||
if self._connhost.count(":"):
|
||||
self._connhost, self._connport = self._connhost.split(":", 1)
|
||||
|
||||
def need_tunnel(self):
|
||||
if self.gaddr is not "127.0.0.1":
|
||||
return False
|
||||
|
||||
return self.transport in ["ssh", "ext"]
|
||||
|
||||
def get_conn_host(self):
|
||||
host = self._connhost
|
||||
port = self._connport
|
||||
|
||||
if not self.need_tunnel():
|
||||
port = self.gport
|
||||
if self.gaddr != "0.0.0.0":
|
||||
host = self.gaddr
|
||||
|
||||
return host, port
|
||||
|
||||
def logstring(self):
|
||||
return ("proto=%s trans=%s connhost=%s connuser=%s "
|
||||
"connport=%s gaddr=%s gport=%s gsocket=%s" %
|
||||
(self.gtype, self.transport, self._connhost, self.connuser,
|
||||
self._connport, self.gaddr, self.gport, self.gsocket))
|
||||
def console_active(self):
|
||||
if self.gsocket:
|
||||
return True
|
||||
if not self.gport:
|
||||
return False
|
||||
return int(self.gport) == -1
|
||||
|
||||
class Tunnel(object):
|
||||
def __init__(self):
|
||||
@ -62,19 +107,21 @@ class Tunnel(object):
|
||||
self.errfd = None
|
||||
self.pid = None
|
||||
|
||||
def open(self, connhost, connuser, connport, gaddr, gport, gsocket):
|
||||
def open(self, ginfo):
|
||||
if self.outfd is not None:
|
||||
return -1
|
||||
|
||||
host, port = ginfo.get_conn_host()
|
||||
|
||||
# Build SSH cmd
|
||||
argv = ["ssh", "ssh"]
|
||||
if connport:
|
||||
argv += ["-p", str(connport)]
|
||||
if port:
|
||||
argv += ["-p", str(port)]
|
||||
|
||||
if connuser:
|
||||
argv += ['-l', connuser]
|
||||
if ginfo.connuser:
|
||||
argv += ['-l', ginfo.connuser]
|
||||
|
||||
argv += [connhost]
|
||||
argv += [host]
|
||||
|
||||
# Build 'nc' command run on the remote host
|
||||
#
|
||||
@ -87,10 +134,10 @@ class Tunnel(object):
|
||||
# Fedora's 'nc' doesn't have this option, and apparently defaults
|
||||
# to the desired behavior.
|
||||
#
|
||||
if gsocket:
|
||||
nc_params = "-U %s" % gsocket
|
||||
if ginfo.gsocket:
|
||||
nc_params = "-U %s" % ginfo.gsocket
|
||||
else:
|
||||
nc_params = "%s %s" % (gaddr, gport)
|
||||
nc_params = "%s %s" % (ginfo.gaddr, ginfo.gport)
|
||||
|
||||
nc_cmd = (
|
||||
"""nc -q 2>&1 | grep "requires an argument" >/dev/null;"""
|
||||
@ -171,22 +218,14 @@ class Tunnel(object):
|
||||
|
||||
return errout
|
||||
|
||||
|
||||
class Tunnels(object):
|
||||
def __init__(self, connhost, connuser, connport, gaddr, gport, gsocket):
|
||||
self.connhost = connhost
|
||||
self.connuser = connuser
|
||||
self.connport = connport
|
||||
|
||||
self.gaddr = gaddr
|
||||
self.gport = gport
|
||||
self.gsocket = gsocket
|
||||
def __init__(self, ginfo):
|
||||
self.ginfo = ginfo
|
||||
self._tunnels = []
|
||||
|
||||
def open_new(self):
|
||||
t = Tunnel()
|
||||
fd = t.open(self.connhost, self.connuser, self.connport,
|
||||
self.gaddr, self.gport, self.gsocket)
|
||||
fd = t.open(self.ginfo)
|
||||
self._tunnels.append(t)
|
||||
return fd
|
||||
|
||||
@ -262,7 +301,10 @@ class Viewer(vmmGObject):
|
||||
logging.debug("Error when getting the grab keys combination: %s",
|
||||
str(e))
|
||||
|
||||
def open_host(self, host, user, port, socketpath, password=None):
|
||||
def open_host(self, ginfo, password=None):
|
||||
raise NotImplementedError()
|
||||
|
||||
def open_fd(self, fd, password=None):
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_desktop_resolution(self):
|
||||
@ -366,29 +408,31 @@ class VNCViewer(Viewer):
|
||||
def is_open(self):
|
||||
return self.display.is_open()
|
||||
|
||||
def open_host(self, host, user, port, socketpath, password=None):
|
||||
ignore = password
|
||||
ignore = user
|
||||
def open_host(self, ginfo, password=None):
|
||||
host, port = ginfo.get_conn_host()
|
||||
|
||||
if not socketpath:
|
||||
if not ginfo.gsocket:
|
||||
logging.debug("VNC connection to %s:%s", host, port)
|
||||
self.display.open_host(host, port)
|
||||
return
|
||||
|
||||
logging.debug("VNC connecting to socket=%s", ginfo.gsocket)
|
||||
try:
|
||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
sock.connect(socketpath)
|
||||
sock.connect(ginfo.gsocket)
|
||||
self.sockfd = sock
|
||||
except Exception, e:
|
||||
raise RuntimeError(_("Error opening socket path '%s': %s") %
|
||||
(socketpath, e))
|
||||
(ginfo.gsocket, e))
|
||||
|
||||
fd = self.sockfd.fileno()
|
||||
if fd < 0:
|
||||
raise RuntimeError((_("Error opening socket path '%s'") %
|
||||
socketpath) + " fd=%s" % fd)
|
||||
ginfo.gsocket) + " fd=%s" % fd)
|
||||
self.open_fd(fd)
|
||||
|
||||
def open_fd(self, fd):
|
||||
def open_fd(self, fd, password=None):
|
||||
ignore = password
|
||||
self.display.open_fd(fd)
|
||||
|
||||
def set_credential_username(self, cred):
|
||||
@ -482,8 +526,9 @@ class SpiceViewer(Viewer):
|
||||
return None
|
||||
return self.display_channel.get_properties("width", "height")
|
||||
|
||||
def open_host(self, host, user, port, socketpath, password=None):
|
||||
ignore = socketpath
|
||||
def open_host(self, ginfo, password=None):
|
||||
host, port = ginfo.get_conn_host()
|
||||
user = ginfo.connuser
|
||||
|
||||
uri = "spice://"
|
||||
uri += (user and str(user) or "")
|
||||
@ -1046,35 +1091,37 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
self.schedule_retry()
|
||||
return
|
||||
|
||||
ginfo = None
|
||||
try:
|
||||
(protocol, transport,
|
||||
connhost, connuser, connport,
|
||||
gaddr, gport, gsocket) = self.vm.get_graphics_console()
|
||||
gdevs = self.vm.get_graphics_devices()
|
||||
gdev = gdevs and gdevs[0] or None
|
||||
if gdev:
|
||||
ginfo = ConnectionInfo(self.vm.conn, gdev)
|
||||
except Exception, e:
|
||||
# We can fail here if VM is destroyed: xen is a bit racy
|
||||
# and can't handle domain lookups that soon after
|
||||
logging.exception("Getting graphics console failed: %s", str(e))
|
||||
return
|
||||
|
||||
if protocol is None:
|
||||
if ginfo is None:
|
||||
logging.debug("No graphics configured for guest")
|
||||
self.activate_unavailable_page(
|
||||
_("Graphical console not configured for guest"))
|
||||
return
|
||||
|
||||
if protocol not in self.config.embeddable_graphics():
|
||||
if ginfo.gtype not in self.config.embeddable_graphics():
|
||||
logging.debug("Don't know how to show graphics type '%s' "
|
||||
"disabling console page", protocol)
|
||||
"disabling console page", ginfo.gtype)
|
||||
|
||||
msg = (_("Cannot display graphical console type '%s'")
|
||||
% protocol)
|
||||
if protocol == "spice":
|
||||
% ginfo.gtype)
|
||||
if ginfo.gtype == "spice":
|
||||
msg += ":\n %s" % self.config.get_spice_error()
|
||||
|
||||
self.activate_unavailable_page(msg)
|
||||
return
|
||||
|
||||
if (gport == -1 and not gsocket):
|
||||
if ginfo.console_active():
|
||||
self.activate_unavailable_page(
|
||||
_("Graphical console is not yet active for guest"))
|
||||
self.schedule_retry()
|
||||
@ -1083,35 +1130,26 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
self.activate_unavailable_page(
|
||||
_("Connecting to graphical console for guest"))
|
||||
|
||||
logging.debug("Starting connect process for "
|
||||
"proto=%s trans=%s connhost=%s connuser=%s "
|
||||
"connport=%s gaddr=%s gport=%s gsocket=%s",
|
||||
protocol, transport, connhost, connuser, connport,
|
||||
gaddr, gport, gsocket)
|
||||
logging.debug("Starting connect process for %s", ginfo.logstring())
|
||||
try:
|
||||
if protocol == "vnc":
|
||||
if ginfo.gtype == "vnc":
|
||||
self.viewer = VNCViewer(self)
|
||||
self.widget("console-vnc-viewport").add(self.viewer.display)
|
||||
self.viewer.init_widget()
|
||||
elif protocol == "spice":
|
||||
elif ginfo.gtype == "spice":
|
||||
self.viewer = SpiceViewer(self)
|
||||
|
||||
self.set_enable_accel()
|
||||
|
||||
if transport in ("ssh", "ext"):
|
||||
if ginfo.need_tunnel():
|
||||
if self.tunnels:
|
||||
# Tunnel already open, no need to continue
|
||||
return
|
||||
|
||||
self.tunnels = Tunnels(connhost, connuser, connport,
|
||||
gaddr, gport, gsocket)
|
||||
fd = self.tunnels.open_new()
|
||||
if fd >= 0:
|
||||
self.viewer.open_fd(fd)
|
||||
|
||||
self.tunnels = Tunnels(ginfo)
|
||||
self.viewer.open_fd(self.tunnels.open_new())
|
||||
else:
|
||||
self.viewer.open_host(connhost, connuser,
|
||||
str(gport), gsocket)
|
||||
self.viewer.open_host(ginfo)
|
||||
|
||||
except Exception, e:
|
||||
logging.exception("Error connection to graphical console")
|
||||
|
@ -936,48 +936,6 @@ class vmmDomain(vmmLibvirtObject):
|
||||
devlist += filter(lambda x: x.virtual_device_type == "console", devs)
|
||||
return devlist
|
||||
|
||||
def get_graphics_console(self):
|
||||
gdevs = self.get_graphics_devices()
|
||||
connhost = self.conn.get_uri_hostname()
|
||||
transport, connuser = self.conn.get_transport()
|
||||
|
||||
gdev = gdevs and gdevs[0] or None
|
||||
gtype = None
|
||||
gport = None
|
||||
gaddr = None
|
||||
gsocket = None
|
||||
|
||||
if gdev:
|
||||
gport = gdev.port
|
||||
if gport != None:
|
||||
gport = int(gport)
|
||||
gtype = gdev.type
|
||||
gaddr = "127.0.0.1"
|
||||
if gdev.listen != None:
|
||||
gaddr = gdev.listen
|
||||
connhost = gaddr
|
||||
if gport != None:
|
||||
connhost += ":"
|
||||
connhost += str(gport)
|
||||
gsocket = gdev.socket
|
||||
|
||||
if connhost == None:
|
||||
# Force use of 127.0.0.1, because some (broken) systems don't
|
||||
# reliably resolve 'localhost' into 127.0.0.1, either returning
|
||||
# the public IP, or an IPv6 addr. Neither work since QEMU only
|
||||
# listens on 127.0.0.1 for VNC.
|
||||
connhost = "127.0.0.1"
|
||||
|
||||
# Parse URI port
|
||||
connport = None
|
||||
if connhost.count(":"):
|
||||
connhost, connport = connhost.split(":", 1)
|
||||
|
||||
return [gtype, transport,
|
||||
connhost, connuser, connport,
|
||||
gaddr, gport, gsocket]
|
||||
|
||||
|
||||
def _build_device_list(self, device_type,
|
||||
refresh_if_necc=True, inactive=False):
|
||||
guest = self._get_guest(refresh_if_necc=refresh_if_necc,
|
||||
|
Loading…
Reference in New Issue
Block a user