bitkeeper revision 1.1327.2.9 (426f9bfcIjY9QAFCPqWBbFw35vclow)

Add support for unix-domain sockets on xend.
Remove some dead code.
Signed-off-by: Mike Wray <mike.wray@hp.com>
This commit is contained in:
mjw@wray-m-3.hpl.hp.com committed 2005-04-27 14:04:44 +00:00
1 parent 890ea518d9
commit 084b3e366e
33 files changed
+337 -723

No files matched your search

-1
View File
@@ -12,7 +12,6 @@ from xen.xend.XendLogging import log
import resource
import http
import httpserver
import defer
def uri_pathlist(p):
"""Split a path into a list.
+1 -1
View File
@@ -20,7 +20,7 @@ class SrvConstructor:
def __init__(self, klass):
"""Create a constructor. It is assumed that the class
should be imported as 'import klass from klass'.
should be imported as 'from xen.xend.server.klass import klass'.
klass name of its class
"""
-3
View File
@@ -1,3 +0,0 @@
class Deferred:
pass
+23 -14
View File
@@ -4,6 +4,8 @@ import string
import socket
import types
from urllib import quote, unquote
import os
import os.path
from xen.xend import sxp
from xen.xend.Args import ArgError
@@ -184,7 +186,9 @@ class HttpServerRequest(http.HttpRequest):
@param val: the value
"""
if isinstance(val, ThreadRequest):
if val is None:
return val
elif isinstance(val, ThreadRequest):
return val
elif self.useSxp():
self.setHeader("Content-Type", sxp.mime_type)
@@ -316,18 +320,23 @@ class HttpServer:
def getResource(self, req):
return self.root.getRequestResource(req)
class UnixHttpServer(HttpServer):
def main():
root = SrvDir()
a = root.add("a", SrvDir())
b = root.add("b", SrvDir())
server = HttpServer(root=root)
server.run()
if __name__ == "__main__":
main()
def __init__(self, path=None, root=None):
HttpServer.__init__(self, interface='localhost', root=root)
self.path = path
def bind(self):
pathdir = os.path.dirname(self.path)
if not os.path.exists(pathdir):
os.makedirs(pathdir)
else:
try:
os.unlink(self.path)
except SystemExit:
raise
except Exception, ex:
pass
self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
#self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind(self.path)
+1 -2
View File
@@ -24,7 +24,7 @@ class File(Resource):
if self.type:
req.setHeader('Content-Type', self.type)
if self.encoding:
rew.setHeader('Content-Encoding', self.encoding)
req.setHeader('Content-Encoding', self.encoding)
req.setHeader('Content-Length', self.getFileSize())
try:
io = file(self.filename, "r")
@@ -40,7 +40,6 @@ class File(Resource):
io.close()
except:
pass
return ''
@@ -1,94 +0,0 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from twisted.protocols import http
from twisted.internet.protocol import ClientCreator
from twisted.internet.defer import Deferred
from twisted.internet import reactor
from XendProtocol import XendClientProtocol, XendRequest
class AsynchXendClient(http.HTTPClient):
"""A subclass of twisted's HTTPClient to deal with a connection to xend.
Makes the request when connected, and delegates handling responses etc.
to its protocol (usually an AsynchXendClientProtocol instance).
"""
def __init__(self, protocol, request):
self.protocol = protocol
self.request = request
def connectionMade(self):
request = self.request
url = self.request.url
self.sendCommand(request.method, url.fullpath())
self.sendHeader('Host', url.location())
for (k, v) in request.headers.items():
self.sendHeader(k, v)
if request.data:
self.sendHeader('Content-Length', len(request.data))
self.endHeaders()
if request.data:
self.transport.write(request.data)
def handleStatus(self, version, status, message):
return self.protocol.handleStatus(version, status, message)
def handleHeader(self, key, val):
return self.protocol.handleHeader(key, val)
def handleResponse(self, data):
return self.protocol.handleResponse(data)
class AsynchXendClientProtocol(XendClientProtocol):
"""An asynchronous xend client. Uses twisted to connect to xend
and make the request. It does not block waiting for the result,
but sets up a deferred that is called when the result becomes available.
Uses AsynchXendClient to manage the connection.
"""
def __init__(self):
self.err = None
self.headers = {}
def xendRequest(self, url, method, args=None):
"""Make a request to xend. The returned deferred is called when
the result is available.
@param url: xend request url
@param method: http method: POST or GET
@param args: request arguments (dict)
@return: deferred
"""
request = XendRequest(url, method, args)
self.deferred = Deferred()
clientCreator = ClientCreator(reactor, AsynchXendClient, self, request)
clientCreator.connectTCP(url.host, url.port)
return self.deferred
def callErrback(self, err):
if not self.deferred.called:
self.err = err
self.deferred.errback(err)
return err
def callCallback(self, val):
if not self.deferred.called:
self.deferred.callback(val)
return val
def handleException(self, err):
return self.callErrback(err)
def handleHeader(self, key, val):
self.headers[key.lower()] = val
def getHeader(self, key):
return self.headers.get(key.lower())
def handleResponse(self, data):
if self.err: return self.err
val = XendClientProtocol.handleResponse(self, data)
if isinstance(val, Exception):
self.callErrback(val)
else:
self.callCallback(val)
return val
+41 -86
View File
@@ -2,7 +2,7 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Client API for the HTTP interface on xend.
Callable as a script - see main().
Supports synchronous or asynchronous connection to xend.
Supports inet or unix connection to xend.
This API is the 'control-plane' for xend.
The 'data-plane' is done separately. For example, consoles
@@ -15,7 +15,9 @@ import types
import sxp
import PrettyPrint
from XendProtocol import XendClientProtocol, SynchXendClientProtocol, XendError
from XendProtocol import HttpXendClientProtocol, \
UnixXendClientProtocol, \
XendError
DEBUG = 0
@@ -32,15 +34,6 @@ def fileof(val):
return val
raise XendError('cannot convert value')
# todo: need to sort of what urls/paths are using for objects.
# e.g. for domains at the moment return '0'.
# should probably return abs path w.r.t. server, e.g. /xend/domain/0.
# As an arg, assume abs path is obj uri, otherwise just id.
# Function to convert to full url: Xend.uri(path), e.g.
# maps /xend/domain/0 to http://wray-m-3.hpl.hp.com:8000/xend/domain/0
# And should accept urls for ids?
class URL:
"""A URL.
"""
@@ -115,7 +108,7 @@ class Xend:
@param root: xend root path on the server
"""
if client is None:
client = SynchXendClientProtocol()
client = HttpXendClientProtocol()
self.client = client
self.bind(srv, root)
@@ -162,9 +155,6 @@ class Xend:
def vneturl(self, id=''):
return self.url.relative('vnet/' + str(id))
def eventurl(self, id=''):
return self.url.relative('event/' + str(id))
def xend(self):
return self.xendGet(self.url)
@@ -262,34 +252,33 @@ class Xend:
def xend_domain_maxmem_set(self, id, memory):
return self.xendPost(self.domainurl(id),
{ 'op' : 'maxmem_set',
'memory' : memory })
{ 'op' : 'maxmem_set',
'memory' : memory })
def xend_domain_mem_target_set(self, id, mem_target):
val = self.xendPost(self.domainurl(id),
{'op' : 'mem_target_set',
'target' : mem_target })
return val
def xend_domain_vif_limit(self, id, vif, credit, period):
return self.xendPost(self.domainurl(id),
{ 'op' : 'vif_credit_limit',
{ 'op' : 'vif_limit_set',
'vif' : vif,
'credit' : credit,
'period' : period })
def xend_domain_vifs(self, id):
def xend_domain_devices(self, id, type):
return self.xendGet(self.domainurl(id),
{ 'op' : 'vifs' })
{'op' : 'devices',
'type' : type })
def xend_domain_vif(self, id, vif):
def xend_domain_device(self, id, type, idx):
return self.xendGet(self.domainurl(id),
{ 'op' : 'vif',
'vif' : vif })
def xend_domain_vbds(self, id):
return self.xendGet(self.domainurl(id),
{'op' : 'vbds'})
def xend_domain_vbd(self, id, vbd):
return self.xendGet(self.domainurl(id),
{'op' : 'vbd',
'vbd' : vbd })
{'op' : 'device',
'type' : type,
'idx' : idx })
def xend_domain_device_create(self, id, config):
return self.xendPost(self.domainurl(id),
{'op' : 'device_create',
@@ -338,63 +327,29 @@ class Xend:
return self.xendPost(self.vneturl(id),
{'op' : 'delete' })
def xend_event_inject(self, sxpr):
val = self.xendPost(self.eventurl(),
{'op' : 'inject',
'event' : fileof(sxpr) })
def xend_domain_mem_target_set(self, id, mem_target):
val = self.xendPost(self.domainurl(id),
{'op' : 'mem_target_set',
'target' : mem_target })
return val
def getAsynchXendClientProtocol():
"""Load AsynchXendClientProtocol on demand to avoid the cost.
def getHttpServer(srv=None):
"""Create and return a xend client.
"""
global AsynchXendClientProtocol
try:
AsynchXendClientProtocol
except:
from XendAsynchProtocol import AsynchXendClientProtocol
return AsynchXendClientProtocol
return Xend(srv=srv, client=XendClientProtocol())
def getAsynchServer():
"""Load AsynchXendClientProtocol and create an asynch xend client.
@return asynch Xend
def getUnixServer(srv=None):
"""Create and return a unix-domain xend client.
"""
getAsynchXendClientProtocol()
return Xend(AsynchXendClientProtocol())
return Xend(client=UnixXendClientProtocol(srv))
def xendmain(srv, asynch, fn, args):
if asynch:
getAsynchXendClientProtocol()
client = AsynchXendClientProtocol()
def xendmain(srv, fn, args, unix=False):
if unix:
xend = getUnixServer(srv)
else:
client = None
xend = Xend(srv=srv, client=client)
xend = getHttpServer(srv)
xend.rc = 0
try:
v = getattr(xend, fn)(*args)
PrettyPrint.prettyprint(v)
return 0
except XendError, err:
print 'ERROR:', err
return 1
if asynch:
def cbok(val):
PrettyPrint.prettyprint(val)
reactor.stop()
def cberr(err):
print 'ERROR:', err
xend.rc = 1
reactor.stop()
v.addCallback(cbok)
v.addErrback(cberr)
reactor.run()
return xend.rc
else:
PrettyPrint.prettyprint(v)
return 0
def main(argv):
"""Call an API function:
@@ -411,16 +366,16 @@ python XendClient.py domain 0
"""
global DEBUG
from getopt import getopt
short_options = 'x:ad'
long_options = ['xend=', 'asynch', 'debug']
short_options = 'x:au:d'
long_options = ['xend=', 'unix=', 'debug']
(options, args) = getopt(argv[1:], short_options, long_options)
srv = None
asynch = 0
unix = 1
for k, v in options:
if k in ['-x', '--xend']:
srv = v
elif k in ['-a', '--asynch']:
asynch = 1
elif k in ['-u', '--unix']:
unix = int(v)
elif k in ['-d', '--debug']:
DEBUG = 1
if len(args):
@@ -431,9 +386,9 @@ python XendClient.py domain 0
args = []
if not fn.startswith('xend'):
fn = 'xend_' + fn
sys.exit(xendmain(srv, asynch, fn, args))
sys.exit(xendmain(srv, fn, args, unix=unix))
if __name__ == "__main__":
main(sys.argv)
else:
server = Xend()
server = getUnixServer()
+1 -35
View File
@@ -778,7 +778,7 @@ class XendDomain:
dominfo = self.domain_lookup(id)
return dominfo.getDeviceByIndex(type, idx)
def domain_vif_credit_limit(self, id, vif, credit, period):
def domain_vif_limit_set(self, id, vif, credit, period):
"""Limit the vif's transmission rate
"""
dominfo = self.domain_lookup(id)
@@ -787,40 +787,6 @@ class XendDomain:
raise XendError("invalid vif")
return dev.setCreditLimit(credit, period)
def domain_vif_ls(self, id):
"""Get list of virtual network interface (vif) indexes for a domain.
@param id: domain
@return: vif indexes
"""
return self.domain_devtype_ls(id, 'vif')
def domain_vif_get(self, id, vif):
"""Get a virtual network interface (vif) from a domain.
@param id: domain
@param vif: vif index
@return: vif device object (or None)
"""
return self.domain_devtype_get(id, 'vif', vif)
def domain_vbd_ls(self, id):
"""Get list of virtual block device (vbd) indexes for a domain.
@param id: domain
@return: vbd indexes
"""
return self.domain_devtype_ls(id, 'vbd')
def domain_vbd_get(self, id, vbd):
"""Get a virtual block device (vbd) from a domain.
@param id: domain
@param vbd: vbd index
@return: vbd device (or None)
"""
return self.domain_devtype_get(id, 'vbd', vbd)
def domain_shadow_control(self, id, op):
"""Shadow page control.
-44
View File
@@ -1,44 +0,0 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Handler for persistent domain configs.
"""
import sxp
import XendDB
import XendDomain
__all__ = [ "XendDomainConfig" ]
class XendDomainConfig:
dbpath = 'config'
def __init__(self):
self.db = XendDB.XendDB(self.dbpath)
def domain_config_ls(self, path):
return self.db.ls(path)
def domain_config_create(self, path, sxpr):
self.db.save(path, sxpr)
pass
def domain_config_delete(self, path):
self.db.delete(path)
def domain_config_instance(self, path):
"""Create a domain from a config.
"""
config = self.db.fetch(path)
xd = XendDomain.instance()
newdom = xd.domain_create(config)
return newdom
def instance():
global inst
try:
inst
except:
inst = XendDomainConfig()
return inst
+37 -3
View File
@@ -1,5 +1,6 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import socket
import httplib
import types
@@ -122,12 +123,19 @@ class XendClientProtocol:
"""
raise NotImplementedError()
class SynchXendClientProtocol(XendClientProtocol):
class HttpXendClientProtocol(XendClientProtocol):
"""A synchronous xend client. This will make a request, wait for
the reply and return the result.
"""
resp = None
request = None
def makeConnection(self, url):
return httplib.HTTPConnection(url.location())
def makeRequest(self, url, method, args):
return XendRequest(url, method, args)
def xendRequest(self, url, method, args=None):
"""Make a request to xend.
@@ -136,8 +144,8 @@ class SynchXendClientProtocol(XendClientProtocol):
@param method: http method: POST or GET
@param args: request arguments (dict)
"""
self.request = XendRequest(url, method, args)
conn = httplib.HTTPConnection(url.location())
self.request = self.makeRequest(url, method, args)
conn = self.makeConnection(url)
if DEBUG: conn.set_debuglevel(1)
conn.request(method, url.fullpath(), self.request.data, self.request.headers)
resp = conn.getresponse()
@@ -154,3 +162,29 @@ class SynchXendClientProtocol(XendClientProtocol):
def getHeader(self, key):
return self.resp.getheader(key)
class UnixConnection(httplib.HTTPConnection):
"""Subclass of Python library HTTPConnection that uses a unix-domain socket.
"""
def __init__(self, path):
httplib.HTTPConnection.__init__(self, 'localhost')
self.path = path
def connect(self):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(self.path)
self.sock = sock
class UnixXendClientProtocol(HttpXendClientProtocol):
"""A synchronous xend client using a unix-domain socket.
"""
XEND_PATH_DEFAULT = '/var/lib/xend/xend-socket'
def __init__(self, path=None):
if path is None:
path = self.XEND_PATH_DEFAULT
self.path = path
def makeConnection(self, url):
return UnixConnection(self.path)
+46 -6
View File
@@ -15,6 +15,7 @@ import sys
import EventServer
from XendLogging import XendLogging
from XendError import XendError
# Initial create of the event server.
eserver = EventServer.instance()
@@ -44,6 +45,9 @@ class XendRoot:
loglevel_default = 'DEBUG'
"""Default for the flag indicating whether xend should run an http server."""
xend_http_server_default = 'no'
"""Default interface address xend listens at. """
xend_address_default = ''
@@ -53,7 +57,13 @@ class XendRoot:
"""Default port xend serves events at. """
xend_event_port_default = '8001'
"""Default inteface address xend listens at for consoles."""
"""Default for the flag indicating whether xend should run a unix-domain server."""
xend_unix_server_default = 'yes'
"""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 = ''
"""Default port xend serves consoles at. """
@@ -157,6 +167,7 @@ class XendRoot:
logfile = self.get_config_value("logfile", self.logfile_default)
loglevel = self.get_config_value("loglevel", self.loglevel_default)
self.logging = XendLogging(logfile, level=loglevel)
self.logging.addLogStderr()
def get_logging(self):
"""Get the XendLogging instance.
@@ -218,15 +229,35 @@ class XendRoot:
"""
return sxp.child_value(self.config, name, val=val)
def get_config_bool(self, name, val=None):
v = self.get_config_value(name, val)
if v in ['yes', '1', 'on', 1, True]:
return True
if v in ['no', '0', 'off', 0, False]:
return False
raise XendError("invalid xend config %s: expected bool: %s" % (name, v))
def get_config_int(self, name, val=None):
v = self.get_config_value(name, val)
try:
return int(v)
except Exception, ex:
raise XendError("invalid xend config %s: expected int: %s" % (name, v))
def get_xend_http_server(self):
"""Get the flag indicating whether xend should run an http server.
"""
return self.get_config_bool("xend-http-server", self.xend_http_server_default)
def get_xend_port(self):
"""Get the port xend listens at for its HTTP interface.
"""
return int(self.get_config_value('xend-port', self.xend_port_default))
return self.get_config_int('xend-port', self.xend_port_default)
def get_xend_event_port(self):
"""Get the port xend listens at for connection to its event server.
"""
return int(self.get_config_value('xend-event-port', self.xend_event_port_default))
return self.get_config_int('xend-event-port', self.xend_event_port_default)
def get_xend_address(self):
"""Get the address xend listens at for its HTTP and event ports.
@@ -236,6 +267,16 @@ class XendRoot:
"""
return self.get_config_value('xend-address', self.xend_address_default)
def get_xend_unix_server(self):
"""Get the flag indicating whether xend should run a unix-domain server.
"""
return self.get_config_bool("xend-unix-server", self.xend_unix_server_default)
def get_xend_unix_path(self):
"""Get the path the xend unix-domain server listens at.
"""
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 the empty string which allows all hosts to connect.
@@ -247,7 +288,7 @@ class XendRoot:
def get_console_port_base(self):
"""Get the base port number used to generate console ports for domains.
"""
return int(self.get_config_value('console-port-base', self.console_port_base_default))
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, '')
@@ -262,8 +303,7 @@ class XendRoot:
return self.get_config_value('vif-script', 'vif-bridge')
def get_vif_antispoof(self):
v = self.get_config_value('vif-antispoof', 'yes')
return v in ['yes', '1', 'on']
return self.get_config_bool('vif-antispoof', 'yes')
def instance():
"""Get an instance of XendRoot.
-2
View File
@@ -1,2 +0,0 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from xen.web.SrvBase import *
+1 -1
View File
@@ -2,7 +2,7 @@
from xen.xend import sxp
from xen.xend import XendConsole
from SrvDir import SrvDir
from xen.web.SrvDir import SrvDir
class SrvConsole(SrvDir):
"""An individual console.
+2 -2
View File
@@ -326,10 +326,10 @@ class Daemon:
self.createFactories()
self.listenEvent(xroot)
self.listenChannels()
serverthread = SrvServer.create(bridge=1)
servers = SrvServer.create()
self.daemonize()
print 'running serverthread...'
serverthread.start()
servers.start()
except Exception, ex:
print >>sys.stderr, 'Exception starting xend:', ex
if DEBUG:
-3
View File
@@ -1,3 +0,0 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from xen.web.SrvBase import *
from xen.web.SrvDir import *
+1 -1
View File
@@ -5,7 +5,7 @@ import os
from xen.xend import sxp
from xen.xend import XendDmesg
from SrvDir import SrvDir
from xen.web.SrvDir import SrvDir
class SrvDmesg(SrvDir):
"""Xen Dmesg output.
+28 -36
View File
@@ -8,7 +8,7 @@ from xen.xend import XendConsole
from xen.xend import PrettyPrint
from xen.xend.Args import FormFn
from SrvDir import SrvDir
from xen.web.SrvDir import SrvDir
class SrvDomain(SrvDir):
"""Service managing a single domain.
@@ -35,10 +35,6 @@ class SrvDomain(SrvDir):
return val
def op_pause(self, op, req):
# Pause doesn't need a thread, but request one for testing.
return req.threadRequest(self.do_pause, op, req)
def do_pause(self, op, req):
val = self.xd.domain_pause(self.dom.name)
return val
@@ -113,6 +109,31 @@ class SrvDomain(SrvDir):
['memory', 'int']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_mem_target_set(self, op, req):
fn = FormFn(self.xd.domain_mem_target_set,
[['dom', 'str'],
['target', 'int']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_devices(self, op, req):
fn = FormFn(self.xd.domain_devtype_ls,
[['dom', 'str'],
['type', 'str']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_device(self, op, req):
fn = FormFn(self.xd.domain_devtype_get,
[['dom', 'str'],
['type', 'str'],
['idx', 'int']])
val = fn(req.args, {'dom': self.dom.id})
if val:
return val.sxpr()
else:
raise XendError("invalid device")
def op_device_create(self, op, req):
fn = FormFn(self.xd.domain_device_create,
@@ -145,8 +166,8 @@ class SrvDomain(SrvDir):
val = fn(req.args, {'dom': self.dom.id})
return val
def op_vif_credit_limit(self, op, req):
fn = FormFn(self.xd.domain_vif_credit_limit,
def op_vif_limit_set(self, op, req):
fn = FormFn(self.xd.domain_vif_limit_set,
[['dom', 'str'],
['vif', 'int'],
['credit', 'int'],
@@ -154,35 +175,6 @@ class SrvDomain(SrvDir):
val = fn(req.args, {'dom': self.dom.id})
return val
def op_vifs(self, op, req):
devs = self.xd.domain_vif_ls(self.dom.id)
return [ dev.sxpr() for dev in devs ]
def op_vif(self, op, req):
fn = FormFn(self.xd.domain_vif_get,
[['dom', 'str'],
['vif', 'str']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_vbds(self, op, req):
devs = self.xd.domain_vbd_ls(self.dom.id)
return [ dev.sxpr() for dev in devs ]
def op_vbd(self, op, req):
fn = FormFn(self.xd.domain_vbd_get,
[['dom', 'str'],
['vbd', 'str']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_mem_target_set(self, op, req):
fn = FormFn(self.xd.domain_mem_target_set,
[['dom', 'str'],
['target', 'int']])
val = fn(req.args, {'dom': self.dom.id})
return val
def render_POST(self, req):
return self.perform(req)
+1 -1
View File
@@ -11,7 +11,7 @@ from xen.xend.Args import FormFn
from xen.xend.XendError import XendError
from xen.xend.XendLogging import log
from SrvDir import SrvDir
from xen.web.SrvDir import SrvDir
from SrvDomain import SrvDomain
class SrvDomainDir(SrvDir):
@@ -1,41 +0,0 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from xen.xend import sxp
from xen.xend import EventServer
from SrvDir import SrvDir
class SrvEventDir(SrvDir):
"""Event directory.
"""
def __init__(self):
SrvDir.__init__(self)
self.eserver = EventServer.instance()
def op_inject(self, op, req):
eventstring = req.args.get('event')
pin = sxp.Parser()
pin.input(eventstring)
pin.input_eof()
sxpr = pin.get_val()
self.eserver.inject(sxp.name(sxpr), sxpr)
if req.use_sxp:
sxp.name(sxpr)
else:
return '<code>' + eventstring + '</code>'
def render_POST(self, req):
return self.perform(req)
def form(self, req):
action = req.prePathURL()
req.write('<form method="post" action="%s" enctype="multipart/form-data">'
% action)
req.write('<button type="submit" name="op" value="inject">Inject</button>')
req.write('Event <input type="text" name="event" size="40"><br>')
req.write('</form>')
req.write('<form method="post" action="%s" enctype="multipart/form-data">'
% action)
req.write('<button type="submit" name="op" value="inject">Inject</button>')
req.write('Event file<input type="file" name="event"><br>')
req.write('</form>')
+1 -1
View File
@@ -2,7 +2,7 @@
import os
from SrvDir import SrvDir
from xen.web.SrvDir import SrvDir
from xen.xend import sxp
from xen.xend import XendNode
from xen.xend.Args import FormFn
+1 -2
View File
@@ -2,7 +2,7 @@
from xen.xend import XendRoot
xroot = XendRoot.instance()
from SrvDir import SrvDir
from xen.web.SrvDir import SrvDir
class SrvRoot(SrvDir):
"""The root of the xend server.
@@ -16,7 +16,6 @@ class SrvRoot(SrvDir):
('node', 'SrvNode' ),
('domain', 'SrvDomainDir' ),
('console', 'SrvConsoleDir' ),
('event', 'SrvEventDir' ),
('vnet', 'SrvVnetDir' ),
]
+29 -14
View File
@@ -27,23 +27,38 @@
from threading import Thread
from xen.web.httpserver import HttpServer
from xen.web.httpserver import HttpServer, UnixHttpServer
from xen.xend import XendRoot
xroot = XendRoot.instance()
from xen.xend import XendRoot; xroot = XendRoot.instance()
from xen.xend import Vifctl
from SrvRoot import SrvRoot
from SrvDir import SrvDir
from xen.web.SrvDir import SrvDir
def create(port=None, interface=None, bridge=0):
if port is None:
port = xroot.get_xend_port()
if interface is None:
interface = xroot.get_xend_address()
if bridge:
from SrvRoot import SrvRoot
class XendServers:
def __init__(self):
self.servers = []
def add(self, server):
self.servers.append(server)
def start(self):
Vifctl.network('start')
for server in self.servers:
thread = Thread(target=server.run)
thread.start()
def create():
root = SrvDir()
root.putChild('xend', SrvRoot())
server = HttpServer(root=root, interface=interface, port=port)
thread = Thread(name="XendHttpServer", target=server.run)
return thread
servers = XendServers()
if xroot.get_xend_http_server():
port = xroot.get_xend_port()
interface = xroot.get_xend_address()
servers.add(HttpServer(root=root, interface=interface, port=port))
if xroot.get_xend_unix_server():
path = xroot.get_xend_unix_path()
print 'unix path=', path
servers.add(UnixHttpServer(path=path, root=root))
return servers
-239
View File
@@ -1,239 +0,0 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from xen.web import http
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
from SrvDir import SrvDir
class SrvDomain(SrvDir):
"""Service managing a single domain.
"""
def __init__(self, dom):
SrvDir.__init__(self)
self.dom = dom
self.xd = XendDomain.instance()
self.xconsole = XendConsole.instance()
def op_configure(self, op, req):
"""Configure an existing domain.
Configure is unusual in that it requires a domain id,
not a domain name.
"""
fn = FormFn(self.xd.domain_configure,
[['dom', 'int'],
['config', 'sxpr']])
deferred = fn(req.args, {'dom': self.dom.dom})
deferred.addErrback(self._op_configure_err, req)
return deferred
def _op_configure_err(self, err, req):
req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err))
return str(err)
def op_unpause(self, op, req):
val = self.xd.domain_unpause(self.dom.name)
return val
def op_pause(self, op, req):
val = self.xd.domain_pause(self.dom.name)
return val
def op_shutdown(self, op, req):
fn = FormFn(self.xd.domain_shutdown,
[['dom', 'str'],
['reason', 'str']])
val = fn(req.args, {'dom': self.dom.id})
req.setResponseCode(http.ACCEPTED)
req.setHeader("Location", "%s/.." % req.prePathURL())
return val
def op_destroy(self, op, req):
fn = FormFn(self.xd.domain_destroy,
[['dom', 'str'],
['reason', 'str']])
val = fn(req.args, {'dom': self.dom.id})
req.setHeader("Location", "%s/.." % req.prePathURL())
return val
def op_save(self, op, req):
fn = FormFn(self.xd.domain_save,
[['dom', 'str'],
['file', 'str']])
deferred = fn(req.args, {'dom': self.dom.id})
deferred.addCallback(self._op_save_cb, req)
deferred.addErrback(self._op_save_err, req)
return deferred
def _op_save_cb(self, val, req):
return 0
def _op_save_err(self, err, req):
req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err))
return str(err)
def op_migrate(self, op, req):
fn = FormFn(self.xd.domain_migrate,
[['dom', 'str'],
['destination', 'str'],
['live', 'int']])
deferred = fn(req.args, {'dom': self.dom.id})
print 'op_migrate>', deferred
deferred.addCallback(self._op_migrate_cb, req)
deferred.addErrback(self._op_migrate_err, req)
return deferred
def _op_migrate_cb(self, info, req):
print '_op_migrate_cb>', info, req
#req.setResponseCode(http.ACCEPTED)
host = info.dst_host
port = info.dst_port
dom = info.dst_dom
url = "http://%s:%d/xend/domain/%d" % (host, port, dom)
req.setHeader("Location", url)
print '_op_migrate_cb> url=', url
return url
def _op_migrate_err(self, err, req):
print '_op_migrate_err>', err, req
req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err))
return str(err)
def op_pincpu(self, op, req):
fn = FormFn(self.xd.domain_pincpu,
[['dom', 'str'],
['cpu', 'int']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_cpu_bvt_set(self, op, req):
fn = FormFn(self.xd.domain_cpu_bvt_set,
[['dom', 'str'],
['mcuadv', 'int'],
['warpback', 'int'],
['warpvalue', 'int'],
['warpl', 'long'],
['warpu', 'long']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_cpu_fbvt_set(self, op, req):
fn = FormFn(self.xd.domain_cpu_fbvt_set,
[['dom', 'str'],
['mcuadv', 'int'],
['warp', 'int'],
['warpl', 'int'],
['warpu', 'int']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_maxmem_set(self, op, req):
fn = FormFn(self.xd.domain_maxmem_set,
[['dom', 'str'],
['memory', 'int']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_device_create(self, op, req):
fn = FormFn(self.xd.domain_device_create,
[['dom', 'str'],
['config', 'sxpr']])
d = fn(req.args, {'dom': self.dom.id})
return d
def op_device_destroy(self, op, req):
fn = FormFn(self.xd.domain_device_destroy,
[['dom', 'str'],
['type', 'str'],
['idx', 'str']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_vifs(self, op, req):
devs = self.xd.domain_vif_ls(self.dom.id)
return [ dev.sxpr() for dev in devs ]
def op_vif(self, op, req):
fn = FormFn(self.xd.domain_vif_get,
[['dom', 'str'],
['vif', 'str']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_vbds(self, op, req):
devs = self.xd.domain_vbd_ls(self.dom.id)
return [ dev.sxpr() for dev in devs ]
def op_vbd(self, op, req):
fn = FormFn(self.xd.domain_vbd_get,
[['dom', 'str'],
['vbd', 'str']])
val = fn(req.args, {'dom': self.dom.id})
return val
def render_POST(self, req):
return self.perform(req)
def render_GET(self, req):
op = req.args.get('op')
if op and op[0] in ['vifs', 'vif', 'vbds', 'vbd']:
return self.perform(req)
if self.use_sxp(req):
req.setHeader("Content-Type", sxp.mime_type)
sxp.show(self.dom.sxpr(), out=req)
else:
req.write('<html><head></head><body>')
self.print_path(req)
#self.ls()
req.write('<p>%s</p>' % 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('<p><a href="/xend/console/%s">Console %s</a></p>'
% (cid, cid))
req.write('<p><a href="%s">Connect to console</a></p>'
% cinfo.uri())
if self.dom.config:
req.write("<code><pre>")
PrettyPrint.prettyprint(self.dom.config, out=req)
req.write("</pre></code>")
self.form(req)
req.write('</body></html>')
return ''
def form(self, req):
url = req.prePathURL()
req.write('<form method="post" action="%s">' % url)
req.write('<input type="submit" name="op" value="unpause">')
req.write('<input type="submit" name="op" value="pause">')
req.write('</form>')
req.write('<form method="post" action="%s">' % url)
req.write('<input type="submit" name="op" value="destroy">')
req.write('<input type="radio" name="reason" value="halt" checked>Halt')
req.write('<input type="radio" name="reason" value="reboot">Reboot')
req.write('</form>')
req.write('<form method="post" action="%s">' % url)
req.write('<input type="submit" name="op" value="shutdown">')
req.write('<input type="radio" name="reason" value="poweroff" checked>Poweroff')
req.write('<input type="radio" name="reason" value="halt">Halt')
req.write('<input type="radio" name="reason" value="reboot">Reboot')
req.write('</form>')
req.write('<form method="post" action="%s">' % url)
req.write('<br><input type="submit" name="op" value="save">')
req.write(' To file: <input type="text" name="file">')
req.write('</form>')
req.write('<form method="post" action="%s">' % url)
req.write('<br><input type="submit" name="op" value="migrate">')
req.write(' To host: <input type="text" name="destination">')
req.write('<input type="checkbox" name="live" value="1">Live')
req.write('</form>')
+1 -1
View File
@@ -5,7 +5,7 @@ from xen.xend.Args import FormFn
from xen.xend import PrettyPrint
from xen.xend import XendVnet
from SrvDir import SrvDir
from xen.web.SrvDir import SrvDir
class SrvVnet(SrvDir):
+1 -1
View File
@@ -4,7 +4,7 @@ from xen.web import static
from xen.xend import XendRoot
from SrvDir import SrvDir
from xen.web.SrvDir import SrvDir
class SrvXendLog(SrvDir):
"""Xend log.
+2 -2
View File
@@ -425,10 +425,10 @@ class BlkifController(DevController):
for a domain.
"""
def __init__(self, dctype, vm, recreate=False):
def __init__(self, vm, recreate=False):
"""Create a block device controller.
"""
DevController.__init__(self, dctype, vm, recreate=recreate)
DevController.__init__(self, vm, recreate=recreate)
self.backends = {}
self.backendId = 0
self.rcvr = None
+38 -12
View File
@@ -66,6 +66,8 @@ class ChannelFactory:
def __init__(self):
"""Constructor - do not use. Use the channelFactory function."""
self.notifier = xu.notifier()
# Register interest in all virqs.
# Unfortunately virqs do not seem to be delivered.
self.bind_virq(VIRQ_MISDIRECT)
self.bind_virq(VIRQ_TIMER)
self.bind_virq(VIRQ_DEBUG)
@@ -97,6 +99,7 @@ class ChannelFactory:
def main(self):
"""Main routine for the thread.
Reads the notifier and dispatches to channels.
"""
while True:
if self.thread == None: return
@@ -224,18 +227,23 @@ def channelFactory():
return inst
class Channel:
"""Chanel to a domain.
Maintains a list of device handlers to dispatch requests to, based
on the request type.
"""
def __init__(self, factory, dom, local_port, remote_port):
self.factory = factory
self.dom = int(dom)
# Registered devices.
# Registered device handlers.
self.devs = []
# Devices indexed by the message types they handle.
# Handlers indexed by the message types they handle.
self.devs_by_type = {}
self.port = self.factory.createPort(self.dom,
local_port=local_port,
remote_port=remote_port)
self.closed = False
# Queue of waiters for responses to requests.
self.queue = ResponseQueue(self)
# Make sure the port will deliver all the messages.
self.port.register(TYPE_WILDCARD)
@@ -298,11 +306,11 @@ class Channel:
def registerDevice(self, types, dev):
"""Register a device controller.
"""Register a device message handler.
@param types: message types the controller handles
@param types: message types handled
@type types: array of ints
@param dev: device controller
@param dev: device handler
"""
if self.closed: return
self.devs.append(dev)
@@ -310,9 +318,9 @@ class Channel:
self.devs_by_type[ty] = dev
def deregisterDevice(self, dev):
"""Remove the registration for a device controller.
"""Remove the registration for a device handler.
@param dev: device controller
@param dev: device handler
"""
if dev in self.devs:
self.devs.remove(dev)
@@ -321,16 +329,20 @@ class Channel:
del self.devs_by_type[ty]
def getDevice(self, type):
"""Get the device controller handling a message type.
"""Get the handler for a message type.
@param type: message type
@type type: int
@return: controller or None
@rtype: device controller
@rtype: device handler
"""
return self.devs_by_type.get(type)
def requestReceived(self, msg):
"""A request has been received on the channel.
Disptach it to the device handlers.
Called from the channel factory thread.
"""
if DEBUG:
print 'Channel>requestReceived>', self,
printMsg(msg)
@@ -340,7 +352,7 @@ class Channel:
if dev:
responded = dev.requestReceived(msg, ty, subty)
elif DEBUG:
print "Channel>requestReceived> No device", self,
print "Channel>requestReceived> No device handler", self,
printMsg(msg)
else:
pass
@@ -348,6 +360,8 @@ class Channel:
self.writeResponse(msg)
def writeRequest(self, msg):
"""Write a request to the channel.
"""
if DEBUG:
print 'Channel>writeRequest>', self,
printMsg(msg, all=True)
@@ -356,6 +370,8 @@ class Channel:
return 1
def writeResponse(self, msg):
"""Write a response to the channel.
"""
if DEBUG:
print 'Channel>writeResponse>', self,
printMsg(msg, all=True)
@@ -364,6 +380,9 @@ class Channel:
return 1
def readRequest(self):
"""Read a request from the channel.
Called internally.
"""
if self.closed:
val = None
else:
@@ -371,6 +390,9 @@ class Channel:
return val
def readResponse(self):
"""Read a response from the channel.
Called internally.
"""
if self.closed:
val = None
else:
@@ -399,6 +421,10 @@ class Channel:
return self.queue.call(msg, timeout)
def responseReceived(self, msg):
"""A response has been received, look for a waiter to
give it to.
Called internally.
"""
if DEBUG:
print 'Channel>responseReceived>', self,
printMsg(msg)
@@ -407,7 +433,6 @@ class Channel:
def virq(self):
self.factory.virq()
class Response:
"""Entry in the response queue.
Used to signal a response to a message.
@@ -463,7 +488,8 @@ class ResponseQueue:
return r
def response(self, mid, msg):
"""Process a response.
"""Process a response - signals any waiter that a response
has arrived.
"""
try:
self.lock.acquire()
+2 -2
View File
@@ -326,8 +326,8 @@ class ConsoleController(DevController):
"""Device controller for all the consoles for a domain.
"""
def __init__(self, dctype, vm, recreate=False):
DevController.__init__(self, dctype, vm, recreate=recreate)
def __init__(self, vm, recreate=False):
DevController.__init__(self, vm, recreate=recreate)
self.rcvr = None
def initController(self, recreate=False, reboot=False):
+75 -61
View File
@@ -9,7 +9,7 @@ from messages import msgTypeName, printMsg, getMessageType
DEBUG = 0
class CtrlMsgRcvr:
"""Dispatcher class for messages on a control channel.
"""Utility class to dispatch messages on a control channel.
Once I{registerChannel} has been called, our message types are registered
with the channel. The channel will call I{requestReceived}
when a request arrives if it has one of our message types.
@@ -105,65 +105,32 @@ class CtrlMsgRcvr:
if self.channel:
self.channel.deregisterDevice(self)
class DevControllerType:
"""Abstract class for device controller types.
"""
def __init__(self, type):
self.type = type
def getType(self):
"""Get the device controller type name.
"""
return self.type
def createDevController(self, vm, recreate=False):
"""Create a device controller for a domain.
Must be implemented in subclass.
"""
raise NotImplementedError()
class SimpleDevControllerType(DevControllerType):
"""Device controller type that simply wraps a controller
class and uses its constructor to create instances.
"""
def __init__(self, type, devControllerClass):
DevControllerType.__init__(self, type)
self.devControllerClass = devControllerClass
def createDevController(self, vm, recreate=False):
"""Create a device controller for a domain.
"""
ctrl = self.devControllerClass(self, vm, recreate=recreate)
ctrl.initController(recreate=recreate)
return ctrl
class DevControllerTable:
"""Table of device controller types, indexed by type name.
"""Table of device controller classes, indexed by type name.
"""
def __init__(self):
self.controllerTypes = {}
self.controllerClasses = {}
def getDevControllerType(self, type):
return self.controllerTypes.get(type)
def getDevControllerClass(self, type):
return self.controllerClasses.get(type)
def addDevControllerType(self, dctype):
self.controllerTypes[dctype.getType()] = dctype
return dctype
def addDevControllerClass(self, klass):
self.controllerClasses[klass.getType()] = klass
def delDevControllerType(self, type):
if type in self.controllerTypes:
del self.controllerTypes[type]
def delDevControllerClass(self, type):
if type in self.controllerClasses:
del self.controllerClasses[type]
def createDevController(self, type, vm, recreate=False):
dctype = self.getDevControllerType(type)
if not dctype:
klass = self.getDevControllerClass(type)
if not klass:
raise XendError("unknown device type: " + type)
return dctype.createDevController(vm, recreate=recreate)
return klass.createDevController(vm, recreate=recreate)
def getDevControllerTable():
"""Singleton constructor for the controller table.
"""
global devControllerTable
try:
devControllerTable
@@ -171,12 +138,11 @@ def getDevControllerTable():
devControllerTable = DevControllerTable()
return devControllerTable
def addDevControllerType(dctype):
return getDevControllerTable().addDevControllerType(dctype)
def addDevControllerClass(name, klass):
ty = SimpleDevControllerType(name, klass)
return addDevControllerType(ty)
"""Add a device controller class to the controller table.
"""
klass.name = name
getDevControllerTable().addDevControllerClass(klass)
def createDevController(name, vm, recreate=False):
return getDevControllerTable().createDevController(name, vm, recreate=recreate)
@@ -189,17 +155,29 @@ class DevController:
"""
def __init__(self, dctype, vm, recreate=False):
self.dctype = dctype
name = None
def createDevController(klass, vm, recreate=False):
"""Class method to create a dev controller.
"""
ctrl = klass(vm, recreate=recreate)
ctrl.initController(recreate=recreate)
return ctrl
createDevController = classmethod(createDevController)
def getType(klass):
return klass.name
getType = classmethod(getType)
def __init__(self, vm, recreate=False):
self.destroyed = False
self.vm = vm
self.deviceId = 0
self.devices = {}
self.device_order = []
def getType(self):
return self.dctype.getType()
def getDevControllerType(self):
return self.dctype
@@ -222,6 +200,14 @@ class DevController:
# Redefinitions must have the same arguments.
def initController(self, recreate=False, reboot=False):
"""Initialise the controller. Called when the controller is
first created, and again after the domain is rebooted (with reboot True).
If called with recreate True (and reboot False) the controller is being
recreated after a xend restart.
As this can be a re-init (after reboot) any controller state should
be reset. For example the destroyed flag.
"""
self.destroyed = False
if reboot:
self.rebootDevices()
@@ -229,12 +215,19 @@ class DevController:
def newDevice(self, id, config, recreate=False):
"""Create a device with the given config.
Must be defined in subclass.
Called with recreate True when the device is being recreated after a
xend restart.
@return device
"""
raise NotImplementedError()
def createDevice(self, config, recreate=False, change=False):
"""Create a device and attach to its front- and back-ends.
If recreate is true the device is being recreated after a xend restart.
If change is true the device is a change to an existing domain,
i.e. it is being added at runtime rather than when the domain is created.
"""
dev = self.newDevice(self.nextDeviceId(), config, recreate=recreate)
dev.init(recreate=recreate)
self.addDevice(dev)
@@ -252,7 +245,12 @@ class DevController:
def destroyDevice(self, id, change=False, reboot=False):
"""Destroy a device.
May be defined in subclass."""
May be defined in subclass.
If reboot is true the device is being destroyed for a domain reboot.
The device is not deleted, since it may be recreated later.
"""
dev = self.getDevice(id)
if not dev:
raise XendError("invalid device id: " + id)
@@ -260,12 +258,18 @@ class DevController:
return dev
def deleteDevice(self, id, change=True):
"""Destroy a device and delete it.
Normally called to remove a device from a domain at runtime.
"""
dev = self.destroyDevice(id, change=change)
self.removeDevice(dev)
def destroyController(self, reboot=False):
"""Destroy all devices and clean up.
May be defined in subclass."""
May be defined in subclass.
If reboot is true the controller is being destroyed for a domain reboot.
Called at domain shutdown.
"""
self.destroyed = True
self.destroyDevices(reboot=reboot)
@@ -394,6 +398,13 @@ class Dev:
"""Initialization. Called on initial create (when reboot is False)
and on reboot (when reboot is True). When xend is restarting is
called with recreate True. Define in subclass if needed.
Device instance variables must be defined in the class constructor,
but given null or default values. The real values should be initialised
in this method. This allows devices to be re-initialised.
Since this can be called to re-initialise a device any state flags
should be reset.
"""
self.destroyed = False
@@ -404,7 +415,7 @@ class Dev:
pass
def reboot(self):
"""Reconnect device when the domain is rebooted.
"""Reconnect the device when the domain is rebooted.
"""
self.init(reboot=True)
self.attach()
@@ -435,6 +446,9 @@ class Dev:
If change is True notify destruction (runtime change).
If reboot is True the device is being destroyed for a reboot.
Redefine in subclass if needed.
Called at domain shutdown and when a device is deleted from
a running domain (with change True).
"""
self.destroyed = True
pass
+2 -2
View File
@@ -376,8 +376,8 @@ class NetifController(DevController):
"""Network interface controller. Handles all network devices for a domain.
"""
def __init__(self, dctype, vm, recreate=False):
DevController.__init__(self, dctype, vm, recreate=recreate)
def __init__(self, vm, recreate=False):
DevController.__init__(self, vm, recreate=recreate)
self.channel = None
self.rcvr = None
self.channel = None
+2 -2
View File
@@ -240,10 +240,10 @@ class UsbifController(DevController):
for a domain.
"""
def __init__(self, dctype, vm, recreate=False):
def __init__(self, vm, recreate=False):
"""Create a USB device controller.
"""
DevController.__init__(self, dctype, vm, recreate=recreate)
DevController.__init__(self, vm, recreate=recreate)
self.backends = {}
self.backendId = 0
self.rcvr = None
View File
Whitespace-only changes.
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.