mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
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:
commit
ea9abef278
16 files changed
+471
-386
No files matched your search
@@ -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 += '/'
|
||||
|
||||
@@ -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>')
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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.
|
||||
|
||||