xen-vtx-unstable

annotate tools/python/xen/xend/server/controller.py @ 1719:430a2d09d6ad

bitkeeper revision 1.1051 (40ed377bW0cMKaeeMSXfQOknw3iMaw)

Documentation.
author mjw@wray-m-3.hpl.hp.com
date Thu Jul 08 12:00:59 2004 +0000 (2004-07-08)
parents 0e23f01219c6
children 3b98f6df869f
rev   line source
mjw@1654 1 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
mjw@1719 2 """General support for controllers, which handle devices
mjw@1719 3 for a domain.
mjw@1719 4 """
mjw@1654 5
mjw@1623 6 from twisted.internet import defer
mjw@1677 7 defer.Deferred.debug = 1
mjw@1623 8
mjw@1623 9 import channel
mjw@1719 10 from messages import msgTypeName, printMsg
mjw@1623 11
mjw@1719 12 DEBUG = 0
mjw@1677 13
mjw@1677 14 class OutOfOrderError(RuntimeError):
mjw@1719 15 """Error reported when a response message arrives out of order.
mjw@1677 16 """
mjw@1677 17 pass
mjw@1677 18
mjw@1677 19 class Responder:
mjw@1719 20 """Handler for a response to a message with a specified id.
mjw@1677 21 """
mjw@1677 22
mjw@1677 23 def __init__(self, mid, deferred):
mjw@1677 24 """Create a responder.
mjw@1677 25
mjw@1719 26 @param mid: message id of response to handle
mjw@1719 27 @type mid: int
mjw@1719 28 @param deferred: deferred object holding the callbacks
mjw@1719 29 @type deferred: Deferred
mjw@1677 30 """
mjw@1677 31 self.mid = mid
mjw@1677 32 self.deferred = deferred
mjw@1677 33
mjw@1677 34 def responseReceived(self, msg):
mjw@1719 35 """Entry point called when a response message with the right id arrives.
mjw@1719 36 Calls callback on I{self.deferred} with the message.
mjw@1719 37
mjw@1719 38 @param msg: response message
mjw@1719 39 @type msg: xu message
mjw@1719 40 """
mjw@1677 41 if self.deferred.called: return
mjw@1677 42 self.deferred.callback(msg)
mjw@1677 43
mjw@1677 44 def error(self, err):
mjw@1719 45 """Entry point called when there has been an error.
mjw@1719 46 Calls errback on I{self.deferred} with the error.
mjw@1719 47
mjw@1719 48 @param err: error
mjw@1719 49 @type err: Exception
mjw@1719 50 """
mjw@1677 51 if self.deferred.called: return
mjw@1677 52 self.deferred.errback(err)
mjw@1677 53
mjw@1623 54 class CtrlMsgRcvr:
mjw@1623 55 """Abstract class for things that deal with a control interface to a domain.
mjw@1719 56 Once I{registerChannel} has been called, our message types are registered
mjw@1719 57 with the channel to the domain. The channel will call I{requestReceived}
mjw@1719 58 when a request arrives, or I{responseReceived} when a response arrives,
mjw@1719 59 if they have one of our message types.
mjw@1654 60
mjw@1719 61 @ivar dom: the domain we are a control interface for
mjw@1719 62 @type dom: int
mjw@1719 63 @ivar majorTypes: major message types we are interested in
mjw@1719 64 @type majorTypes: [int]
mjw@1719 65 @ivar subTypes: mapping of message subtypes to methods
mjw@1719 66 @ivar subTypes: {int:method}
mjw@1719 67 @ivar timeout: timeout (in seconds) for message handlers
mjw@1719 68 @type timeout: int
mjw@1654 69
mjw@1719 70 @ivar channel: channel to the domain
mjw@1719 71 @type channel: Channel
mjw@1719 72 @ivar idx: channel index
mjw@1719 73 @ivar idx: string
mjw@1719 74 @ivar responders: table of message response handlers
mjw@1719 75 @type responders: {int:Responder}
mjw@1623 76 """
mjw@1623 77
mjw@1623 78 def __init__(self):
mjw@1623 79 self.channelFactory = channel.channelFactory()
mjw@1623 80 self.majorTypes = [ ]
mjw@1623 81 self.subTypes = {}
mjw@1623 82 self.dom = None
mjw@1623 83 self.channel = None
mjw@1623 84 self.idx = None
mjw@1677 85 self.responders = []
mjw@1677 86 self.timeout = 10
mjw@1677 87
mjw@1677 88 def setTimeout(self, timeout):
mjw@1677 89 self.timeout = timeout
mjw@1623 90
mjw@1623 91 def requestReceived(self, msg, type, subtype):
mjw@1719 92 """Dispatch a request message to handlers.
mjw@1719 93 Called by the channel for requests with one of our types.
mjw@1654 94
mjw@1719 95 @param msg: message
mjw@1719 96 @type msg: xu message
mjw@1719 97 @param type: major message type
mjw@1719 98 @type type: int
mjw@1719 99 @param subtype: minor message type
mjw@1719 100 @type subtype: int
mjw@1654 101 """
mjw@1677 102 if DEBUG:
mjw@1719 103 print 'requestReceived>',
mjw@1719 104 printMsg(msg, all=1)
mjw@1623 105 method = self.subTypes.get(subtype)
mjw@1623 106 if method:
mjw@1623 107 method(msg, 1)
mjw@1677 108 elif DEBUG:
mjw@1623 109 print ('requestReceived> No handler: Message type %s %d:%d'
mjw@1623 110 % (msgTypeName(type, subtype), type, subtype)), self
mjw@1623 111
mjw@1623 112 def responseReceived(self, msg, type, subtype):
mjw@1654 113 """Dispatch a response to handlers.
mjw@1719 114 Called by the channel for responses with one of our types.
mjw@1719 115
mjw@1719 116 First looks for a message responder for the message's id.
mjw@1719 117 See L{callResponders}, L{addResponder}.
mjw@1719 118 If there is no responder, looks for a message handler for
mjw@1719 119 the message type/subtype.
mjw@1654 120
mjw@1719 121 @param msg: message
mjw@1719 122 @type msg: xu message
mjw@1719 123 @param type: major message type
mjw@1719 124 @type type: int
mjw@1719 125 @param subtype: minor message type
mjw@1719 126 @type subtype: int
mjw@1654 127 """
mjw@1677 128 if DEBUG:
mjw@1719 129 print 'responseReceived>',
mjw@1719 130 printMsg(msg, all=1)
mjw@1677 131 if self.callResponders(msg):
mjw@1677 132 return
mjw@1623 133 method = self.subTypes.get(subtype)
mjw@1623 134 if method:
mjw@1623 135 method(msg, 0)
mjw@1677 136 elif DEBUG:
mjw@1623 137 print ('responseReceived> No handler: Message type %s %d:%d'
mjw@1623 138 % (msgTypeName(type, subtype), type, subtype)), self
mjw@1623 139
mjw@1677 140 def addResponder(self, mid, deferred):
mjw@1677 141 """Add a responder for a message id.
mjw@1719 142 The I{deferred} is called with callback(msg) when a response
mjw@1719 143 with message id I{mid} arrives. Responses are expected
mjw@1677 144 to arrive in order of message id. When a response arrives,
mjw@1677 145 waiting responders for messages with lower id have errback
mjw@1677 146 called with an OutOfOrder error.
mjw@1677 147
mjw@1719 148 Responders have a timeout set and I{deferred} will error
mjw@1719 149 on expiry.
mjw@1677 150
mjw@1719 151 @param mid: message id of response expected
mjw@1719 152 @type mid: int
mjw@1719 153 @param deferred: handler for the response
mjw@1719 154 @type deferred: Deferred
mjw@1719 155 @return: responder
mjw@1719 156 @rtype: Responder
mjw@1677 157 """
mjw@1677 158 if self.timeout > 0:
mjw@1677 159 deferred.setTimeout(self.timeout)
mjw@1677 160 resp = Responder(mid, deferred)
mjw@1677 161 self.responders.append(resp)
mjw@1677 162 return resp
mjw@1677 163
mjw@1677 164 def callResponders(self, msg):
mjw@1677 165 """Call any waiting responders for a response message.
mjw@1719 166 Looks for a responder registered for the message's id.
mjw@1719 167 See L{addResponder}.
mjw@1677 168
mjw@1719 169 @param msg: response message
mjw@1719 170 @type msg: xu message
mjw@1719 171 @return: 1 if there was a responder for the message, 0 otherwise
mjw@1719 172 @rtype : bool
mjw@1677 173 """
mjw@1677 174 hdr = msg.get_header()
mjw@1677 175 mid = hdr['id']
mjw@1677 176 handled = 0
mjw@1677 177 while self.responders:
mjw@1677 178 resp = self.responders[0]
mjw@1677 179 if resp.mid > mid:
mjw@1677 180 break
mjw@1677 181 self.responders.pop()
mjw@1677 182 if resp.mid < mid:
mjw@1719 183 print 'callResponders> Out of order:', resp.mid, mid
mjw@1677 184 resp.error(OutOfOrderError())
mjw@1677 185 else:
mjw@1677 186 handled = 1
mjw@1677 187 resp.responseReceived(msg)
mjw@1677 188 break
mjw@1677 189 return handled
mjw@1677 190
mjw@1623 191 def lostChannel(self):
mjw@1654 192 """Called when the channel to the domain is lost.
mjw@1654 193 """
mjw@1623 194 pass
mjw@1623 195
mjw@1623 196 def registerChannel(self):
mjw@1654 197 """Register interest in our major message types with the
mjw@1719 198 channel to our domain. Once we have registered, the channel
mjw@1719 199 will call requestReceived or responseReceived for our messages.
mjw@1654 200 """
mjw@1623 201 self.channel = self.channelFactory.domChannel(self.dom)
mjw@1623 202 self.idx = self.channel.getIndex()
mjw@1623 203 if self.majorTypes:
mjw@1623 204 self.channel.registerDevice(self.majorTypes, self)
mjw@1623 205
mjw@1623 206 def deregisterChannel(self):
mjw@1654 207 """Deregister interest in our major message types with the
mjw@1719 208 channel to our domain. After this the channel won't call
mjw@1719 209 us any more.
mjw@1654 210 """
mjw@1623 211 if self.channel:
mjw@1623 212 self.channel.deregisterDevice(self)
mjw@1623 213 del self.channel
mjw@1623 214
mjw@1623 215 def produceRequests(self):
mjw@1654 216 """Produce any queued requests.
mjw@1654 217
mjw@1719 218 @return: number produced
mjw@1719 219 @rtype: int
mjw@1654 220 """
mjw@1623 221 return 0
mjw@1623 222
mjw@1677 223 def writeRequest(self, msg, response=None):
mjw@1654 224 """Write a request to the channel.
mjw@1677 225
mjw@1719 226 @param msg: request message
mjw@1719 227 @type msg: xu message
mjw@1719 228 @param response: response handler
mjw@1719 229 @type response: Deferred
mjw@1654 230 """
mjw@1623 231 if self.channel:
mjw@1719 232 if DEBUG:
mjw@1719 233 print 'CtrlMsgRcvr>writeRequest>',
mjw@1719 234 printMsg(msg, all=1)
mjw@1677 235 if response:
mjw@1677 236 self.addResponder(msg.get_header()['id'], response)
mjw@1623 237 self.channel.writeRequest(msg)
mjw@1623 238 else:
mjw@1623 239 print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self
mjw@1623 240
mjw@1623 241 def writeResponse(self, msg):
mjw@1719 242 """Write a response to the channel. This acknowledges
mjw@1719 243 a request message.
mjw@1719 244
mjw@1719 245 @param msg: message
mjw@1719 246 @type msg: xu message
mjw@1654 247 """
mjw@1623 248 if self.channel:
mjw@1719 249 if DEBUG:
mjw@1719 250 print 'CtrlMsgRcvr>writeResponse>',
mjw@1719 251 printMsg(msg, all=0)
mjw@1623 252 self.channel.writeResponse(msg)
mjw@1623 253 else:
mjw@1623 254 print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self
mjw@1623 255
mjw@1623 256 class ControllerFactory(CtrlMsgRcvr):
mjw@1719 257 """Abstract class for factories creating controllers for a domain.
mjw@1623 258 Maintains a table of instances.
mjw@1654 259
mjw@1719 260 @ivar instances: mapping of index to controller instance
mjw@1719 261 @type instances: {int: Controller}
mjw@1719 262 @ivar dom: domain
mjw@1719 263 @type dom: int
mjw@1623 264 """
mjw@1623 265
mjw@1623 266 def __init__(self):
mjw@1623 267 CtrlMsgRcvr.__init__(self)
mjw@1623 268 self.instances = {}
mjw@1623 269 self.dom = 0
mjw@1623 270
mjw@1623 271 def addInstance(self, instance):
mjw@1654 272 """Add a controller instance (under its index).
mjw@1654 273 """
mjw@1623 274 self.instances[instance.idx] = instance
mjw@1623 275
mjw@1623 276 def getInstance(self, idx):
mjw@1654 277 """Get a controller instance from its index.
mjw@1654 278 """
mjw@1623 279 return self.instances.get(idx)
mjw@1623 280
mjw@1623 281 def getInstances(self):
mjw@1654 282 """Get a list of all controller instances.
mjw@1654 283 """
mjw@1623 284 return self.instances.values()
mjw@1623 285
mjw@1623 286 def getInstanceByDom(self, dom):
mjw@1654 287 """Get the controller instance for the given domain.
mjw@1654 288 """
mjw@1623 289 for inst in self.instances.values():
mjw@1623 290 if inst.dom == dom:
mjw@1623 291 return inst
mjw@1623 292 return None
mjw@1623 293
mjw@1623 294 def delInstance(self, instance):
mjw@1654 295 """Delete an instance from the table.
mjw@1654 296 """
mjw@1623 297 if instance.idx in self.instances:
mjw@1623 298 del self.instances[instance.idx]
mjw@1623 299
mjw@1623 300 def createInstance(self, dom, recreate=0):
mjw@1654 301 """Create an instance. Define in a subclass.
mjw@1719 302
mjw@1719 303 @param dom: domain
mjw@1719 304 @type dom: int
mjw@1719 305 @param recreate: true if the instance is being recreated (after xend restart)
mjw@1719 306 @type recreate: int
mjw@1654 307 """
mjw@1623 308 raise NotImplementedError()
mjw@1623 309
mjw@1623 310 def instanceClosed(self, instance):
mjw@1654 311 """Callback called when an instance is closed (usually by the instance).
mjw@1654 312 """
mjw@1623 313 self.delInstance(instance)
mjw@1623 314
mjw@1623 315 class Controller(CtrlMsgRcvr):
mjw@1623 316 """Abstract class for a device controller attached to a domain.
mjw@1623 317 """
mjw@1623 318
mjw@1623 319 def __init__(self, factory, dom):
mjw@1623 320 CtrlMsgRcvr.__init__(self)
mjw@1623 321 self.factory = factory
mjw@1623 322 self.dom = int(dom)
mjw@1623 323 self.channel = None
mjw@1623 324 self.idx = None
mjw@1623 325
mjw@1623 326 def close(self):
mjw@1654 327 """Close the controller.
mjw@1654 328 """
mjw@1623 329 self.lostChannel()
mjw@1623 330
mjw@1623 331 def lostChannel(self):
mjw@1654 332 """The controller channel has been lost.
mjw@1654 333 """
mjw@1664 334 self.deregisterChannel()
mjw@1623 335 self.factory.instanceClosed(self)
mjw@1623 336
mjw@1623 337 class Dev:
mjw@1654 338 """Abstract class for a device attached to a device controller.
mjw@1654 339 """
mjw@1654 340
mjw@1623 341 def __init__(self, controller):
mjw@1623 342 self.controller = controller
mjw@1623 343 self.props = {}
mjw@1623 344
mjw@1623 345 def setprop(self, k, v):
mjw@1623 346 self.props[k] = v
mjw@1623 347
mjw@1623 348 def getprop(self, k, v=None):
mjw@1623 349 return self.props.get(k, v)
mjw@1623 350
mjw@1623 351 def hasprop(self, k):
mjw@1623 352 return k in self.props
mjw@1623 353
mjw@1623 354 def delprop(self, k):
mjw@1623 355 if k in self.props:
mjw@1623 356 del self.props[k]
mjw@1623 357
mjw@1623 358 def sxpr(self):
mjw@1623 359 raise NotImplementedError()
mjw@1623 360
mjw@1623 361