2006-08-11 00:47:14 +04:00
#
# Copyright (C) 2006 Red Hat, Inc.
# Copyright (C) 2006 Daniel P. Berrange <berrange@redhat.com>
#
# 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
2007-11-20 19:12:20 +03:00
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
2006-08-11 00:47:14 +04:00
#
import os
import termios
import tty
2008-02-03 20:42:21 +03:00
import pty
2008-10-03 00:17:25 +04:00
import fcntl
2009-07-15 03:42:16 +04:00
import logging
2006-08-11 00:47:14 +04:00
2011-04-12 01:48:21 +04:00
import gtk
import gobject
import vte
2008-10-03 00:17:25 +04:00
import libvirt
2006-08-11 00:47:14 +04:00
2011-04-12 01:48:21 +04:00
from virtManager . baseclass import vmmGObject
2011-06-20 02:53:15 +04:00
class ConsoleConnection ( vmmGObject ) :
def __init__ ( self , vm ) :
vmmGObject . __init__ ( self )
self . vm = vm
self . conn = vm . get_connection ( )
def cleanup ( self ) :
vmmGObject . cleanup ( self )
self . close ( )
self . vm = None
self . conn = None
2011-06-20 04:49:41 +04:00
def open ( self , dev , terminal ) :
2011-06-20 02:53:15 +04:00
raise NotImplementedError ( )
def close ( self ) :
raise NotImplementedError ( )
def send_data ( self , src , text , length , terminal ) :
"""
Callback when data has been entered into VTE terminal
"""
raise NotImplementedError ( )
class LocalConsoleConnection ( ConsoleConnection ) :
def __init__ ( self , vm ) :
ConsoleConnection . __init__ ( self , vm )
self . fd = None
self . source = None
self . origtermios = None
def cleanup ( self ) :
ConsoleConnection . cleanup ( self )
2011-06-20 04:49:41 +04:00
def open ( self , dev , terminal ) :
2011-06-20 02:53:15 +04:00
if self . fd != None :
self . close ( )
2011-06-20 04:49:41 +04:00
ipty = dev and dev . source_path or None
2011-06-20 02:53:15 +04:00
logging . debug ( " Opening serial tty path: %s " % ipty )
if ipty == None :
return
self . fd = pty . slave_open ( ipty )
fcntl . fcntl ( self . fd , fcntl . F_SETFL , os . O_NONBLOCK )
self . source = gobject . io_add_watch ( self . fd ,
gobject . IO_IN | gobject . IO_ERR | gobject . IO_HUP ,
self . display_data , terminal )
# Save term settings & set to raw mode
self . origtermios = termios . tcgetattr ( self . fd )
tty . setraw ( self . fd , termios . TCSANOW )
def close ( self ) :
if self . fd == None :
return
# Restore term settings
try :
termios . tcsetattr ( self . fd , termios . TCSANOW , self . origtermios )
except :
# domain may already have exited, destroying the pty, so ignore
pass
os . close ( self . fd )
gobject . source_remove ( self . source )
self . fd = None
self . source = None
self . origtermios = None
def send_data ( self , src , text , length , terminal ) :
ignore = src
ignore = length
ignore = terminal
if self . fd is None :
return
os . write ( self . fd , text )
def display_data ( self , src , cond , terminal ) :
ignore = src
if cond != gobject . IO_IN :
self . close ( )
return False
data = os . read ( self . fd , 1024 )
terminal . feed ( data , len ( data ) )
return True
2011-04-12 01:48:21 +04:00
class vmmSerialConsole ( vmmGObject ) :
2009-07-15 03:42:16 +04:00
def __init__ ( self , vm , target_port ) :
2011-04-12 01:48:21 +04:00
vmmGObject . __init__ ( self )
2006-08-11 00:47:14 +04:00
2008-10-03 00:17:25 +04:00
self . vm = vm
2009-07-15 03:42:16 +04:00
self . target_port = target_port
2011-06-20 04:49:41 +04:00
self . lastpath = None
2006-08-11 00:47:14 +04:00
2011-06-20 02:53:15 +04:00
self . console = LocalConsoleConnection ( self . vm )
2011-04-12 01:48:21 +04:00
self . terminal = None
self . init_terminal ( )
self . box = None
self . init_ui ( )
self . box . connect ( " realize " , self . handle_realize )
self . box . connect ( " unrealize " , self . handle_unrealize )
self . vm . connect ( " status-changed " , self . vm_status_changed )
def init_terminal ( self ) :
2008-09-22 18:19:19 +04:00
self . terminal = vte . Terminal ( )
self . terminal . set_cursor_blinks ( True )
self . terminal . set_emulation ( " xterm " )
self . terminal . set_font_from_string ( " fixed 10 " )
self . terminal . set_scrollback_lines ( 1000 )
self . terminal . set_audible_bell ( False )
self . terminal . set_visible_bell ( True )
2006-12-04 20:22:45 +03:00
# XXX python VTE binding has bug failing to register constants
#self.terminal.set_backspace_binding(vte.ERASE_ASCII_BACKSPACE)
self . terminal . set_backspace_binding ( 1 )
2006-08-11 00:47:14 +04:00
2011-06-20 02:53:15 +04:00
self . terminal . connect ( " commit " , self . console . send_data , self . terminal )
2008-09-22 18:19:19 +04:00
self . terminal . show ( )
2006-08-11 00:47:14 +04:00
2011-04-12 01:48:21 +04:00
def init_ui ( self ) :
self . box = gtk . HBox ( )
2008-09-22 18:19:19 +04:00
scrollbar = gtk . VScrollbar ( )
scrollbar . set_adjustment ( self . terminal . get_adjustment ( ) )
2006-08-11 00:47:14 +04:00
2011-04-12 01:48:21 +04:00
self . box . pack_start ( self . terminal )
self . box . pack_start ( scrollbar , expand = False , fill = False )
2006-08-11 00:47:14 +04:00
2011-04-12 01:48:21 +04:00
def cleanup ( self ) :
vmmGObject . cleanup ( self )
2006-08-11 00:47:14 +04:00
2011-06-20 02:53:15 +04:00
self . console . cleanup ( )
self . console = None
2011-04-12 01:48:21 +04:00
self . vm = None
self . terminal = None
self . box = None
2006-08-11 00:47:14 +04:00
2008-10-03 00:17:25 +04:00
def handle_realize ( self , ignore = None ) :
2011-06-20 04:49:41 +04:00
self . console . open ( self . lookup_dev ( ) , self . terminal )
2006-08-11 00:47:14 +04:00
2010-12-09 19:22:35 +03:00
def handle_unrealize ( self , src_ignore = None , ignore = None ) :
2011-06-20 02:53:15 +04:00
self . console . close ( )
2006-08-11 00:47:14 +04:00
2010-12-09 19:22:35 +03:00
def vm_status_changed ( self , src_ignore , oldstatus_ignore , status ) :
2010-12-10 19:47:07 +03:00
if status in [ libvirt . VIR_DOMAIN_RUNNING ] :
2011-06-20 04:49:41 +04:00
self . console . open ( self . lookup_dev ( ) , self . terminal )
2008-10-03 00:17:25 +04:00
else :
2011-06-20 02:53:15 +04:00
self . console . close ( )
2006-11-03 18:02:02 +03:00
2011-06-20 04:49:41 +04:00
def lookup_dev ( self ) :
devs = self . vm . get_serial_devs ( )
for dev in devs :
port = dev . vmmindex
path = dev . source_path
2009-07-15 03:42:16 +04:00
if port == self . target_port :
2011-06-20 04:49:41 +04:00
if path != self . lastpath :
2009-07-15 03:42:16 +04:00
logging . debug ( " Serial console ' %s ' path changed to %s . "
2011-06-20 04:49:41 +04:00
% ( self . target_port , path ) )
self . lastpath = path
return dev
2009-07-28 17:32:18 +04:00
2010-06-23 21:05:09 +04:00
logging . debug ( " No devices found for serial target port ' %s ' . " %
2009-07-15 03:42:16 +04:00
self . target_port )
2011-06-20 04:49:41 +04:00
self . lastpath = None
return None