506
501
argv += ['-l', username]
508
argv += [ server, "nc", vncaddr, str(vncport) ]
510
logging.debug("Creating SSH tunnel: %s" % argv)
512
fds = socket.socketpair()
505
# Build 'nc' command run on the remote host
507
# This ugly thing is a shell script to detect availability of
508
# the -q option for 'nc': debian and suse based distros need this
509
# flag to ensure the remote nc will exit on EOF, so it will go away
510
# when we close the VNC tunnel. If it doesn't go away, subsequent
511
# VNC connection attempts will hang.
513
# Fedora's 'nc' doesn't have this option, and apparently defaults
514
# to the desired behavior.
516
nc_params = "%s %s" % (vncaddr, str(vncport))
518
"nc -q 2>&1 | grep -q 'requires an argument';"
519
"if [ $? -eq 0 ] ; then"
520
" CMD='nc -q 0 %(nc_params)s';"
522
" CMD='nc %(nc_params)s';"
524
"$CMD;" % {'nc_params': nc_params}
529
argv_str = reduce(lambda x, y: x + " " + y, argv[1:])
530
logging.debug("Creating SSH tunnel: %s" % argv_str)
532
fds = socket.socketpair()
533
errorfds = socket.socketpair()
518
os.dup(fds[1].fileno())
519
os.dup(fds[1].fileno())
543
os.dup(fds[1].fileno())
544
os.dup(fds[1].fileno())
545
os.dup(errorfds[1].fileno())
525
logging.debug("Tunnel PID %d FD %d" % (fds[0].fileno(), pid))
526
self.vncTunnel = [fds[0], pid]
552
logging.debug("Tunnel PID=%d OUTFD=%d ERRFD=%d" %
553
(pid, fds[0].fileno(), errorfds[0].fileno()))
554
errorfds[0].setblocking(0)
555
self.vncTunnel = [fds[0], errorfds[0], pid]
527
557
return fds[0].fileno()
529
559
def close_tunnel(self):
530
560
if self.vncTunnel is None:
533
logging.debug("Shutting down tunnel PID %d FD %d" %
534
(self.vncTunnel[1], self.vncTunnel[0].fileno()))
563
logging.debug("Shutting down tunnel PID=%d OUTFD=%d ERRFD=%d" %
564
(self.vncTunnel[2], self.vncTunnel[0].fileno(),
565
self.vncTunnel[1].fileno()))
535
566
self.vncTunnel[0].close()
536
os.waitpid(self.vncTunnel[1], 0)
567
self.vncTunnel[1].close()
569
os.kill(self.vncTunnel[2], signal.SIGKILL)
537
570
self.vncTunnel = None
572
def get_tunnel_err_output(self):
573
errfd = self.vncTunnel[1]
576
new = errfd.recv(1024)
584
def skip_connect_attempt(self):
585
return (self.vnc_connected or
586
not self.is_visible())
588
def guest_not_avail(self):
589
return (not self.vm.get_handle() or
590
self.vm.status() in [ libvirt.VIR_DOMAIN_SHUTOFF,
591
libvirt.VIR_DOMAIN_CRASHED ] or
592
self.vm.get_id() < 0)
539
594
def try_login(self, src=None):
540
if not self.vm.get_handle():
541
# VM was removed, skip login attempt
595
if self.skip_connect_attempt():
596
# Don't try and login for these cases
544
if self.vm.get_id() < 0:
599
if self.guest_not_avail():
600
# Guest isn't running, schedule another try
545
601
self.activate_unavailable_page(_("Guest not running"))
546
602
self.schedule_retry()
551
port, trans, username) = self.vm.get_graphics_console()
607
vncport, trans, username,
608
connport, vncuri) = self.vm.get_graphics_console()
552
609
except Exception, e:
553
610
# We can fail here if VM is destroyed: xen is a bit racy
554
611
# and can't handle domain lookups that soon after
555
612
logging.debug("Getting graphics console failed: %s" % str(e))
560
host, connport = host.split(":", 1)
562
615
if protocol is None:
563
616
logging.debug("No graphics configured in guest")
564
self.activate_unavailable_page(_("Graphical console not configured for guest"))
617
self.activate_unavailable_page(
618
_("Graphical console not configured for guest"))
567
uri = str(protocol) + "://"
569
uri = uri + str(username) + '@'
570
uri = uri + str(host) + ":" + str(port)
572
logging.debug("Graphics console configured at " + uri)
574
621
if protocol != "vnc":
575
622
logging.debug("Not a VNC console, disabling")
576
self.activate_unavailable_page(_("Graphical console not supported for guest"))
623
self.activate_unavailable_page(
624
_("Graphical console not supported for guest"))
580
self.activate_unavailable_page(_("Graphical console is not yet active for guest"))
628
self.activate_unavailable_page(
629
_("Graphical console is not yet active for guest"))
581
630
self.schedule_retry()
584
self.activate_unavailable_page(_("Connecting to graphical console for guest"))
585
logging.debug("Starting connect process for %s %s" % (host, str(port)))
633
self.activate_unavailable_page(
634
_("Connecting to graphical console for guest"))
635
logging.debug("Starting connect process for %s: %s %s" %
636
(vncuri, connhost, str(vncport)))
587
if trans is not None and trans in ("ssh", "ext"):
639
if trans in ("ssh", "ext"):
588
640
if self.vncTunnel:
589
logging.debug("Tunnel already open, skipping open_tunnel.")
641
# Tunnel already open, no need to continue
592
fd = self.open_tunnel(host, "127.0.0.1", port, username,
644
fd = self.open_tunnel(connhost, "127.0.0.1", vncport,
595
647
self.vncViewer.open_fd(fd)
597
self.vncViewer.open_host(host, str(port))
650
self.vncViewer.open_host(connhost, str(vncport))
599
653
(typ, value, stacktrace) = sys.exc_info ()