diff -r 60c4cd9ebaa1 tools/Makefile --- a/tools/Makefile Wed Aug 3 16:11:32 2005 +++ b/tools/Makefile Wed Aug 3 16:19:56 2005 @@ -13,7 +13,7 @@ #SUBDIRS += pygrub SUBDIRS += firmware SUBDIRS += security -#SUBDIRS += consoled +SUBDIRS += consoled .PHONY: all install clean check check_clean ioemu eioemuinstall ioemuclean diff -r 60c4cd9ebaa1 tools/misc/xend --- a/tools/misc/xend Wed Aug 3 16:11:32 2005 +++ b/tools/misc/xend Wed Aug 3 16:19:56 2005 @@ -130,6 +130,8 @@ return status >> 8 elif sys.argv[1] == 'start': start_xcs() + if os.fork() == 0: + os.execvp('/usr/sbin/consoled', ['/usr/sbin/consoled']); return daemon.start() elif sys.argv[1] == 'trace_start': start_xcs() diff -r 60c4cd9ebaa1 tools/python/xen/xend/XendClient.py --- a/tools/python/xen/xend/XendClient.py Wed Aug 3 16:11:32 2005 +++ b/tools/python/xen/xend/XendClient.py Wed Aug 3 16:19:56 2005 @@ -5,9 +5,7 @@ Supports inet or unix connection to xend. This API is the 'control-plane' for xend. -The 'data-plane' is done separately. For example, consoles -are accessed via sockets on xend, but the list of consoles -is accessible via this API. +The 'data-plane' is done separately. """ import os import sys @@ -145,9 +143,6 @@ def domainurl(self, id=''): return self.url.relative('domain/' + str(id)) - - def consoleurl(self, id=''): - return self.url.relative('console/' + str(id)) def deviceurl(self, id=''): return self.url.relative('device/' + str(id)) @@ -317,16 +312,6 @@ {'op' : 'device_configure', 'idx' : idx, 'config' : fileof(config) }) - - def xend_consoles(self): - return self.xendGet(self.consoleurl()) - - def xend_console(self, id): - return self.xendGet(self.consoleurl(id)) - - def xend_console_disconnect(self, id): - return self.xendPost(self.consoleurl(id), - {'op' : 'disconnect'}) def xend_vnets(self): return self.xendGet(self.vneturl()) diff -r 60c4cd9ebaa1 tools/python/xen/xend/XendDomainInfo.py --- a/tools/python/xen/xend/XendDomainInfo.py Wed Aug 3 16:11:32 2005 +++ b/tools/python/xen/xend/XendDomainInfo.py Wed Aug 3 16:19:56 2005 @@ -268,7 +268,6 @@ self.restart_time = None self.restart_count = 0 - self.console_port = None self.vcpus = 1 self.bootloader = None @@ -344,9 +343,6 @@ s += " name=" + self.name s += " memory=" + str(self.memory) s += " ssidref=" + str(self.ssidref) - console = self.getConsole() - if console: - s += " console=" + str(console.console_port) s += ">" return s @@ -443,9 +439,6 @@ sxpr.append(self.store_channel.sxpr()) if self.store_mfn: sxpr.append(['store_mfn', self.store_mfn]) - console = self.getConsole() - if console: - sxpr.append(console.sxpr()) if self.restart_count: sxpr.append(['restart_count', self.restart_count]) @@ -519,7 +512,6 @@ # Create domain devices. self.configure_backends() - self.configure_console() self.configure_restart() self.construct_image() self.configure() @@ -785,17 +777,6 @@ """ self.bootloader = sxp.child_value(self.config, "bootloader") - def configure_console(self): - """Configure the vm console port. - """ - x = sxp.child_value(self.config, 'console') - if x: - try: - port = int(x) - except: - raise VmError('invalid console:' + str(x)) - self.console_port = port - def configure_restart(self): """Configure the vm restart mode. """ @@ -855,7 +836,7 @@ def restart(self): """Restart the domain after it has exited. - Reuses the domain id and console port. + Reuses the domain id """ try: @@ -910,24 +891,8 @@ """ self.configure_fields() - self.create_console() self.create_devices() self.create_blkif() - - def create_console(self): - console = self.getConsole() - if not console: - config = ['console'] - if self.console_port: - config.append(['console_port', self.console_port]) - console = self.createDevice('console', config) - return console - - def getConsole(self): - console_ctrl = self.getDeviceController("console", error=False) - if console_ctrl: - return console_ctrl.getDevice(0) - return None def create_blkif(self): """Create the block device interface (blkif) for the vm. @@ -1048,7 +1013,6 @@ add_config_handler('ssidref', vm_field_ignore) add_config_handler('cpu', vm_field_ignore) add_config_handler('cpu_weight', vm_field_ignore) -add_config_handler('console', vm_field_ignore) add_config_handler('restart', vm_field_ignore) add_config_handler('image', vm_field_ignore) add_config_handler('device', vm_field_ignore) @@ -1062,9 +1026,6 @@ #============================================================================ # Register device controllers and their device config types. -from server import console -controller.addDevControllerClass("console", console.ConsoleController) - from server import blkif controller.addDevControllerClass("vbd", blkif.BlkifController) add_device_handler("vbd", "vbd") diff -r 60c4cd9ebaa1 tools/python/xen/xend/XendRoot.py --- a/tools/python/xen/xend/XendRoot.py Wed Aug 3 16:11:32 2005 +++ b/tools/python/xen/xend/XendRoot.py Wed Aug 3 16:19:56 2005 @@ -69,12 +69,6 @@ """Default path the unix-domain server listens at.""" xend_unix_path_default = '/var/lib/xend/xend-socket' - - """Default interface address xend listens at for consoles.""" - console_address_default = 'localhost' - - """Default port xend serves consoles at. """ - console_port_base_default = '9600' dom0_min_mem_default = '0' @@ -302,19 +296,6 @@ """ return self.get_config_value("xend-unix-path", self.xend_unix_path_default) - def get_console_address(self): - """Get the address xend listens at for its console ports. - This defaults to 'localhost', allowing only the localhost to connect - to the console ports. Setting this to the empty string, allows all - hosts to connect. - """ - return self.get_config_value('console-address', self.console_address_default) - - def get_console_port_base(self): - """Get the base port number used to generate console ports for domains. - """ - return self.get_config_int('console-port-base', self.console_port_base_default) - def get_block_script(self, type): return self.get_config_value('block-%s' % type, '') diff -r 60c4cd9ebaa1 tools/python/xen/xend/server/SrvDomain.py --- a/tools/python/xen/xend/server/SrvDomain.py Wed Aug 3 16:11:32 2005 +++ b/tools/python/xen/xend/server/SrvDomain.py Wed Aug 3 16:19:56 2005 @@ -4,7 +4,6 @@ from xen.xend import sxp from xen.xend import XendDomain -from xen.xend import XendConsole from xen.xend import PrettyPrint from xen.xend.Args import FormFn @@ -18,7 +17,6 @@ SrvDir.__init__(self) self.dom = dom self.xd = XendDomain.instance() - self.xconsole = XendConsole.instance() def op_configure(self, op, req): """Configure an existing domain. @@ -208,14 +206,6 @@ self.print_path(req) #self.ls() req.write('
%s
' % self.dom) - if self.dom.console: - cinfo = self.dom.console - cid = str(cinfo.console_port) - #todo: Local xref: need to know server prefix. - req.write('' - % (cid, cid)) - req.write('' - % cinfo.uri()) if self.dom.config: req.write("")
PrettyPrint.prettyprint(self.dom.config, out=req)
diff -r 60c4cd9ebaa1 tools/python/xen/xend/server/SrvRoot.py
--- a/tools/python/xen/xend/server/SrvRoot.py Wed Aug 3 16:11:32 2005
+++ b/tools/python/xen/xend/server/SrvRoot.py Wed Aug 3 16:19:56 2005
@@ -15,7 +15,6 @@
subdirs = [
('node', 'SrvNode' ),
('domain', 'SrvDomainDir' ),
- ('console', 'SrvConsoleDir' ),
('vnet', 'SrvVnetDir' ),
]
diff -r 60c4cd9ebaa1 tools/python/xen/xend/server/SrvServer.py
--- a/tools/python/xen/xend/server/SrvServer.py Wed Aug 3 16:11:32 2005
+++ b/tools/python/xen/xend/server/SrvServer.py Wed Aug 3 16:19:56 2005
@@ -1,7 +1,7 @@
#!/usr/bin/python
# Copyright (C) 2004 Mike Wray
-"""Example xend HTTP and console server.
+"""Example xend HTTP
Can be accessed from a browser or from a program.
Do 'python SrvServer.py' to run the server.
diff -r 60c4cd9ebaa1 tools/python/xen/xend/server/event.py
--- a/tools/python/xen/xend/server/event.py Wed Aug 3 16:11:32 2005
+++ b/tools/python/xen/xend/server/event.py Wed Aug 3 16:19:56 2005
@@ -128,16 +128,8 @@
def op_pretty(self, name, req):
self.pretty = 1
- def op_console_disconnect(self, name, req):
- id = sxp.child_value(req, 'id')
- if not id:
- raise XendError('Missing console id')
- id = int(id)
- self.daemon.console_disconnect(id)
-
def op_info(self, name, req):
val = ['info']
- #val += self.daemon.consoles()
#val += self.daemon.blkifs()
#val += self.daemon.netifs()
#val += self.daemon.usbifs()
diff -r 60c4cd9ebaa1 tools/python/xen/xend/server/messages.py
--- a/tools/python/xen/xend/server/messages.py Wed Aug 3 16:11:32 2005
+++ b/tools/python/xen/xend/server/messages.py Wed Aug 3 16:19:56 2005
@@ -16,16 +16,6 @@
See below.
"""
msg_formats = {}
-
-#============================================================================
-# Console message types.
-#============================================================================
-
-CMSG_CONSOLE = 0
-
-console_formats = { 'console_data': (CMSG_CONSOLE, 0) }
-
-msg_formats.update(console_formats)
#============================================================================
# Block interface message types.
diff -r 60c4cd9ebaa1 tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py Wed Aug 3 16:11:32 2005
+++ b/tools/python/xen/xm/create.py Wed Aug 3 16:19:56 2005
@@ -7,6 +7,7 @@
import string
import sys
import socket
+import commands
import xen.lowlevel.xc
@@ -16,8 +17,6 @@
from xen.xend.XendBootloader import bootloader
from xen.xend import XendRoot; xroot = XendRoot.instance()
from xen.util import blkif
-
-from xen.util import console_client
from xen.xm.opts import *
@@ -144,10 +143,6 @@
fn=set_float, default=None,
use="""Set the new domain's cpu weight.
WEIGHT is a float that controls the domain's share of the cpu.""")
-
-gopts.var('console', val='PORT',
- fn=set_int, default=None,
- use="Console port to use. Default is 9600 + domain id.")
gopts.var('restart', val='onreboot|always|never',
fn=set_value, default=None,
@@ -471,8 +466,6 @@
config.append(['backend', ['netif']])
if vals.restart:
config.append(['restart', vals.restart])
- if vals.console:
- config.append(['console', vals.console])
if vals.bootloader:
run_bootloader(opts, config, vals)
@@ -620,8 +613,8 @@
@param opts: options
@param config: configuration
- @return: domain id, console port
- @rtype: (int, int)
+ @return: domain id
+ @rtype: int
"""
try:
@@ -634,19 +627,13 @@
opts.err(str(ex))
dom = sxp.child_value(dominfo, 'name')
- console_info = sxp.child(dominfo, 'console')
- if console_info:
- console_port = int(sxp.child_value(console_info, 'console_port'))
- else:
- console_port = None
if not opts.vals.paused:
if server.xend_domain_unpause(dom) < 0:
server.xend_domain_destroy(dom)
opts.err("Failed to unpause domain %s" % dom)
- opts.info("Started domain %s, console on port %d"
- % (dom, console_port))
- return (dom, console_port)
+ opts.info("Started domain %s" % (dom))
+ return int(sxp.child_value(dominfo, 'id'))
def get_dom0_alloc():
"""Return current allocation memory of dom0 (in MB). Return 0 on error"""
@@ -709,10 +696,10 @@
if dom0_min_mem != 0:
balloon_out(dom0_min_mem, opts)
- (dom, console) = make_domain(opts, config)
+ dom = make_domain(opts, config)
if opts.vals.console_autoconnect:
- path = "/var/lib/xend/console-%s" % console
- console_client.connect('localhost', console, path=path)
+ cmd = "/usr/libexec/xen/xc_console %d" % dom
+ os.execvp('/usr/libexec/xen/xc_console', cmd.split())
if __name__ == '__main__':
main(sys.argv)
diff -r 60c4cd9ebaa1 tools/python/xen/xm/main.py
--- a/tools/python/xen/xm/main.py Wed Aug 3 16:11:32 2005
+++ b/tools/python/xen/xm/main.py Wed Aug 3 16:19:56 2005
@@ -4,6 +4,7 @@
import os
import os.path
import sys
+import commands
from getopt import getopt
import socket
import warnings
@@ -390,7 +391,7 @@
self.brief_list(doms)
def brief_list(self, doms):
- print 'Name Id Mem(MB) CPU VCPU(s) State Time(s) Console'
+ print 'Name Id Mem(MB) CPU VCPU(s) State Time(s)'
for dom in doms:
info = server.xend_domain(dom)
d = {}
@@ -401,19 +402,14 @@
d['vcpus'] = int(sxp.child_value(info, 'vcpus', '0'))
d['state'] = sxp.child_value(info, 'state', '??')
d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
- console = sxp.child(info, 'console')
- if console:
- d['port'] = sxp.child_value(console, 'console_port')
- else:
- d['port'] = ''
if d['vcpus'] > 1:
d['cpu'] = '-'
if ((int(sxp.child_value(info, 'ssidref', '0'))) != 0):
d['ssidref1'] = int(sxp.child_value(info, 'ssidref', '0')) & 0xffff
d['ssidref2'] = (int(sxp.child_value(info, 'ssidref', '0')) >> 16) & 0xffff
- print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f %(port)4s s:%(ssidref2)02x/p:%(ssidref1)02x" % d)
+ print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f %s:%(ssidref2)02x/p:%(ssidref1)02x" % d)
else:
- print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f %(port)4s" % d)
+ print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f" % d)
def show_vcpus(self, doms):
print 'Name Id VCPU CPU CPUMAP'
@@ -699,29 +695,6 @@
xm.prog(ProgInfo)
-class ProgConsoles(Prog):
- group = 'console'
- name = "consoles"
- info = """Get information about domain consoles."""
-
- def main(self, args):
- l = server.xend_consoles()
- print "Dom Port Id Connection"
- for x in l:
- info = server.xend_console(x)
- d = {}
- d['dom'] = sxp.child(info, 'domain', '?')[1]
- d['port'] = sxp.child_value(info, 'console_port', '?')
- d['id'] = sxp.child_value(info, 'id', '?')
- connected = sxp.child(info, 'connected')
- if connected:
- d['conn'] = '%s:%s' % (connected[1], connected[2])
- else:
- d['conn'] = ''
- print "%(dom)3s %(port)4s %(id)3s %(conn)s" % d
-
-xm.prog(ProgConsoles)
-
class ProgConsole(Prog):
group = 'console'
name = "console"
@@ -735,13 +708,9 @@
if len(args) < 2: self.err("%s: Missing domain" % args[0])
dom = args[1]
info = server.xend_domain(dom)
- console = sxp.child(info, "console")
- if not console:
- self.err("No console information")
- port = sxp.child_value(console, "console_port")
- from xen.util import console_client
- path = "/var/lib/xend/console-%s" % port
- console_client.connect("localhost", int(port), path=path)
+ domid = int(sxp.child_value(info, 'id', '-1'))
+ cmd = "/usr/libexec/xen/xc_console %d" % domid
+ os.execvp('/usr/libexec/xen/xc_console', cmd.split())
xm.prog(ProgConsole)
diff -r 60c4cd9ebaa1 tools/python/xen/util/console_client.py
--- a/tools/python/xen/util/console_client.py Wed Aug 3 16:11:32 2005
+++ /dev/null Wed Aug 3 16:19:56 2005
@@ -1,108 +0,0 @@
-#!/usr/bin/env python
-
-##############################################
-# Console client for Xen guest OSes
-# Copyright (c) 2004, K A Fraser
-##############################################
-
-import errno, os, signal, socket, struct, sys
-
-from termios import *
-# Indexes into termios.tcgetattr() list.
-IFLAG = 0
-OFLAG = 1
-CFLAG = 2
-LFLAG = 3
-ISPEED = 4
-OSPEED = 5
-CC = 6
-
-def __child_death(signum, frame):
- global stop
- stop = True
-
-def __recv_from_sock(sock):
- global stop
- stop = False
- while not stop:
- try:
- data = sock.recv(1024)
- except socket.error, error:
- if error[0] != errno.EINTR:
- raise
- else:
- try:
- os.write(1, data)
- except os.error, error:
- if error[0] != errno.EINTR:
- raise
- os.wait()
-
-def __send_to_sock(sock):
- while 1:
- try:
- data = os.read(0,1024)
- except os.error, error:
- if error[0] != errno.EINTR:
- raise
- else:
- if ord(data[0]) == ord(']')-64:
- break
- try:
- sock.send(data)
- except socket.error, error:
- if error[0] == errno.EPIPE:
- sys.exit(0)
- if error[0] != errno.EINTR:
- raise
- sys.exit(0)
-
-def connect(host, port, path=None):
- # Try inet first. If 'path' is given and the error
- # was connection refused, try unix-domain on 'path'.
- try:
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- sock.connect((host, port))
- except socket.error, err:
- if (path is None) or (err[0] != errno.ECONNREFUSED):
- raise
- # Try unix-domain.
- sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- sock.connect(path)
-
- oattrs = tcgetattr(0)
- nattrs = tcgetattr(0)
- nattrs[IFLAG] = nattrs[IFLAG] & ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON)
- nattrs[OFLAG] = nattrs[OFLAG] & ~(OPOST)
- nattrs[CFLAG] = nattrs[CFLAG] & ~(CSIZE | PARENB)
- nattrs[CFLAG] = nattrs[CFLAG] | CS8
- nattrs[LFLAG] = nattrs[LFLAG] & ~(ECHO | ICANON | IEXTEN | ISIG)
- nattrs[CC][VMIN] = 1
- nattrs[CC][VTIME] = 0
-
- if os.fork():
- signal.signal(signal.SIGCHLD, __child_death)
- print "************ REMOTE CONSOLE: CTRL-] TO QUIT ********"
- tcsetattr(0, TCSAFLUSH, nattrs)
- try:
- __recv_from_sock(sock)
- finally:
- tcsetattr(0, TCSAFLUSH, oattrs)
- print
- print "************ REMOTE CONSOLE EXITED *****************"
- else:
- signal.signal(signal.SIGPIPE, signal.SIG_IGN)
- __send_to_sock(sock)
-
-if __name__ == '__main__':
- argc = len(sys.argv)
- if argc < 3 or argc > 4:
- print >>sys.stderr, sys.argv[0], " []"
- sys.exit(1)
- host = sys.argv[1]
- port = int(sys.argv[2])
- if argc > 3:
- path = sys.argv[3]
- else:
- path = None
- connect(host, port, path=path)
diff -r 60c4cd9ebaa1 tools/python/xen/xend/XendConsole.py
--- a/tools/python/xen/xend/XendConsole.py Wed Aug 3 16:11:32 2005
+++ /dev/null Wed Aug 3 16:19:56 2005
@@ -1,44 +0,0 @@
-# Copyright (C) 2004 Mike Wray
-
-import XendRoot; xroot = XendRoot.instance()
-from XendError import XendError
-
-class XendConsole:
-
- def __init__(self):
- pass
-
- def console_ls(self):
- return [ c.console_port for c in self.consoles() ]
-
- def consoles(self):
- l = []
- xd = XendRoot.get_component('xen.xend.XendDomain')
- for vm in xd.list():
- ctrl = vm.getDeviceController("console", error=False)
- if (not ctrl): continue
- console = ctrl.getDevice(0)
- if (not console): continue
- l.append(console)
- return l
-
- def console_get(self, id):
- id = int(id)
- for c in self.consoles():
- if c.console_port == id:
- return c
- return None
-
- def console_disconnect(self, id):
- console = self.console_get(id)
- if not console:
- raise XendError('Invalid console id')
- console.disconnect()
-
-def instance():
- global inst
- try:
- inst
- except:
- inst = XendConsole()
- return inst
diff -r 60c4cd9ebaa1 tools/python/xen/xend/server/SrvConsole.py
--- a/tools/python/xen/xend/server/SrvConsole.py Wed Aug 3 16:11:32 2005
+++ /dev/null Wed Aug 3 16:19:56 2005
@@ -1,41 +0,0 @@
-# Copyright (C) 2004 Mike Wray
-
-from xen.xend import sxp
-from xen.xend import XendConsole
-from xen.web.SrvDir import SrvDir
-
-class SrvConsole(SrvDir):
- """An individual console.
- """
-
- def __init__(self, info):
- SrvDir.__init__(self)
- self.info = info
- self.xc = XendConsole.instance()
-
- def op_disconnect(self, op, req):
- val = self.xc.console_disconnect(self.info.console_port)
- return val
-
- def render_POST(self, req):
- return self.perform(req)
-
- def render_GET(self, req):
- if self.use_sxp(req):
- req.setHeader("Content-Type", sxp.mime_type)
- sxp.show(self.info.sxpr(), out=req)
- else:
- req.write('')
- self.print_path(req)
- #self.ls()
- req.write('%s
' % self.info)
- req.write(''
- % (self.info.uri(), self.info.id))
- self.form(req)
- req.write('')
-
- def form(self, req):
- req.write('')
diff -r 60c4cd9ebaa1 tools/python/xen/xend/server/SrvConsoleDir.py
--- a/tools/python/xen/xend/server/SrvConsoleDir.py Wed Aug 3 16:11:32 2005
+++ /dev/null Wed Aug 3 16:19:56 2005
@@ -1,59 +0,0 @@
-# Copyright (C) 2004 Mike Wray
-
-from xen.web.SrvDir import SrvDir
-from SrvConsole import SrvConsole
-from xen.xend import XendConsole
-from xen.xend import sxp
-
-class SrvConsoleDir(SrvDir):
- """Console directory.
- """
-
- def __init__(self):
- SrvDir.__init__(self)
- self.xconsole = XendConsole.instance()
-
- def console(self, x):
- val = None
- try:
- info = self.xconsole.console_get(x)
- val = SrvConsole(info)
- except KeyError, ex:
- print 'SrvConsoleDir>', ex
- pass
- return val
-
- def get(self, x):
- v = SrvDir.get(self, x)
- if v is not None:
- return v
- v = self.console(x)
- return v
-
- def render_GET(self, req):
- if self.use_sxp(req):
- req.setHeader("Content-Type", sxp.mime_type)
- self.ls_console(req, 1)
- else:
- req.write("")
- self.print_path(req)
- self.ls(req)
- self.ls_console(req)
- #self.form(req.wfile)
- req.write("")
-
- def ls_console(self, req, use_sxp=0):
- url = req.prePathURL()
- if not url.endswith('/'):
- url += '/'
- if use_sxp:
- consoles = self.xconsole.console_ls()
- sxp.show(consoles, out=req)
- else:
- consoles = self.xconsole.consoles()
- consoles.sort(lambda x, y: cmp(x.console_port, y.console_port))
- req.write('')
- for c in consoles:
- cid = str(c.console_port)
- req.write('- %s
' % (url, cid, cid))
- req.write('
')
diff -r 60c4cd9ebaa1 tools/python/xen/xend/server/console.py
--- a/tools/python/xen/xend/server/console.py Wed Aug 3 16:11:32 2005
+++ /dev/null Wed Aug 3 16:19:56 2005
@@ -1,391 +0,0 @@
-# Copyright (C) 2004 Mike Wray
-
-import socket
-import threading
-from errno import EAGAIN, EINTR, EWOULDBLOCK
-
-from xen.web import reactor, protocol
-
-from xen.lowlevel import xu
-
-from xen.xend.XendError import XendError
-from xen.xend import EventServer; eserver = EventServer.instance()
-from xen.xend.XendLogging import log
-from xen.xend import XendRoot; xroot = XendRoot.instance()
-from xen.xend import sxp
-from xen.xend.xenstore import DBVar
-
-from xen.xend.server.controller import CtrlMsgRcvr, Dev, DevController
-from xen.xend.server.messages import *
-from xen.xend.server.params import *
-
-class ConsoleProtocol(protocol.Protocol):
- """Asynchronous handler for a console socket.
- """
-
- def __init__(self, console, id):
- self.console = console
- self.id = id
- self.addr = None
-
- def connectionMade(self, addr=None):
- peer = self.transport.getPeer()
- self.addr = addr
- if self.console.connect(self.addr, self):
- self.transport.write("Cannot connect to console %d on domain %d\n"
- % (self.id, self.console.getDomain()))
- self.loseConnection()
- return
- else:
- if len(self.addr) == 2:
- host = str(self.addr[0])
- port = str(self.addr[1])
- else:
- host = 'localhost'
- port = str(addr)
- log.info("Console connected %s %s %s",
- self.id, host, port)
- eserver.inject('xend.console.connect',
- [self.id, host, port])
-
- def dataReceived(self, data):
- if self.console.receiveInput(self, data):
- self.loseConnection()
-
- def write(self, data):
- self.transport.write(data)
- return len(data)
-
- def connectionLost(self, reason=None):
- log.info("Console disconnected %s %s %s",
- str(self.id), str(self.addr[0]), str(self.addr[1]))
- eserver.inject('xend.console.disconnect',
- [self.id, self.addr[0], self.addr[1]])
- self.console.disconnect(conn=self)
-
- def loseConnection(self):
- self.transport.loseConnection()
-
-class ConsoleDev(Dev, protocol.ServerFactory):
- """Console device for a domain.
- Does not poll for i/o itself, but relies on the domain to post console
- output and the connected TCP sockets to post console input.
- """
-
- STATUS_NEW = 'new'
- STATUS_CLOSED = 'closed'
- STATUS_CONNECTED = 'connected'
- STATUS_LISTENING = 'listening'
-
- __exports__ = Dev.__exports__ + [
- DBVar('status', ty='str'),
- #DBVar('listening', ty='str'),
- DBVar('console_port', ty='int'),
- ]
-
- def __init__(self, controller, id, config, recreate=False):
- Dev.__init__(self, controller, id, config)
- self.lock = threading.RLock()
- self.status = self.STATUS_NEW
- self.addr = None
- self.conn = None
- self.console_port = None
- self.obuf = xu.buffer()
- self.ibuf = xu.buffer()
- self.channel = None
- self.listening = False
- self.unix_listener = None
- self.tcp_listener = None
-
- console_port = sxp.child_value(self.config, "console_port")
- if console_port is None:
- console_port = xroot.get_console_port_base() + self.getDomain()
- self.checkConsolePort(console_port)
- self.console_port = console_port
-
- log.info("Created console id=%d domain=%d port=%d",
- self.id, self.getDomain(), self.console_port)
- eserver.inject('xend.console.create',
- [self.id, self.getDomain(), self.console_port])
-
- def init(self, recreate=False, reboot=False):
- try:
- self.lock.acquire()
- self.destroyed = False
- self.channel = self.getChannel()
- self.listen()
- finally:
- self.lock.release()
-
- def checkConsolePort(self, console_port):
- """Check that a console port is not in use by another console.
- """
- xd = XendRoot.get_component('xen.xend.XendDomain')
- for vm in xd.list():
- ctrl = vm.getDeviceController(self.getType(), error=False)
- if (not ctrl): continue
- ctrl.checkConsolePort(console_port)
-
- def sxpr(self):
- try:
- self.lock.acquire()
- val = ['console',
- ['status', self.status ],
- ['id', self.id ],
- ['domain', self.getDomain() ] ]
- val.append(['local_port', self.getLocalPort() ])
- val.append(['remote_port', self.getRemotePort() ])
- val.append(['console_port', self.console_port ])
- if self.addr:
- val.append(['connected', self.addr[0], self.addr[1]])
- finally:
- self.lock.release()
- return val
-
- def getLocalPort(self):
- try:
- self.lock.acquire()
- if self.channel:
- return self.channel.getLocalPort()
- else:
- return 0
- finally:
- self.lock.release()
-
- def getRemotePort(self):
- try:
- self.lock.acquire()
- if self.channel:
- return self.channel.getRemotePort()
- else:
- return 0
- finally:
- self.lock.release()
-
- def uri(self):
- """Get the uri to use to connect to the console.
- This will be a telnet: uri.
-
- return uri
- """
- host = socket.gethostname()
- return "telnet://%s:%d" % (host, self.console_port)
-
- def closed(self):
- return self.status == self.STATUS_CLOSED
-
- def connected(self):
- return self.status == self.STATUS_CONNECTED
-
- def destroy(self, change=False, reboot=False):
- """Close the console.
- """
- if reboot:
- return
- try:
- self.lock.acquire()
- self.status = self.STATUS_CLOSED
- self.listening = False
- if self.conn:
- self.conn.loseConnection()
- if self.tcp_listener:
- self.tcp_listener.stopListening()
- self.tcp_listener = None
- if self.unix_listener:
- self.unix_listener.stopListening()
- self.unix_listener = None
- finally:
- self.lock.release()
-
- def listen(self):
- """Listen for TCP connections to the console port..
- """
- try:
- self.lock.acquire()
- if self.closed():
- return
- if self.listening:
- pass
- else:
- self.listening = True
- self.status = self.STATUS_LISTENING
- if xroot.get_xend_unix_server():
- path = '/var/lib/xend/console-%s' % self.console_port
- self.unix_listener = reactor.listenUNIX(path, self)
- if xroot.get_xend_http_server():
- interface = xroot.get_console_address()
- self.tcp_listener = reactor.listenTCP(
- self.console_port, self, interface=interface)
- finally:
- self.lock.release()
-
- def buildProtocol(self, addr):
- """Factory function called to create the protocol when a connection is accepted
- by listenTCP.
- """
- proto = ConsoleProtocol(self, self.id)
- proto.factory = self
- return proto
-
- def connect(self, addr, conn):
- """Connect a TCP connection to the console.
- Fails if closed or already connected.
-
- addr peer address
- conn connection
-
- returns 0 if ok, negative otherwise
- """
- try:
- self.lock.acquire()
- if self.closed():
- return -1
- if self.connected():
- return -1
- self.addr = addr
- self.conn = conn
- self.status = self.STATUS_CONNECTED
- self.writeOutput()
- finally:
- self.lock.release()
- return 0
-
- def disconnect(self, conn=None):
- """Disconnect the TCP connection to the console.
- """
- try:
- self.lock.acquire()
- if conn and conn != self.conn: return
- if self.conn:
- self.conn.loseConnection()
- self.addr = None
- self.conn = None
- self.status = self.STATUS_LISTENING
- self.listen()
- finally:
- self.lock.release()
-
- def receiveOutput(self, msg):
- """Receive output console data from the console channel.
-
- msg console message
- type major message type
- subtype minor message typ
- """
- # Treat the obuf as a ring buffer.
- try:
- self.lock.acquire()
- data = msg.get_payload()
- data_n = len(data)
- if self.obuf.space() < data_n:
- self.obuf.discard(data_n)
- if self.obuf.space() < data_n:
- data = data[-self.obuf.space():]
- self.obuf.write(data)
- self.writeOutput()
- finally:
- self.lock.release()
-
- def writeOutput(self):
- """Handle buffered output from the console device.
- Sends it to the connected TCP connection (if any).
- """
- try:
- self.lock.acquire()
- if self.closed():
- return -1
- writes = 0
- while self.conn and (writes < 100) and (not self.obuf.empty()):
- try:
- writes += 1
- bytes = self.conn.write(self.obuf.peek())
- if bytes > 0:
- self.obuf.discard(bytes)
- except socket.error, err:
- if err.args[0] in (EWOULDBLOCK, EAGAIN, EINTR):
- pass
- else:
- self.disconnect()
- break
-
- finally:
- self.lock.release()
- return 0
-
- def receiveInput(self, conn, data):
- """Receive console input from a TCP connection. Ignores the
- input if the calling connection (conn) is not the one
- connected to the console (self.conn).
-
- conn connection
- data input data
- """
- try:
- self.lock.acquire()
- if self.closed(): return -1
- if conn != self.conn: return 0
- self.ibuf.write(data)
- self.writeInput()
- finally:
- self.lock.release()
- return 0
-
- def writeInput(self):
- """Write pending console input to the console channel.
- Writes as much to the channel as it can.
- """
- try:
- self.lock.acquire()
- while self.channel and not self.ibuf.empty():
- msg = xu.message(CMSG_CONSOLE, 0, 0)
- msg.append_payload(self.ibuf.read(msg.MAX_PAYLOAD))
- self.channel.writeRequest(msg)
- finally:
- self.lock.release()
-
-class ConsoleController(DevController):
- """Device controller for all the consoles for a domain.
- """
-
- def __init__(self, vm, recreate=False):
- DevController.__init__(self, vm, recreate=recreate)
- self.rcvr = None
-
- def initController(self, recreate=False, reboot=False):
- self.destroyed = False
- self.rcvr = CtrlMsgRcvr(self.getChannel())
- self.rcvr.addHandler(CMSG_CONSOLE,
- 0,
- self.receiveOutput)
- self.rcvr.registerChannel()
- if reboot:
- self.rebootDevices()
-
- def destroyController(self, reboot=False):
- self.destroyed = True
- self.destroyDevices(reboot=reboot)
- self.rcvr.deregisterChannel()
-
- def newDevice(self, id, config, recreate=False):
- return ConsoleDev(self, id, config, recreate=recreate)
-
- def checkConsolePort(self, console_port):
- """Check that a console port is not in use by a console.
- """
- for c in self.getDevices():
- if c.console_port == console_port:
- raise XendError('console port in use: ' + str(console_port))
-
- def receiveOutput(self, msg):
- """Handle a control request.
- The CMSG_CONSOLE messages just contain data, and no console id,
- so just send to console 0 (if there is one).
-
- todo: extend CMSG_CONSOLE to support more than one console?
- """
- console = self.getDevice(0)
- if console:
- console.receiveOutput(msg)
- else:
- log.warning('no console: domain %d', self.getDomain())
-