bitkeeper revision 1.1041.5.1 (40e51d24Wg4h3PKvj5VuOULXCYhqbg)

Merge http://xen.bkbits.net:8080/xeno-unstable.bk
into gandalf.hpl.hp.com:/var/bk/xeno-unstable.bk
This commit is contained in:
xenbk@gandalf.hpl.hp.com committed 2004-07-02 08:30:28 +00:00
commit ea9abef278
16 files changed
+471 -386

No files matched your search

+30
View File
@@ -1,6 +1,11 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Client API for the HTTP interface on xend.
Callable as a script - see main().
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.
"""
import sys
import httplib
@@ -27,6 +32,8 @@ class Foo(httplib.HTTPResponse):
def sxprio(sxpr):
"""Convert an sxpr to a string.
"""
io = StringIO()
sxp.show(sxpr, out=io)
print >> io
@@ -80,6 +87,12 @@ def eventurl(location, root, id=''):
return urljoin(location, root, 'event/', id)
def xend_request(url, method, data=None):
"""Make a request to xend.
url xend request url
method http method: POST or GET
data request argument data (dict)
"""
urlinfo = urlparse.urlparse(url)
(uproto, ulocation, upath, uparam, uquery, ufrag) = urlinfo
if DEBUG: print url, urlinfo
@@ -122,20 +135,37 @@ def xend_request(url, method, data=None):
return val
def xend_get(url, args=None):
"""Make a xend request using GET.
Requests using GET are 'safe' and may be repeated without
nasty side-effects.
"""
return xend_request(url, "GET", args)
def xend_call(url, data):
"""Make xend request using POST.
Requests using POST potentially cause side-effects and should
not be repeated unless it really is wanted to do the side
effect again.
"""
return xend_request(url, "POST", data)
class Xend:
"""Default location of the xend server."""
SRV_DEFAULT = "localhost:8000"
"""Default path to the xend root on the server."""
ROOT_DEFAULT = "/xend/"
def __init__(self, srv=None, root=None):
self.bind(srv, root)
def bind(self, srv=None, root=None):
"""Bind to a given server.
srv server location (host:port)
root server xend root path
"""
if srv is None: srv = self.SRV_DEFAULT
if root is None: root = self.ROOT_DEFAULT
if not root.endswith('/'): root += '/'
+15 -5
View File
@@ -1,5 +1,6 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import traceback
from StringIO import StringIO
from twisted.protocols import http
@@ -24,6 +25,7 @@ class SrvDomainDir(SrvDir):
val = None
try:
dom = self.xd.domain_get(x)
if not dom: raise KeyError('No such domain')
val = SrvDomain(dom)
except KeyError, ex:
print 'SrvDomainDir>', ex
@@ -38,6 +40,9 @@ class SrvDomainDir(SrvDir):
return v
def op_create(self, op, req):
"""Create a domain.
Expects the domain config in request parameter 'config' in SXP format.
"""
ok = 0
try:
configstring = req.args.get('config')[0]
@@ -48,7 +53,8 @@ class SrvDomainDir(SrvDir):
config = pin.get_val()
ok = 1
except Exception, ex:
print 'op_create>', ex
print 'op_create> Exception in config', ex
traceback.print_exc()
if not ok:
req.setResponseCode(http.BAD_REQUEST, "Invalid configuration")
return "Invalid configuration"
@@ -60,10 +66,10 @@ class SrvDomainDir(SrvDir):
deferred.addCallback(self._cb_op_create, configstring, req)
return deferred
except Exception, ex:
raise
#return ['err', str(ex) ]
#req.setResponseCode(http.BAD_REQUEST, "Error creating domain")
#return str(ex)
print 'op_create> Exception creating domain:'
traceback.print_exc()
req.setResponseCode(http.BAD_REQUEST, "Error creating domain")
return str(ex)
#return error.ErrorPage(http.BAD_REQUEST,
# "Error creating domain",
# str(ex))
@@ -90,6 +96,8 @@ class SrvDomainDir(SrvDir):
return val
def op_restore(self, op, req):
"""Restore a domain from file.
"""
fn = FormFn(self.xd.domain_restore,
[['file', 'str']])
val = fn(req.args)
@@ -131,6 +139,8 @@ class SrvDomainDir(SrvDir):
req.write('</ul>')
def form(self, req):
"""Generate the form(s) for domain dir operations.
"""
req.write('<form method="post" action="%s" enctype="multipart/form-data">'
% req.prePathURL())
req.write('<button type="submit" name="op" value="create">Create Domain</button>')
+42 -17
View File
@@ -1,3 +1,5 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from twisted.internet import defer
from xen.xend import sxp
@@ -28,6 +30,11 @@ class BlkifControllerFactory(controller.ControllerFactory):
self.registerChannel()
def createInstance(self, dom, recreate=0):
"""Create a block device controller for a domain.
dom domain
recreate if true it's a recreate (after xend restart)
"""
d = self.addDeferred()
blkif = self.getInstanceByDom(dom)
if blkif:
@@ -42,29 +49,50 @@ class BlkifControllerFactory(controller.ControllerFactory):
return d
def getDomainDevices(self, dom):
"""Get the block devices for a domain.
dom domain
returns devices
"""
blkif = self.getInstanceByDom(dom)
return (blkif and blkif.getDevices()) or []
def getDomainDevice(self, dom, vdev):
"""Get a block device from a domain.
dom domain
vdev device index
returns device
"""
blkif = self.getInstanceByDom(dom)
return (blkif and blkif.getDevice(vdev)) or None
def setControlDomain(self, dom, recreate=0):
"""Set the back-end block device controller domain.
dom domain
recreate if true it's a recreate (after xend restart)
"""
if self.dom == dom: return
self.deregisterChannel()
if not recreate:
self.attached = 0
self.dom = dom
self.registerChannel()
#
#if xend.blkif.be_port:
# xend.blkif.recovery = True
#xend.blkif.be_port = xend.main.port_from_dom(dom)
def getControlDomain(self):
"""Get the back-end block device controller domain.
"""
return self.dom
def reattachDevice(self, dom, vdev):
"""Reattach a device (on changing control domain).
dom domain
vdev device index
"""
blkif = self.getInstanceByDom(dom)
if blkif:
blkif.reattachDevice(vdev)
@@ -83,6 +111,9 @@ class BlkifControllerFactory(controller.ControllerFactory):
return attached
def reattached(self):
"""Notify all block interface we have been reattached
(after changing control domain).
"""
for blkif in self.getInstances():
blkif.reattached()
@@ -147,7 +178,6 @@ class BlkDev(controller.Dev):
return val
def destroy(self):
print 'BlkDev>destroy>', self.vdev
PrettyPrint.prettyprint(self.sxpr())
self.controller.send_be_vbd_destroy(self.vdev)
@@ -157,7 +187,6 @@ class BlkifController(controller.Controller):
"""
def __init__(self, factory, dom):
#print 'BlkifController> dom=', dom
controller.Controller.__init__(self, factory, dom)
self.devices = {}
@@ -172,7 +201,6 @@ class BlkifController(controller.Controller):
self.attached = 1
self.evtchn = None
self.registerChannel()
#print 'BlkifController<', 'dom=', self.dom, 'idx=', self.idx
def sxpr(self):
val = ['blkif', ['dom', self.dom]]
@@ -183,8 +211,6 @@ class BlkifController(controller.Controller):
return val
def lostChannel(self):
print 'BlkifController>lostChannel>', 'dom=', self.dom
#self.destroyDevices()
controller.Controller.lostChannel(self)
def getDevices(self):
@@ -201,8 +227,14 @@ class BlkifController(controller.Controller):
def attachDevice(self, vdev, mode, segment, recreate=0):
"""Attach a device to the specified interface.
vdev device index
mode read/write mode
segment segment
recreate if true it's being recreated (after xend restart)
returns deferred
"""
#print 'BlkifController>attach_device>', self.dom, vdev, mode, segment
dev = self.addDevice(vdev, mode, segment)
if not dev: return -1
if recreate:
@@ -214,13 +246,11 @@ class BlkifController(controller.Controller):
return d
def destroy(self):
print 'BlkifController>destroy> dom=', self.dom
def cb_destroy(val):
self.send_be_destroy()
d = self.factory.addDeferred()
d.addCallback(cb_destroy)
self.send_be_disconnect()
#self.destroyDevices()
def destroyDevices(self):
for dev in self.getDevices():
@@ -276,11 +306,6 @@ class BlkifController(controller.Controller):
self.factory.writeRequest(msg)
pass
#def recv_fe_interface_status_changed(self, msg, req):
# (hnd, status, chan) = unpackMsg('blkif_fe_interface_status_changed_t', msg)
# print 'recv_fe_interface_status_changed>', hnd, status, chan
# pass
def send_fe_interface_status_changed(self):
msg = packMsg('blkif_fe_interface_status_changed_t',
{ 'handle' : 0,
+8 -4
View File
@@ -1,3 +1,5 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
from xen.lowlevel import xu
from messages import msgTypeName
@@ -24,14 +26,11 @@ class ChannelFactory:
self.notifier = xu.notifier()
def addChannel(self, channel):
"""Add a channel.
"""Add a channel. Registers with the notifier.
"""
idx = channel.idx
self.channels[idx] = channel
self.notifier.bind(idx)
# Try to wake it up
#self.notifier.unmask(idx)
#channel.notify()
def getChannel(self, idx):
"""Get the channel with the given index (if any).
@@ -40,6 +39,7 @@ class ChannelFactory:
def delChannel(self, idx):
"""Remove the channel with the given index (if any).
Deregisters with the notifier.
"""
if idx in self.channels:
del self.channels[idx]
@@ -288,6 +288,8 @@ class Channel(BaseChannel):
self.getRemotePort()))
def handleNotification(self):
"""Process outstanding messages in repsonse to notification on the port.
"""
if self.closed:
print 'handleNotification> Notification on closed channel', self
return
@@ -299,6 +301,8 @@ class Channel(BaseChannel):
self.notify()
def notify(self):
"""Notify the other end of the port that messages have been processed.
"""
if self.closed: return
self.port.notify()
+3 -21
View File
@@ -1,3 +1,4 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from twisted.internet import reactor
from twisted.internet import protocol
@@ -12,11 +13,6 @@ import controller
from messages import *
from params import *
"""Telnet binary option."""
TRANSMIT_BINARY = '0'
WILL = chr(251)
IAC = chr(255)
class ConsoleProtocol(protocol.Protocol):
"""Asynchronous handler for a console TCP socket.
"""
@@ -36,19 +32,12 @@ class ConsoleProtocol(protocol.Protocol):
self.loseConnection()
return
else:
# KAF: A nice quiet successful connect. Don't bother with telnet
# control sequence -- telnet is not the appropriate protocol here.
# KAF: A nice quiet successful connect.
#self.transport.write("Connected to console %d on domain %d\n"
# % (self.idx, self.controller.dom))
#self.setTelnetTransmitBinary()
eserver.inject('xend.console.connect',
[self.idx, self.addr[0], self.addr[1]])
def setTelnetTransmitBinary(self):
"""Send the sequence to set the telnet TRANSMIT-BINARY option.
"""
self.write(IAC + WILL + TRANSMIT_BINARY)
def dataReceived(self, data):
if self.controller.handleInput(self, data):
self.loseConnection()
@@ -105,7 +94,6 @@ class ConsoleController(controller.Controller):
"""
def __init__(self, factory, dom, console_port):
#print 'ConsoleController> dom=', dom, type(dom)
controller.Controller.__init__(self, factory, dom)
self.majorTypes = [ CMSG_CONSOLE ]
self.status = "new"
@@ -118,7 +106,6 @@ class ConsoleController(controller.Controller):
self.registerChannel()
self.listener = None
self.listen()
#print 'ConsoleController<', 'dom=', self.dom, 'idx=', self.idx
def sxpr(self):
val =['console',
@@ -143,7 +130,6 @@ class ConsoleController(controller.Controller):
def close(self):
try:
#print 'ConsoleController> close dom=', self.dom
self.status = "closed"
if self.conn:
self.conn.loseConnection()
@@ -183,11 +169,11 @@ class ConsoleController(controller.Controller):
self.listen()
def requestReceived(self, msg, type, subtype):
#print '***Console', self.dom, msg.get_payload()
self.rbuf.write(msg.get_payload())
self.handleOutput()
def responseReceived(self, msg, type, subtype):
# Just ignore responses.
pass
def produceRequests(self):
@@ -215,18 +201,14 @@ class ConsoleController(controller.Controller):
Sends it to the connected console (if any).
"""
if self.closed():
#print 'Console>handleOutput> closed'
return -1
if not self.conn:
#print 'Console>handleOutput> not connected'
return 0
while not self.rbuf.empty():
try:
#print 'Console>handleOutput> writing...'
bytes = self.conn.write(self.rbuf.peek())
if bytes > 0:
self.rbuf.discard(bytes)
except socket.error, error:
pass
#print 'Console>handleOutput<'
return 0
+79 -8
View File
@@ -1,3 +1,5 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from twisted.internet import defer
import channel
@@ -5,6 +7,15 @@ from messages import msgTypeName
class CtrlMsgRcvr:
"""Abstract class for things that deal with a control interface to a domain.
Instance variables:
dom : the domain we are a control interface for
majorTypes: list of major message types we are interested in
subTypes : mapping of message subtypes to methods
channel : channel to the domain
idx : channel index
"""
@@ -17,6 +28,12 @@ class CtrlMsgRcvr:
self.idx = None
def requestReceived(self, msg, type, subtype):
"""Dispatch a request to handlers.
msg message
type major message type
subtype minor message type
"""
method = self.subTypes.get(subtype)
if method:
method(msg, 1)
@@ -25,6 +42,12 @@ class CtrlMsgRcvr:
% (msgTypeName(type, subtype), type, subtype)), self
def responseReceived(self, msg, type, subtype):
"""Dispatch a response to handlers.
msg message
type major message type
subtype minor message type
"""
method = self.subTypes.get(subtype)
if method:
method(msg, 0)
@@ -33,9 +56,14 @@ class CtrlMsgRcvr:
% (msgTypeName(type, subtype), type, subtype)), self
def lostChannel(self):
"""Called when the channel to the domain is lost.
"""
pass
def registerChannel(self):
"""Register interest in our major message types with the
channel to our domain.
"""
#print 'CtrlMsgRcvr>registerChannel>', self
self.channel = self.channelFactory.domChannel(self.dom)
self.idx = self.channel.getIndex()
@@ -43,21 +71,32 @@ class CtrlMsgRcvr:
self.channel.registerDevice(self.majorTypes, self)
def deregisterChannel(self):
"""Deregister interest in our major message types with the
channel to our domain.
"""
#print 'CtrlMsgRcvr>deregisterChannel>', self
if self.channel:
self.channel.deregisterDevice(self)
del self.channel
def produceRequests(self):
"""Produce any queued requests.
return number produced
"""
return 0
def writeRequest(self, msg):
"""Write a request to the channel.
"""
if self.channel:
self.channel.writeRequest(msg)
else:
print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self
def writeResponse(self, msg):
"""Write a response to the channel.
"""
if self.channel:
self.channel.writeResponse(msg)
else:
@@ -66,6 +105,13 @@ class CtrlMsgRcvr:
class ControllerFactory(CtrlMsgRcvr):
"""Abstract class for factories creating controllers.
Maintains a table of instances.
Instance variables:
instances : mapping of index to controller instance
dlist : list of deferreds
dom : domain
timeout : deferred timeout
"""
def __init__(self):
@@ -77,34 +123,49 @@ class ControllerFactory(CtrlMsgRcvr):
self.timeout = 10
def addInstance(self, instance):
"""Add a controller instance (under its index).
"""
self.instances[instance.idx] = instance
def getInstance(self, idx):
"""Get a controller instance from its index.
"""
return self.instances.get(idx)
def getInstances(self):
"""Get a list of all controller instances.
"""
return self.instances.values()
def getInstanceByDom(self, dom):
"""Get the controller instance for the given domain.
"""
for inst in self.instances.values():
if inst.dom == dom:
return inst
return None
def delInstance(self, instance):
#print 'ControllerFactory>delInstance>', instance.idx
"""Delete an instance from the table.
"""
if instance.idx in self.instances:
#print 'ControllerFactory>delInstance> remove', instance.idx
del self.instances[instance.idx]
def createInstance(self, dom, recreate=0):
"""Create an instance. Define in a subclass.
"""
raise NotImplementedError()
def instanceClosed(self, instance):
#print 'ControllerFactory>instanceClosed>', instance.idx, instance
"""Callback called when an instance is closed (usually by the instance).
"""
self.delInstance(instance)
def addDeferred(self):
"""Add a deferred object.
returns deferred
"""
d = defer.Deferred()
if self.timeout > 0:
# The deferred will error if not called before timeout.
@@ -113,11 +174,19 @@ class ControllerFactory(CtrlMsgRcvr):
return d
def callDeferred(self, *args):
"""Call the top deferred object
args arguments
"""
if self.dlist:
d = self.dlist.pop(0)
d.callback(*args)
def errDeferred(self, *args):
"""Signal an error to the top deferred object.
args arguments
"""
if self.dlist:
d = self.dlist.pop(0)
d.errback(*args)
@@ -134,15 +203,20 @@ class Controller(CtrlMsgRcvr):
self.idx = None
def close(self):
"""Close the controller.
"""
self.deregisterChannel()
self.lostChannel()
def lostChannel(self):
#print 'Controller>lostChannel>', self, self.factory
"""The controller channel has been lost.
"""
self.factory.instanceClosed(self)
class Dev:
"""Abstract class for a device attached to a device controller.
"""
def __init__(self, controller):
self.controller = controller
self.props = {}
@@ -160,9 +234,6 @@ class Dev:
if k in self.props:
del self.props[k]
#def __repr__(self):
# return str(self.sxpr())
def sxpr(self):
raise NotImplementedError()
-269
View File
@@ -1,269 +0,0 @@
import struct
class Struct:
maxDepth = 10
base = ['x', 'B', 'H', 'I', 'L', 'Q', 'c', 'h', 'i', 'l', 'q', ]
sizes = {'B': 1,
'H': 2,
'I': 4,
'L': 4,
'Q': 8,
'c': 1,
'h': 2,
'i': 4,
'l': 4,
'q': 8,
'x': 1,
}
formats = {
'int8' : 'B',
'int16' : 'H',
'int32' : 'I',
'int64' : 'Q',
'u8' : 'B',
'u16' : 'H',
'u32' : 'I',
'u64' : 'Q'
}
def typedef(self, name, val):
self.formats[name] = val
def struct(self, name, *f):
self.typedef(name, StructInfo(self, f))
def getType(self, name):
return self.formats[name]
def format(self, ty):
d = 0
f = ty
while d < self.maxDepth:
d += 1
f = self.formats[f]
if isinstance(f, StructInfo):
return f.format()
if f in self.base:
return f
return -1
def alignedformat(self, ty):
fmt = self.format(ty)
#print 'alignedformat> %s |%s|' %(ty, fmt)
afmt = self.align(fmt)
#print 'alignedformat< %s |%s| |%s|' % (ty, fmt, afmt)
return afmt
def align(self, fmt):
n1 = 0
afmt = ''
for a in fmt:
n2 = self.getSize(a)
m = n1 % n2
if m:
d = (n2 - m)
afmt += 'x' * d
n1 += d
afmt += a
n1 += n2
return afmt
def fmtsize(self, fmt):
s = 0
for f in fmt:
s += self.getSize(f)
return s
def getSize(self, f):
return self.sizes[f]
def pack(self, ty, data):
return self.getType(ty).pack(data)
def unpack(self, ty, data):
return self.getType(ty).unpack(data)
def show(self):
l = self.formats.keys()
l.sort()
for v in l:
print "%-35s %-10s %s" % (v, self.format(v), self.alignedformat(v))
class StructInfo:
def __init__(self, s, f):
self.fmt = None
self.structs = s
self.fields = f
def alignedformat(self):
if self.afmt: return self.afmt
self.afmt = self.structs.align(self.format())
return self.afmt
def format(self):
if self.fmt: return self.fmt
fmt = ""
for (ty, name) in self.fields:
fmt += self.formatString(ty)
self.fmt = fmt
return fmt
def formatString(self, ty):
if ty in self.fields:
ty = self.fields[ty]
return self.structs.format(ty)
def pack(self, *args):
return struct.pack(self.alignedformat(), *args)
def unpack(self, data):
return struct.unpack(self.alignedformat(), data)
types = Struct()
types.typedef('short' , 'h')
types.typedef('int' , 'i')
types.typedef('long' , 'l')
types.typedef('unsigned short', 'H')
types.typedef('unsigned int' , 'I')
types.typedef('unsigned long' , 'L')
types.typedef('domid_t' , 'u64')
types.typedef('blkif_vdev_t' , 'u16')
types.typedef('blkif_pdev_t' , 'u16')
types.typedef('blkif_sector_t', 'u64')
types.struct('u8[6]',
('u8', 'a1'),
('u8', 'a2'),
('u8', 'a3'),
('u8', 'a4'),
('u8', 'a5'),
('u8', 'a6'))
types.struct('blkif_fe_interface_status_changed_t',
('unsigned int', 'handle'),
('unsigned int', 'status'),
('unsigned int', 'evtchn'))
types.struct('blkif_fe_driver_status_changed_t',
('unsigned int', 'status'),
('unsigned int', 'nr_interfaces'))
types.struct('blkif_fe_interface_connect_t',
('unsigned int' , 'handle'),
('unsigned long', 'shmem_frame'))
types.struct('blkif_fe_interface_disconnect_t',
('unsigned int', 'handle'))
types.struct('blkif_extent_t',
('blkif_pdev_t' , 'device'),
('blkif_sector_t', 'sector_start'),
('blkif_sector_t', 'sector_length'))
types.struct('blkif_be_create_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('unsigned int', 'status'))
types.struct('blkif_be_destroy_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('unsigned int', 'status'))
types.struct('blkif_be_connect_t',
('domid_t' , 'domid'),
('unsigned int' , 'blkif_handle'),
('unsigned int' , 'evtchn'),
('unsigned long', 'shmem_frame'),
('unsigned int' , 'status'))
types.struct('blkif_be_disconnect_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('unsigned int', 'status'))
types.struct('blkif_be_vbd_create_t',
('domid_t' , 'domid'), #Q
('unsigned int', 'blkif_handle'), #I
('blkif_vdev_t', 'vdevice'), #H
('int' , 'readonly'), #i
('unsigned int', 'status')) #I
types.struct('blkif_be_vbd_destroy_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('blkif_vdev_t', 'vdevice'),
('unsigned int', 'status'))
types.struct('blkif_be_vbd_grow_t',
('domid_t' , 'domid'), #Q
('unsigned int' , 'blkif_handle'), #I
('blkif_vdev_t' , 'vdevice'), #H
('blkif_extent_t', 'extent'), #HQQ
('unsigned int' , 'status')) #I
types.struct('blkif_be_vbd_shrink_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('blkif_vdev_t', 'vdevice'),
('unsigned int', 'status'))
types.struct('blkif_be_driver_status_changed_t',
('unsigned int', 'status'),
('unsigned int', 'nr_interfaces'))
types.struct('netif_fe_interface_status_changed_t',
('unsigned int', 'handle'),
('unsigned int', 'status'),
('unsigned int', 'evtchn'),
('u8[6]', 'mac'))
types.struct('netif_fe_driver_status_changed_t',
('unsigned int', 'status'),
('unsigned int', 'nr_interfaces'))
types.struct('netif_fe_interface_connect_t',
('unsigned int', 'handle'),
('unsigned long', 'tx_shmem_frame'),
('unsigned long', 'rx_shmem_frame'))
types.struct('netif_fe_interface_disconnect_t',
('unsigned int', 'handle'))
types.struct('netif_be_create_t',
('domid_t' , 'domid'),
('unsigned int', 'netif_handle'),
('u8[6]' , 'mac'),
('unsigned int', 'status'))
types.struct('netif_be_destroy_t',
('domid_t' , 'domid'),
('unsigned int', 'netif_handle'),
('unsigned int', 'status'))
types.struct('netif_be_connect_t',
('domid_t' , 'domid'),
('unsigned int' , 'netif_handle'),
('unsigned int' , 'evtchn'),
('unsigned long', 'tx_shmem_frame'),
('unsigned long', 'rx_shmem_frame'),
('unsigned int' , 'status'))
types.struct('netif_be_disconnect_t',
('domid_t' , 'domid'),
('unsigned int', 'netif_handle'),
('unsigned int', 'status'))
types.struct('netif_be_driver_status_changed_t',
('unsigned int', 'status'),
('unsigned int', 'nr_interfaces'))
if 1 or __name__ == "__main__":
types.show()
+21
View File
@@ -1,3 +1,5 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import channel
import controller
from messages import *
@@ -7,11 +9,23 @@ class DomainControllerFactory(controller.ControllerFactory):
"""
def createInstance(self, dom):
"""Create a domain controller.
dom domain
returns domain controller
"""
d = DomainController(self, dom)
self.addInstance(d)
return d
def getInstanceByDom(self, dom):
"""Get a domain controller for a domain, creating if necessary.
dom domain
returns domain controller
"""
for inst in self.instances.values():
if inst.dom == dom:
return inst
@@ -21,8 +35,11 @@ class DomainControllerFactory(controller.ControllerFactory):
class DomainController(controller.Controller):
"""Generic controller for a domain.
Used for domain shutdown.
"""
"""Map shutdown reasons to the message type to use.
"""
reasons = {'poweroff' : 'shutdown_poweroff_t',
'reboot' : 'shutdown_reboot_t',
'suspend' : 'shutdown_suspend_t' }
@@ -34,6 +51,10 @@ class DomainController(controller.Controller):
print 'DomainController>', self, self.channel, self.idx
def shutdown(self, reason):
"""Shutdown a domain.
reason shutdown reason
"""
msgtype = self.reasons.get(reason)
if not msgtype:
raise ValueError('invalid reason:' + reason)
+27
View File
@@ -148,6 +148,9 @@ netif_formats = {
msg_formats.update(netif_formats)
#============================================================================
# Domain shutdown message types.
#============================================================================
CMSG_SHUTDOWN = 6
CMSG_SHUTDOWN_POWEROFF = 0
@@ -177,6 +180,14 @@ class Msg:
pass
def packMsg(ty, params):
"""Pack a message.
Any 'mac' parameter is passed in as an int[6] array and converted.
ty message type name
params message parameter dict
returns xu message
"""
if DEBUG: print '>packMsg', ty, params
(major, minor) = msg_formats[ty]
args = {}
@@ -194,6 +205,15 @@ def packMsg(ty, params):
return msg
def unpackMsg(ty, msg):
"""Unpack a message.
Any mac addresses in the message are converted to int[6] array
in the return dict.
ty message type
msg xu message
returns parameter dict
"""
args = msg.get_payload()
mac = [0, 0, 0, 0, 0, 0]
macs = []
@@ -212,6 +232,13 @@ def unpackMsg(ty, msg):
return args
def msgTypeName(ty, subty):
"""Convert a message type, subtype pair (ints) to a message type name (string).
ty integer message type
subty integer message subtype
returns message type name (or None)
"""
for (name, info) in msg_formats.items():
if info[0] == ty and info[1] == subty:
return name
+70 -41
View File
@@ -1,3 +1,5 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import random
from twisted.internet import defer
@@ -30,8 +32,12 @@ class NetifControllerFactory(controller.ControllerFactory):
def createInstance(self, dom, recreate=0):
"""Create or find the network interface controller for a domain.
dom domain
recreate if true this is a recreate (xend restarted)
returns netif controller
"""
#print 'netif>createInstance> dom=', dom
netif = self.getInstanceByDom(dom)
if netif is None:
netif = NetifController(self, dom)
@@ -39,15 +45,31 @@ class NetifControllerFactory(controller.ControllerFactory):
return netif
def getDomainDevices(self, dom):
"""Get the network device controllers for a domain.
dom domain
returns netif controller
"""
netif = self.getInstanceByDom(dom)
return (netif and netif.getDevices()) or []
def getDomainDevice(self, dom, vif):
"""Get a virtual network interface device for a domain.
dom domain
vif virtual interface index
returns NetDev
"""
netif = self.getInstanceByDom(dom)
return (netif and netif.getDevice(vif)) or None
def setControlDomain(self, dom, recreate=0):
"""Set the 'back-end' device driver domain.
dom domain
recreate if true this is a recreate (xend restarted)
"""
if self.dom == dom: return
self.deregisterChannel()
@@ -55,13 +77,10 @@ class NetifControllerFactory(controller.ControllerFactory):
self.attached = 0
self.dom = dom
self.registerChannel()
#
#if xend.netif.be_port.remote_dom != 0:
# xend.netif.recovery = True
# xend.netif.be_port = xend.main.port_from_dom(dom)
#
def getControlDomain(self):
"""Get the domain id of the back-end control domain.
"""
return self.dom
def recv_be_create(self, msg, req):
@@ -88,23 +107,6 @@ class NetifControllerFactory(controller.ControllerFactory):
netif.reattach_devices()
self.attached = 1
## pl = msg.get_payload()
## status = pl['status']
## if status == NETIF_DRIVER_STATUS_UP:
## if xend.netif.recovery:
## print "New netif backend now UP, notifying guests:"
## for netif_key in interface.list.keys():
## netif = interface.list[netif_key]
## netif.create()
## print " Notifying %d" % netif.dom
## msg = xu.message(
## CMSG_NETIF_FE,
## CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, 0,
## { 'handle' : 0, 'status' : 1 })
## netif.ctrlif_tx_req(xend.main.port_from_dom(netif.dom),msg)
## print "Done notifying guests"
## recovery = False
class NetDev(controller.Dev):
"""Info record for a network device.
"""
@@ -130,9 +132,13 @@ class NetDev(controller.Dev):
return val
def get_vifname(self):
"""Get the virtual interface device name.
"""
return "vif%d.%d" % (self.controller.dom, self.vif)
def get_mac(self):
"""Get the MAC address as a string.
"""
return ':'.join(map(lambda x: "%x" % x, self.mac))
def vifctl_params(self):
@@ -141,23 +147,30 @@ class NetDev(controller.Dev):
'ipaddr': self.ipaddr }
def up(self, bridge=None, ipaddr=[]):
"""Bring the device up.
bridge ethernet bridge to connect to
ipaddr list of ipaddrs to filter using iptables
"""
self.bridge = bridge
self.ipaddr = ipaddr
Vifctl.up(self.get_vifname(), **self.vifctl_params())
def down(self):
"""Bring the device down.
"""
Vifctl.down(self.get_vifname(), **self.vifctl_params())
def destroy(self):
"""Destroy the device's resources and disconnect from the back-end
device controller.
"""
def cb_destroy(val):
self.controller.send_be_destroy(self.vif)
print 'NetDev>destroy>', 'vif=', self.vif
PrettyPrint.prettyprint(self.sxpr())
self.down()
d = self.controller.factory.addDeferred()
d.addCallback(cb_destroy)
self.controller.send_be_disconnect(self.vif)
#self.controller.send_be_destroy(self.vif)
class NetifController(controller.Controller):
@@ -165,7 +178,6 @@ class NetifController(controller.Controller):
"""
def __init__(self, factory, dom):
#print 'NetifController> dom=', dom
controller.Controller.__init__(self, factory, dom)
self.devices = {}
@@ -178,21 +190,22 @@ class NetifController(controller.Controller):
self.recv_fe_interface_connect,
}
self.registerChannel()
#print 'NetifController<', 'dom=', self.dom, 'idx=', self.idx
def sxpr(self):
val = ['netif', ['dom', self.dom]]
return val
def randomMAC(self):
# VIFs get a random MAC address with a "special" vendor id.
#
# NB. The vendor is currently an "obsolete" one that used to belong
# to DEC (AA-00-00). Using it is probably a bit rude :-)
#
# NB2. The first bit of the first random octet is set to zero for
# all dynamic MAC addresses. This may allow us to manually specify
# MAC addresses for some VIFs with no fear of clashes.
"""Generate a random MAC address.
The OUI (Organisation Unique Identifier) used is AA:00:00, which
is a currently unassigned one that used to belong to DEC.
The remaining 3 fields are random, with the first bit of the first
random field set 0.
returns array of 6 ints
"""
mac = [ 0xaa, 0x00, 0x00,
random.randint(0x00, 0x7f),
random.randint(0x00, 0xff),
@@ -200,29 +213,46 @@ class NetifController(controller.Controller):
return mac
def lostChannel(self):
print 'NetifController>lostChannel>', 'dom=', self.dom
#self.destroyDevices()
"""Method called when the channel has been lost.
"""
controller.Controller.lostChannel(self)
def getDevices(self):
"""Get a list of the devices.
"""
return self.devices.values()
def getDevice(self, vif):
"""Get a device.
vif device index
returns device (or None)
"""
return self.devices.get(vif)
def addDevice(self, vif, vmac):
"""Add a network interface. If vmac is None a random MAC is
assigned. If specified, vmac must be a string of the form
XX:XX:XX:XX:XX where X is hex digit.
vif device index
vmac device MAC
returns device
"""
if vmac is None:
mac = self.randomMAC()
else:
mac = [ int(x, 16) for x in vmac.split(':') ]
if len(mac) != 6: raise ValueError("invalid mac")
#print "attach_device>", "vif=", vif, "mac=", mac
dev = NetDev(self, vif, mac)
self.devices[vif] = dev
return dev
def destroy(self):
print 'NetifController>destroy>', 'dom=', self.dom
"""Destroy the controller and all devices.
"""
self.destroyDevices()
def destroyDevices(self):
@@ -306,7 +336,6 @@ class NetifController(controller.Controller):
self.factory.writeRequest(msg)
def send_be_destroy(self, vif):
print 'NetifController>send_be_destroy>', 'dom=', self.dom, 'vif=', vif
PrettyPrint.prettyprint(self.sxpr())
dev = self.devices[vif]
del self.devices[vif]
+42 -7
View File
@@ -1,4 +1,5 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Domain creation.
"""
import string
@@ -15,12 +16,22 @@ from xen.xm.opts import *
gopts = Opts(use="""[options]
Create a domain.
Domain creation parameters can be set by command-line switches, from
a python configuration script or an SXP config file. See documentation
for --defaults, --config. Configuration variables can be set using
VAR=VAL on the command line. For example vmid=3 sets vmid to 3.
""")
gopts.opt('help', short='h',
fn=set_true, default=0,
use="Print this help.")
gopts.opt('help_config',
fn=set_true, default=0,
use="Print help for configuration file.")
gopts.opt('quiet', short='q',
fn=set_true, default=0,
use="Quiet.")
@@ -31,24 +42,40 @@ gopts.opt('path', val='PATH',
gopts.opt('defaults', short='f', val='FILE',
fn=set_value, default='xmdefaults',
use="Use the given default script.")
use="""Use the given Python defaults script.
The defaults script is loaded after arguments have been processed.
Each command-line option sets a configuration variable named after
its long option name, and these variables are placed in the
environment of the script before it is loaded.
Variables for options that may be repeated have list values.
Other variables can be set using VAR=VAL on the command line.
After the script is loaded, option values that were not set on the
command line are replaced by the values set in the script.
""")
gopts.opt('config', short='F', val='FILE',
fn=set_value, default=None,
use='Domain configuration to use (SXP).')
use="""Domain configuration to use (SXP).
SXP is the underlying configuration format used by Xen.
SXP configs can be hand-written or generated from Python defaults
scripts, using the -n (dryrun) option to print the config.
""")
gopts.opt('load', short='L', val='FILE',
fn=set_value, default=None,
use='Domain saved state to load.')
gopts.opt('define', short='D', val='VAR=VAL',
fn=set_var, default=None,
use="""Set a variable before loading defaults, e.g. '-D vmid=3'
to set vmid. May be repeated to set more thanone variable.""")
#gopts.opt('define', short='D', val='VAR=VAL',
# fn=set_var, default=None,
# use="""Set a variable before loading defaults, e.g. '-D vmid=3'
# to set vmid. May be repeated to set more than one variable.""")
gopts.opt('dryrun', short='n',
fn=set_true, default=0,
use="Dry run - print the config but don't create the domain.")
use="""Dry run - print the config but don't create the domain.
The defaults file is loaded and the SXP configuration is created and printed.
""")
gopts.opt('name', short='N', val='NAME',
fn=set_value, default=None,
@@ -352,7 +379,15 @@ def main(argv):
args = opts.parse(argv)
if opts.vals.help:
opts.usage()
if opts.vals.help or opts.vals.help_config:
opts.load_defaults(help=1)
if opts.vals.help or opts.vals.help_config:
return
# Process remaining args as config variables.
for arg in args:
if '=' in arg:
(var, val) = arg.strip().split('=')
gopts.setvar(var.strip(), val.strip())
if opts.vals.config:
pass
else:
+82
View File
@@ -0,0 +1,82 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Variable definition and help support for Python defaults files.
"""
import sys
class Vars:
"""A set of configuration variables.
"""
def __init__(self, name, help, env):
"""Create a variable set.
name name of the defaults file
help help flag
env local environment
"""
self.name = name
self.help = help
self.env = env
self.vars = []
def var(self, name, use=None, check=None):
"""Define a configuration variable.
If provided, the check function will be called as check(var, val)
where var is the variable name and val is its value (string).
It should return a new value for the variable, or raise ValueError if
the value is not acceptable.
name variable name
use variable usage string
check variable check function
"""
self.vars.append(Var(name, use, check))
def check(self):
"""Execute the variable checks or print help, depending on the value
of the help flag passed to the constructor.
"""
if self.help:
self.doHelp()
else:
for v in self.vars:
v.doCheck(self.env)
def doHelp(self, out=sys.stderr):
"""Print help for the variables.
"""
if self.vars:
print >>out, "\nConfiguration variables for %s:\n" % self.name
for v in self.vars:
v.doHelp(out)
print >>out
class Var:
"""A single variable.
"""
def __init__(self, name, use, check):
"""Create a variable.
name variable name
use variable use string
check variable value check function
"""
self.name = name
self.use = use or ''
self.check = check
def doCheck(self, env):
"""Execute the check and set the variable to the new value.
"""
if not self.check: return
env[self.name] = self.check(self.name, env.get(self.name))
def doHelp(self, out):
"""Print help for the variable.
"""
print >>out, "%-12s" % self.name, self.use
+25
View File
@@ -5,10 +5,12 @@ import os
import os.path
import sys
from getopt import getopt
import socket
from xen.xend import PrettyPrint
from xen.xend import sxp
from xen.xend.XendClient import server
from xen.xend.XendClient import main as xend_client_main
from xen.xm import create, shutdown
class Prog:
@@ -65,6 +67,13 @@ class Xm:
sys.exit(1)
def main(self, args):
try:
self.main_call(args)
except socket.error, ex:
print >>sys.stderr, ex
self.err("Error connecting to xend, is xend running?")
def main_call(self, args):
"""Main entry point. Dispatches to the progs.
"""
self.name = args[0]
@@ -444,5 +453,21 @@ class ProgConsole(Prog):
xm.prog(ProgConsole)
class ProgCall(Prog):
name = "call"
info = "Call xend api functions."
def help (self, args):
print "call fn argss..."
print """
Call a xend HTTP API function. The leading 'xend_' on the function
can be omitted. See xen.xend.XendClient for the API functions.
"""
def main(self, args):
xend_client_main(args)
xm.prog(ProgCall)
def main(args):
xm.main(args)
+12 -6
View File
@@ -259,7 +259,7 @@ class Opts:
for opt in self.options:
opt.show()
def load_defaults(self):
def load_defaults(self, help=0):
"""Load a defaults script. Assumes these options set:
'path' search path
'default' script name
@@ -270,12 +270,12 @@ class Opts:
else:
p = self.vals.defaults
if os.path.exists(p):
self.load(p)
self.load(p, help)
break
else:
self.err("Cannot open defaults file %s" % self.vals.defaults)
def load(self, defaults, help=0):
def load(self, defaults, help):
"""Load a defaults file. Local variables in the file
are used to set options with the same names.
Variables are not used to set options that are already specified.
@@ -290,11 +290,17 @@ class Opts:
cmd = '\n'.join(["import sys",
"import os",
"import os.path",
"import xen.util.ip",
"from xen.xm.help import Vars",
"from xen.util import ip",
"xm_file = '%s'" % defaults,
"xm_help = %d" % help ])
"xm_help = %d" % help,
"xm_vars = Vars(xm_file, xm_help, locals())",
])
exec cmd in globals, locals
execfile(defaults, globals, locals)
try:
execfile(defaults, globals, locals)
except:
if not help: raise
if help: return
# Extract the values set by the script and set the corresponding
# options, if not set on the command line.
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.