diff options
author | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2004-03-15 13:20:33 +0000 |
---|---|---|
committer | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2004-03-15 13:20:33 +0000 |
commit | 74851d00abd8170a7b8482f7075ea3f6ea7c49b6 (patch) | |
tree | 90c0905891f4ca857f9cda5b31163646b5ef94e7 /tools/xend | |
parent | 0b9d367cf8677be6d54c6d80e393499c99398d2f (diff) | |
download | xen-74851d00abd8170a7b8482f7075ea3f6ea7c49b6.tar.gz xen-74851d00abd8170a7b8482f7075ea3f6ea7c49b6.tar.bz2 xen-74851d00abd8170a7b8482f7075ea3f6ea7c49b6.zip |
bitkeeper revision 1.796 (4055ada1c5nV7AgvKi2Y_vrxKyA7CA)
manager.py, console.py, __init__.py:
new file
setup.py, utils.c, main.py, Makefile:
Refactor the Xen daemon.
main.py:
Rename: tools/xend/xend.py -> tools/xend/lib/main.py
utils.c:
Rename: tools/xend/xend_utils.c -> tools/xend/lib/utils.c
Diffstat (limited to 'tools/xend')
-rw-r--r-- | tools/xend/Makefile | 6 | ||||
-rw-r--r-- | tools/xend/lib/__init__.py | 0 | ||||
-rw-r--r-- | tools/xend/lib/console.py | 114 | ||||
-rwxr-xr-x | tools/xend/lib/main.py (renamed from tools/xend/xend.py) | 194 | ||||
-rw-r--r-- | tools/xend/lib/manager.py | 39 | ||||
-rw-r--r-- | tools/xend/lib/utils.c (renamed from tools/xend/xend_utils.c) | 12 | ||||
-rw-r--r-- | tools/xend/setup.py | 20 |
7 files changed, 191 insertions, 194 deletions
diff --git a/tools/xend/Makefile b/tools/xend/Makefile index de6aeb3982..1ea271e80e 100644 --- a/tools/xend/Makefile +++ b/tools/xend/Makefile @@ -5,8 +5,7 @@ all: install: all if [ "$(prefix)" = "" ]; then python setup.py install; \ else python setup.py install --root "$(prefix)"; fi - install --mode=755 xend.py $(prefix)/usr/sbin - ln -sf xend.py $(prefix)/usr/sbin/xend + install --mode=755 xend $(prefix)/usr/sbin dist: all mkdir -p ../../../../install/lib/python @@ -14,8 +13,7 @@ dist: all install --mode=755 $$i ../../../../install/lib/python/`basename $$i` ; \ done python -c 'import py_compile, sys; py_compile.compile("XenoUtil.py")' - install --mode=755 xend.py ../../../../install/sbin - ln -sf xend.py ../../../../install/sbin/xend + install --mode=755 xend ../../../../install/sbin clean: rm -rf build *.pyc *.pyo *.a *.so *.o *~ *.rpm diff --git a/tools/xend/lib/__init__.py b/tools/xend/lib/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tools/xend/lib/__init__.py diff --git a/tools/xend/lib/console.py b/tools/xend/lib/console.py new file mode 100644 index 0000000000..1b2874c696 --- /dev/null +++ b/tools/xend/lib/console.py @@ -0,0 +1,114 @@ + +############################################################# +## xend/console.py -- Console-management functions for Xend +## Copyright (c) 2004, K A Fraser (University of Cambridge) +############################################################# + +import errno, re, os, select, signal, socket, struct, sys + + +## +## interface: +## Each control interface owns an instance of this class, which manages +## the current state of the console interface. Normally a console interface +## will be one of two state: +## LISTENING: listening for a connection on TCP port 'self.port' +## CONNECTED: sending/receiving console data on TCP port 'self.port' +## +## A dictionary of all active interfaces, indexed by TCP socket descriptor, +## is accessible as 'interface.interface_list'. +## +## NB. When a class instance is to be destroyed you *must* call the 'close' +## method. Otherwise a stale reference will eb left in the interface list. +## +class interface: + + # The various states that a console interface may be in. + CLOSED = 0 # No console activity + LISTENING = 1 # Listening on port 'self.port'. Socket object 'self.sock'. + CONNECTED = 2 # Active connection on 'self.port'. Socket obj 'self.sock'. + + + # Dictionary of all active (non-closed) console interfaces. + interface_list = {} + + + # NB. 'key' is an opaque value that has no meaning in this class. + def __init__(self, port, key): + self.status = interface.CLOSED + self.port = port + self.key = key + + + # Is this interface closed (inactive)? + def closed(self): + return self.status == interface.CLOSED + + + # Is this interface listening? + def listening(self): + return self.status == interface.LISTENING + + + # Is this interface active and connected? + def connected(self): + return self.status == interface.CONNECTED + + + # Close the interface, if it is not closed already. + def close(self): + if not self.closed(): + del interface.interface_list[self.sock.fileno()] + self.sock.close() + del self.sock + self.status = interface.CLOSED + + + # Move the interface into the 'listening' state. Opens a new listening + # socket and updates 'interface_list'. + def listen(self): + # Close old socket (if any), and create a fresh one. + self.close() + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + + try: + # Turn the new socket into a non-blocking listener. + self.sock.setblocking(False) + self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, + struct.pack('ii', 0, 0)) + self.sock.bind(('', self.port)) + self.sock.listen(1) + + # Announce the new status of thsi interface. + self.status = interface.LISTENING + interface.interface_list[self.sock.fileno()] = self + + except: + # In case of trouble ensure we get rid of dangling socket reference + self.sock.close() + del self.sock + raise + + + # Move a listening interface into the 'connected' state. + def connect(self): + # Pick up a new connection, if one is available. + try: + (sock, addr) = self.sock.accept() + except: + return 0 + sock.setblocking(False) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, + struct.pack('ii', 0, 0)) + + # Close the listening socket. + self.sock.close() + + # Publish the new socket and the new interface state. + self.sock = sock + self.status = interface.CONNECTED + interface.interface_list[self.sock.fileno()] = self + return 1 + + diff --git a/tools/xend/xend.py b/tools/xend/lib/main.py index 313dc06575..2bf1ed246d 100755 --- a/tools/xend/xend.py +++ b/tools/xend/lib/main.py @@ -1,15 +1,11 @@ -#!/usr/bin/env python - ########################################################### ## xend.py -- Xen controller daemon ## Copyright (c) 2004, K A Fraser (University of Cambridge) ########################################################### - import errno, re, os, pwd, select, signal, socket, struct, sys, tempfile, time -import xend_utils, Xc - +import xend.console, xend.manager, xend.utils, Xc # The following parameters could be placed in a configuration file. @@ -20,152 +16,16 @@ CONTROL_DIR = '/var/run/xend' UNIX_SOCK = 'management_sock' # relative to CONTROL_DIR - -## -## console_interface: -## Each control interface owns an instance of this class, which manages -## the current state of the console interface. Normally a console interface -## will be one of two state: -## LISTENING: listening for a connection on TCP port 'self.port' -## CONNECTED: sending/receiving console data on TCP port 'self.port' -## -## A dictionary of all active interfaces, indexed by TCP socket descriptor, -## is accessible as 'console_interface.interface_list'. -## -## NB. When a class instance is to be destroyed you *must* call the 'close' -## method. Otherwise a stale reference will eb left in the interface list. -## -class console_interface: - - # The various states that a console interface may be in. - CLOSED = 0 # No console activity - LISTENING = 1 # Listening on port 'self.port'. Socket object 'self.sock'. - CONNECTED = 2 # Active connection on 'self.port'. Socket obj 'self.sock'. - - - # Dictionary of all active (non-closed) console interfaces. - interface_list = {} - - - # NB. 'key' is an opaque value that has no meaning in this class. - def __init__(self, port, key): - self.status = console_interface.CLOSED - self.port = port - self.key = key - - - # Is this interface closed (inactive)? - def closed(self): - return self.status == console_interface.CLOSED - - - # Is this interface listening? - def listening(self): - return self.status == console_interface.LISTENING - - - # Is this interface active and connected? - def connected(self): - return self.status == console_interface.CONNECTED - - - # Close the interface, if it is not closed already. - def close(self): - if not self.closed(): - del console_interface.interface_list[self.sock.fileno()] - self.sock.close() - del self.sock - self.status = console_interface.CLOSED - - - # Move the interface into the 'listening' state. Opens a new listening - # socket and updates 'interface_list'. - def listen(self): - # Close old socket (if any), and create a fresh one. - self.close() - self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) - - try: - # Turn the new socket into a non-blocking listener. - self.sock.setblocking(False) - self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, - struct.pack('ii', 0, 0)) - self.sock.bind(('', self.port)) - self.sock.listen(1) - - # Announce the new status of thsi interface. - self.status = console_interface.LISTENING - console_interface.interface_list[self.sock.fileno()] = self - - except: - # In case of trouble ensure we get rid of dangling socket reference - self.sock.close() - del self.sock - raise - - - # Move a listening interface into the 'connected' state. - def connect(self): - # Pick up a new connection, if one is available. - try: - (sock, addr) = self.sock.accept() - except: - return 0 - sock.setblocking(False) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, - struct.pack('ii', 0, 0)) - - # Close the listening socket. - self.sock.close() - - # Publish the new socket and the new interface state. - self.sock = sock - self.status = console_interface.CONNECTED - console_interface.interface_list[self.sock.fileno()] = self - return 1 - - - -## -## new_control_interface: -## Create a new control interface with the specified domain 'dom'. -## The console port may also be specified; otehrwise a suitable port is -## automatically allocated. -## -def new_control_interface(dom, console_port=-1): - # Allocate an event channel. Clear pending notifications. - port = xend_utils.port(dom) - notifier.clear(port.local_port, notifier.NORMAL) - notifier.clear(port.local_port, notifier.DISCONNECT) - - # If necessary, compute a suitable TCP port for console I/O. - if console_port < 0: - console_port = 9600 + port.local_port - - # Create a listenign console interface. - con_if = console_interface(console_port, port.local_port) - con_if.listen() - - # Add control state to the master list. - control_list[port.local_port] = \ - (port, xend_utils.buffer(), xend_utils.buffer(), con_if) - - # Construct the successful response to be returned to the requester. - response = { 'success': True } - response['local_port'] = port.local_port - response['remote_port'] = port.remote_port - response['console_port'] = console_port - return response - - - def daemon_loop(): + # Could we do this more nicely? The xend.manager functions need access + # to this global state to do their work. global control_list, notifier - xc = Xc.new() + # List of all control interfaces, indexed by local event-channel port. control_list = {} + xc = Xc.new() + # Ignore writes to disconnected sockets. We clean up differently. signal.signal(signal.SIGPIPE, signal.SIG_IGN) @@ -179,7 +39,11 @@ def daemon_loop(): management_interface.setblocking(False) management_interface.bind(CONTROL_DIR+'/'+UNIX_SOCK) - notifier = xend_utils.notifier() + # Interface via which we receive event notifications from other guest + # OSes. This interface also allows us to clear/acknowledge outstanding + # notifications --- successive notifications for the same channel are + # dropped until the first notification is cleared. + notifier = xend.utils.notifier() ## ## MAIN LOOP @@ -218,7 +82,7 @@ def daemon_loop(): # Evaluate the request in an exception-trapping sandbox. try: print "Mgmt_req[%s]: %s" % (addr, data) - response = str(eval(data)) + response = str(eval('xend.manager.'+data)) except: # Catch all exceptions and turn into an error response: @@ -242,9 +106,9 @@ def daemon_loop(): # Do work for every console interface that hit in the poll set. for (fd, events) in fdset: - if not console_interface.interface_list.has_key(fd): + if not xend.console.interface.interface_list.has_key(fd): continue - con_if = console_interface.interface_list[fd] + con_if = xend.console.interface.interface_list[fd] # If the interface is listening, check for pending connections. if con_if.listening(): @@ -290,7 +154,7 @@ def daemon_loop(): # and notify the remote end. work_done = False while not wbuf.empty() and port.space_to_write_request(): - msg = xend_utils.message(0, 0, 0) + msg = xend.utils.message(0, 0, 0) msg.append_payload(wbuf.read(msg.MAX_PAYLOAD)) port.write_request(msg) work_done = True @@ -347,7 +211,7 @@ def daemon_loop(): # Send as much pending console data as there is room for. while not wbuf.empty() and port.space_to_write_request(): - msg = xend_utils.message(0, 0, 0) + msg = xend.utils.message(0, 0, 0) msg.append_payload(wbuf.read(msg.MAX_PAYLOAD)) port.write_request(msg) work_done = True @@ -401,7 +265,7 @@ def start_daemon(): return 1 # Ensure that zombie children are automatically reaped. - xend_utils.autoreap() + xend.utils.autoreap() # Fork -- parent writes the PID file and exits. pid = os.fork() @@ -428,27 +292,3 @@ def start_daemon(): def stop_daemon(): return cleanup_daemon(kill=True) - - - -def main(): - xend_utils.autoreap() - if not sys.argv[1:]: - print 'usage: %s {start|stop|restart}' % sys.argv[0] - elif os.fork(): - pid, status = os.wait() - return status >> 8 - elif sys.argv[1] == 'start': - return start_daemon() - elif sys.argv[1] == 'stop': - return stop_daemon() - elif sys.argv[1] == 'restart': - return stop_daemon() or start_daemon() - else: - print 'not an option:', sys.argv[1] - return 1 - - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/tools/xend/lib/manager.py b/tools/xend/lib/manager.py new file mode 100644 index 0000000000..092caa02fc --- /dev/null +++ b/tools/xend/lib/manager.py @@ -0,0 +1,39 @@ + +############################################################# +## xend/manager.py -- Management-interface functions for Xend +## Copyright (c) 2004, K A Fraser (University of Cambridge) +############################################################# + +import xend.console, xend.main, xend.utils + + +## +## new_control_interface: +## Create a new control interface with the specified domain 'dom'. +## The console port may also be specified; otehrwise a suitable port is +## automatically allocated. +## +def new_control_interface(dom, console_port=-1): + # Allocate an event channel. Clear pending notifications. + port = xend.utils.port(dom) + xend.main.notifier.clear(port.local_port, xend.main.notifier.NORMAL) + xend.main.notifier.clear(port.local_port, xend.main.notifier.DISCONNECT) + + # If necessary, compute a suitable TCP port for console I/O. + if console_port < 0: + console_port = 9600 + port.local_port + + # Create a listenign console interface. + con_if = xend.console.interface(console_port, port.local_port) + con_if.listen() + + # Add control state to the master list. + xend.main.control_list[port.local_port] = \ + (port, xend.utils.buffer(), xend.utils.buffer(), con_if) + + # Construct the successful response to be returned to the requester. + response = { 'success': True } + response['local_port'] = port.local_port + response['remote_port'] = port.remote_port + response['console_port'] = console_port + return response diff --git a/tools/xend/xend_utils.c b/tools/xend/lib/utils.c index 81b101e5c8..de832a1761 100644 --- a/tools/xend/xend_utils.c +++ b/tools/xend/lib/utils.c @@ -1,5 +1,5 @@ /****************************************************************************** - * xend_utils.c + * utils.c * * Copyright (c) 2004, K A Fraser */ @@ -409,7 +409,7 @@ static PyObject *xu_port_write_request(PyObject *self, PyObject *args) if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) ) { - PyErr_SetString(PyExc_TypeError, "expected a xend_utils.message"); + PyErr_SetString(PyExc_TypeError, "expected a xend.utils.message"); return NULL; } @@ -467,7 +467,7 @@ static PyObject *xu_port_write_response(PyObject *self, PyObject *args) if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) ) { - PyErr_SetString(PyExc_TypeError, "expected a xend_utils.message"); + PyErr_SetString(PyExc_TypeError, "expected a xend.utils.message"); return NULL; } @@ -994,13 +994,13 @@ static PyMethodDef xu_methods[] = { { NULL, NULL, 0, NULL } }; -PyMODINIT_FUNC initxend_utils(void) +PyMODINIT_FUNC initutils(void) { PyObject *m, *d; - m = Py_InitModule("xend_utils", xu_methods); + m = Py_InitModule("xend.utils", xu_methods); d = PyModule_GetDict(m); - port_error = PyErr_NewException("xend_utils.PortError", NULL, NULL); + port_error = PyErr_NewException("xend.utils.PortError", NULL, NULL); PyDict_SetItemString(d, "PortError", port_error); } diff --git a/tools/xend/setup.py b/tools/xend/setup.py index 9bc967785f..3dc84d61fa 100644 --- a/tools/xend/setup.py +++ b/tools/xend/setup.py @@ -1,11 +1,17 @@ from distutils.core import setup, Extension -module = Extension("xend_utils", - include_dirs = ["../xc/lib", - "../../xenolinux-sparse/include"], - library_dirs = ["../xc/lib"], - libraries = ["xc"], - sources = ["xend_utils.c"]) +utils = Extension("utils", + include_dirs = ["../xc/lib", + "../../xenolinux-sparse/include"], + library_dirs = ["../xc/lib"], + libraries = ["xc"], + sources = ["lib/utils.c"]) -setup(name = "xend_utils", version = "1.0", ext_modules = [module]) +setup(name = "xend", + version = "1.0", + packages = ["xend"], + package_dir = { "xend" : "lib" }, + ext_package = "xend", + ext_modules = [ utils ] + ) |