xen-vtx-unstable

annotate tools/python/xen/xend/server/controller.py @ 2185:6c272033a2ed

bitkeeper revision 1.1159.1.36 (4119f27eonzahatd09ja80xf3ifOFw)

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