xen-vtx-unstable

annotate tools/python/xen/xend/server/controller.py @ 2225:f8bc691dd640

bitkeeper revision 1.1159.1.53 (411ccd729CC_RzyLGa4nViY2XcSdig)

Separate controller backend from the controller factory, allowing
each controller to have its own backend domain.
author mjw@wray-m-3.hpl.hp.com
date Fri Aug 13 14:17:22 2004 +0000 (2004-08-13)
parents 6c85a89e99e3
children af0729973950 703b333dc90c a6d73a771367
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@2224 12 DEBUG = 1
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@2224 59 @type majorTypes: {int:{int:method}}
mjw@1719 60 @ivar timeout: timeout (in seconds) for message handlers
mjw@1719 61 @type timeout: int
mjw@1654 62
mjw@1719 63 @ivar channel: channel to the domain
mjw@1719 64 @type channel: Channel
mjw@1719 65 @ivar idx: channel index
mjw@1719 66 @ivar idx: string
mjw@1719 67 @ivar responders: table of message response handlers
mjw@1719 68 @type responders: {int:Responder}
mjw@1623 69 """
mjw@1623 70
mjw@1623 71 def __init__(self):
mjw@1623 72 self.channelFactory = channel.channelFactory()
mjw@2224 73 self.majorTypes = {}
mjw@1623 74 self.dom = None
mjw@1623 75 self.channel = None
mjw@1623 76 self.idx = None
mjw@1728 77 self.responders = {}
mjw@1677 78 self.timeout = 10
mjw@1677 79
mjw@1677 80 def setTimeout(self, timeout):
mjw@1677 81 self.timeout = timeout
mjw@1623 82
mjw@2224 83 def getMethod(self, type, subtype):
mjw@2224 84 """Get the method for a type and subtype.
mjw@2224 85
mjw@2224 86 @param type: major message type
mjw@2224 87 @param subtype: minor message type
mjw@2224 88 @return: method or None
mjw@2224 89 """
mjw@2224 90 method = None
mjw@2224 91 subtypes = self.majorTypes.get(type)
mjw@2224 92 if subtypes:
mjw@2224 93 method = subtypes.get(subtype)
mjw@2224 94 return method
mjw@2224 95
mjw@2224 96 def addMethod(self, type, subtype, method):
mjw@2224 97 """Add a method to handle a message type and subtype.
mjw@2224 98
mjw@2224 99 @param type: major message type
mjw@2224 100 @param subtype: minor message type
mjw@2224 101 @param method: method
mjw@2224 102 """
mjw@2224 103 subtypes = self.majorTypes.get(type)
mjw@2224 104 if not subtypes:
mjw@2224 105 subtypes = {}
mjw@2224 106 self.majorTypes[type] = subtypes
mjw@2224 107 subtypes[subtype] = method
mjw@2224 108
mjw@2224 109 def getMajorTypes(self):
mjw@2224 110 """Get the list of major message types handled.
mjw@2224 111 """
mjw@2224 112 return self.majorTypes.keys()
mjw@2224 113
mjw@1623 114 def requestReceived(self, msg, type, subtype):
mjw@1719 115 """Dispatch a request message to handlers.
mjw@1719 116 Called by the channel for requests with one of our types.
mjw@1654 117
mjw@1719 118 @param msg: message
mjw@1719 119 @type msg: xu message
mjw@1719 120 @param type: major message type
mjw@1719 121 @type type: int
mjw@1719 122 @param subtype: minor message type
mjw@1719 123 @type subtype: int
mjw@1654 124 """
mjw@1677 125 if DEBUG:
mjw@1719 126 print 'requestReceived>',
mjw@1719 127 printMsg(msg, all=1)
mjw@2224 128 method = self.getMethod(type, subtype)
mjw@1623 129 if method:
mjw@1623 130 method(msg, 1)
mjw@1677 131 elif DEBUG:
mjw@1623 132 print ('requestReceived> No handler: Message type %s %d:%d'
mjw@1623 133 % (msgTypeName(type, subtype), type, subtype)), self
mjw@1623 134
mjw@1623 135 def responseReceived(self, msg, type, subtype):
mjw@1654 136 """Dispatch a response to handlers.
mjw@1719 137 Called by the channel for responses with one of our types.
mjw@1719 138
mjw@1719 139 First looks for a message responder for the message's id.
mjw@1719 140 See L{callResponders}, L{addResponder}.
mjw@1719 141 If there is no responder, looks for a message handler for
mjw@1719 142 the message type/subtype.
mjw@1654 143
mjw@1719 144 @param msg: message
mjw@1719 145 @type msg: xu message
mjw@1719 146 @param type: major message type
mjw@1719 147 @type type: int
mjw@1719 148 @param subtype: minor message type
mjw@1719 149 @type subtype: int
mjw@1654 150 """
mjw@1677 151 if DEBUG:
mjw@1719 152 print 'responseReceived>',
mjw@1719 153 printMsg(msg, all=1)
mjw@1677 154 if self.callResponders(msg):
mjw@1677 155 return
mjw@2224 156 method = self.getMethod(type, subtype)
mjw@1623 157 if method:
mjw@1623 158 method(msg, 0)
mjw@1677 159 elif DEBUG:
mjw@1623 160 print ('responseReceived> No handler: Message type %s %d:%d'
mjw@1623 161 % (msgTypeName(type, subtype), type, subtype)), self
mjw@1623 162
mjw@1677 163 def addResponder(self, mid, deferred):
mjw@1677 164 """Add a responder for a message id.
mjw@1719 165 The I{deferred} is called with callback(msg) when a response
mjw@1728 166 with message id I{mid} arrives.
mjw@1677 167
mjw@1719 168 Responders have a timeout set and I{deferred} will error
mjw@1719 169 on expiry.
mjw@1677 170
mjw@1719 171 @param mid: message id of response expected
mjw@1719 172 @type mid: int
mjw@1719 173 @param deferred: handler for the response
mjw@1719 174 @type deferred: Deferred
mjw@1719 175 @return: responder
mjw@1719 176 @rtype: Responder
mjw@1677 177 """
mjw@1728 178 resp = Responder(mid, deferred)
mjw@1728 179 self.responders[resp.mid] = resp
mjw@1677 180 if self.timeout > 0:
mjw@1677 181 deferred.setTimeout(self.timeout)
mjw@1677 182 return resp
mjw@1677 183
mjw@1677 184 def callResponders(self, msg):
mjw@1677 185 """Call any waiting responders for a response message.
mjw@1719 186 Looks for a responder registered for the message's id.
mjw@1719 187 See L{addResponder}.
mjw@1677 188
mjw@1719 189 @param msg: response message
mjw@1719 190 @type msg: xu message
mjw@1719 191 @return: 1 if there was a responder for the message, 0 otherwise
mjw@1719 192 @rtype : bool
mjw@1677 193 """
mjw@1677 194 hdr = msg.get_header()
mjw@1677 195 mid = hdr['id']
mjw@1677 196 handled = 0
mjw@1728 197 resp = self.responders.get(mid)
mjw@1728 198 if resp:
mjw@1728 199 handled = 1
mjw@1728 200 resp.responseReceived(msg)
mjw@1728 201 del self.responders[mid]
mjw@1728 202 # Clean up called responders.
mjw@1728 203 for resp in self.responders.values():
mjw@1728 204 if resp.deferred.called:
mjw@1728 205 del self.responders[resp.mid]
mjw@1677 206 return handled
mjw@1677 207
mjw@1623 208 def lostChannel(self):
mjw@1654 209 """Called when the channel to the domain is lost.
mjw@1654 210 """
mjw@1623 211 pass
mjw@1623 212
mjw@1623 213 def registerChannel(self):
mjw@1654 214 """Register interest in our major message types with the
mjw@1719 215 channel to our domain. Once we have registered, the channel
mjw@1719 216 will call requestReceived or responseReceived for our messages.
mjw@1654 217 """
mjw@1623 218 self.channel = self.channelFactory.domChannel(self.dom)
mjw@1623 219 self.idx = self.channel.getIndex()
mjw@1623 220 if self.majorTypes:
mjw@2224 221 self.channel.registerDevice(self.getMajorTypes(), self)
mjw@1623 222
mjw@1623 223 def deregisterChannel(self):
mjw@1654 224 """Deregister interest in our major message types with the
mjw@1719 225 channel to our domain. After this the channel won't call
mjw@1719 226 us any more.
mjw@1654 227 """
mjw@1623 228 if self.channel:
mjw@1623 229 self.channel.deregisterDevice(self)
mjw@1893 230 self.channel = None
mjw@1623 231
mjw@1623 232 def produceRequests(self):
mjw@1654 233 """Produce any queued requests.
mjw@1654 234
mjw@1719 235 @return: number produced
mjw@1719 236 @rtype: int
mjw@1654 237 """
mjw@1623 238 return 0
mjw@1623 239
mjw@1677 240 def writeRequest(self, msg, response=None):
mjw@1654 241 """Write a request to the channel.
mjw@1677 242
mjw@1719 243 @param msg: request message
mjw@1719 244 @type msg: xu message
mjw@1719 245 @param response: response handler
mjw@1719 246 @type response: Deferred
mjw@1654 247 """
mjw@1623 248 if self.channel:
mjw@1719 249 if DEBUG:
mjw@1719 250 print 'CtrlMsgRcvr>writeRequest>',
mjw@1719 251 printMsg(msg, all=1)
mjw@1677 252 if response:
mjw@1677 253 self.addResponder(msg.get_header()['id'], response)
mjw@1623 254 self.channel.writeRequest(msg)
mjw@1623 255 else:
mjw@1623 256 print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self
mjw@1623 257
mjw@1623 258 def writeResponse(self, msg):
mjw@1719 259 """Write a response to the channel. This acknowledges
mjw@1719 260 a request message.
mjw@1719 261
mjw@1719 262 @param msg: message
mjw@1719 263 @type msg: xu message
mjw@1654 264 """
mjw@1623 265 if self.channel:
mjw@1719 266 if DEBUG:
mjw@1719 267 print 'CtrlMsgRcvr>writeResponse>',
mjw@1719 268 printMsg(msg, all=0)
mjw@1623 269 self.channel.writeResponse(msg)
mjw@1623 270 else:
mjw@1623 271 print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self
mjw@1623 272
mjw@2225 273 class ControllerFactory:
mjw@1719 274 """Abstract class for factories creating controllers for a domain.
mjw@1623 275 Maintains a table of instances.
mjw@1654 276
mjw@1719 277 @ivar instances: mapping of index to controller instance
mjw@2185 278 @type instances: {String: Controller}
mjw@1719 279 @ivar dom: domain
mjw@1719 280 @type dom: int
mjw@1623 281 """
mjw@1623 282
mjw@1623 283 def __init__(self):
mjw@1623 284 self.instances = {}
mjw@2225 285 self.backends = {}
mjw@1623 286 self.dom = 0
mjw@1623 287
mjw@1623 288 def addInstance(self, instance):
mjw@1654 289 """Add a controller instance (under its index).
mjw@1654 290 """
mjw@1623 291 self.instances[instance.idx] = instance
mjw@1623 292
mjw@1623 293 def getInstance(self, idx):
mjw@1654 294 """Get a controller instance from its index.
mjw@1654 295 """
mjw@1623 296 return self.instances.get(idx)
mjw@1623 297
mjw@1623 298 def getInstances(self):
mjw@1654 299 """Get a list of all controller instances.
mjw@1654 300 """
mjw@1623 301 return self.instances.values()
mjw@1623 302
mjw@1623 303 def getInstanceByDom(self, dom):
mjw@1654 304 """Get the controller instance for the given domain.
mjw@2185 305
mjw@2185 306 @param dom: domain id
mjw@2185 307 @type dom: int
mjw@2185 308 @return: controller or None
mjw@1654 309 """
mjw@1623 310 for inst in self.instances.values():
mjw@1623 311 if inst.dom == dom:
mjw@1623 312 return inst
mjw@1623 313 return None
mjw@1623 314
mjw@1623 315 def delInstance(self, instance):
mjw@2185 316 """Delete a controller instance from the table.
mjw@2185 317
mjw@2185 318 @param instance: controller instance
mjw@1654 319 """
mjw@1623 320 if instance.idx in self.instances:
mjw@1623 321 del self.instances[instance.idx]
mjw@1623 322
mjw@1623 323 def createInstance(self, dom, recreate=0):
mjw@1654 324 """Create an instance. Define in a subclass.
mjw@1719 325
mjw@1719 326 @param dom: domain
mjw@1719 327 @type dom: int
mjw@1719 328 @param recreate: true if the instance is being recreated (after xend restart)
mjw@1719 329 @type recreate: int
mjw@2185 330 @return: controller instance
mjw@2185 331 @rtype: Controller (or subclass)
mjw@1654 332 """
mjw@1623 333 raise NotImplementedError()
mjw@1623 334
mjw@1623 335 def instanceClosed(self, instance):
mjw@1654 336 """Callback called when an instance is closed (usually by the instance).
mjw@2185 337
mjw@2185 338 @param instance: controller instance
mjw@1654 339 """
mjw@1623 340 self.delInstance(instance)
mjw@1623 341
mjw@1623 342 class Controller(CtrlMsgRcvr):
mjw@1623 343 """Abstract class for a device controller attached to a domain.
mjw@2185 344
mjw@2185 345 @ivar factory: controller factory
mjw@2185 346 @type factory: ControllerFactory
mjw@2185 347 @ivar dom: domain
mjw@2185 348 @type dom: int
mjw@2185 349 @ivar channel: channel to the domain
mjw@2185 350 @type channel: Channel
mjw@2185 351 @ivar idx: channel index
mjw@2185 352 @type idx: String
mjw@1623 353 """
mjw@1623 354
mjw@1623 355 def __init__(self, factory, dom):
mjw@1623 356 CtrlMsgRcvr.__init__(self)
mjw@1623 357 self.factory = factory
mjw@1623 358 self.dom = int(dom)
mjw@1623 359 self.channel = None
mjw@1623 360 self.idx = None
mjw@1623 361
mjw@1623 362 def close(self):
mjw@1654 363 """Close the controller.
mjw@1654 364 """
mjw@1623 365 self.lostChannel()
mjw@1623 366
mjw@1623 367 def lostChannel(self):
mjw@1654 368 """The controller channel has been lost.
mjw@1654 369 """
mjw@1664 370 self.deregisterChannel()
mjw@1623 371 self.factory.instanceClosed(self)
mjw@1623 372
mjw@2225 373 class SplitControllerFactory(ControllerFactory):
mjw@2225 374 """Factory for SplitControllers.
mjw@2225 375
mjw@2225 376 @ivar backends: mapping of domain id to backend
mjw@2225 377 @type backends: {int: BackendController}
mjw@2225 378 """
mjw@2225 379
mjw@2225 380 def __init__(self):
mjw@2225 381 ControllerFactory.__init__(self)
mjw@2225 382 self.backends = {}
mjw@2225 383
mjw@2225 384 def createInstance(self, dom, recreate=0, backend=0):
mjw@2225 385 """Create an instance. Define in a subclass.
mjw@2225 386
mjw@2225 387 @param dom: domain
mjw@2225 388 @type dom: int
mjw@2225 389 @param recreate: true if the instance is being recreated (after xend restart)
mjw@2225 390 @type recreate: int
mjw@2225 391 @param backend: backend domain
mjw@2225 392 @type backend: int
mjw@2225 393 @return: controller instance
mjw@2225 394 @rtype: SplitController (or subclass)
mjw@2225 395 """
mjw@2225 396 raise NotImplementedError()
mjw@2225 397
mjw@2225 398 def getBackendController(self, dom):
mjw@2225 399 """Get the backend controller for a domain.
mjw@2225 400
mjw@2225 401 @param dom: domain
mjw@2225 402 @return: backend controller
mjw@2225 403 """
mjw@2225 404 ctrlr = self.backends.get(dom)
mjw@2225 405 if ctrlr is None:
mjw@2225 406 ctrlr = self.createBackendController(dom)
mjw@2225 407 self.backends[dom] = ctrlr
mjw@2225 408 return ctrlr
mjw@2225 409
mjw@2225 410 def createBackendController(self, dom):
mjw@2225 411 """Create a backend controller. Define in a subclass.
mjw@2225 412
mjw@2225 413 @param dom: domain
mjw@2225 414 """
mjw@2225 415 raise NotImplementedError()
mjw@2225 416
mjw@2225 417 def delBackendController(self, ctrlr):
mjw@2225 418 """Remove a backend controller.
mjw@2225 419
mjw@2225 420 @param ctrlr: backend controller
mjw@2225 421 """
mjw@2225 422 if ctrlr.dom in self.backends:
mjw@2225 423 del self.backends[ctrlr.dom]
mjw@2225 424
mjw@2225 425 def backendControllerClosed(self, ctrlr):
mjw@2225 426 """Callback called when a backend is closed.
mjw@2225 427 """
mjw@2225 428 self.delBackendController(ctrlr)
mjw@2225 429
mjw@2225 430 class BackendController(CtrlMsgRcvr):
mjw@2225 431 """Abstract class for a backend device controller attached to a domain.
mjw@2225 432
mjw@2225 433 @ivar factory: controller factory
mjw@2225 434 @type factory: ControllerFactory
mjw@2225 435 @ivar dom: domain
mjw@2225 436 @type dom: int
mjw@2225 437 @ivar channel: channel to the domain
mjw@2225 438 @type channel: Channel
mjw@2225 439 """
mjw@2225 440
mjw@2225 441
mjw@2225 442 def __init__(self, factory, dom):
mjw@2225 443 CtrlMsgRcvr.__init__(self)
mjw@2225 444 self.factory = factory
mjw@2225 445 self.dom = int(dom)
mjw@2225 446 self.channel = None
mjw@2225 447
mjw@2225 448 def close(self):
mjw@2225 449 self.lostChannel()
mjw@2225 450
mjw@2225 451 def lostChannel(self):
mjw@2225 452 self.deregisterChannel()
mjw@2225 453 self.factory.instanceClosed(self)
mjw@2225 454
mjw@2225 455
mjw@2225 456 class SplitController(Controller):
mjw@2225 457 """Abstract class for a device controller attached to a domain.
mjw@2225 458 A SplitController has a BackendContoller.
mjw@2225 459 """
mjw@2225 460
mjw@2225 461 def __init__(self, factory, dom, backend):
mjw@2225 462 Controller.__init__(self, factory, dom)
mjw@2225 463 self.backendDomain = None
mjw@2225 464 self.backendController = None
mjw@2225 465 self.setBackendDomain(backend)
mjw@2225 466
mjw@2225 467 def setBackendDomain(self, dom):
mjw@2225 468 ctrlr = self.factory.getBackendController(dom)
mjw@2225 469 self.backendDomain = ctrlr.dom
mjw@2225 470 self.backendController = ctrlr
mjw@2225 471
mjw@2225 472 def getBackendDomain(self):
mjw@2225 473 return self.backendDomain
mjw@2225 474
mjw@2225 475 def getBackendController(self):
mjw@2225 476 return self.backendController
mjw@2225 477
mjw@1623 478 class Dev:
mjw@1654 479 """Abstract class for a device attached to a device controller.
mjw@2185 480
mjw@2185 481 @ivar idx: identifier
mjw@2185 482 @type idx: String
mjw@2185 483 @ivar controller: device controller
mjw@2185 484 @type controller: DeviceController
mjw@2185 485 @ivar props: property table
mjw@2185 486 @type props: { String: value }
mjw@1654 487 """
mjw@1654 488
mjw@1975 489 def __init__(self, idx, controller):
mjw@1975 490 self.idx = str(idx)
mjw@1623 491 self.controller = controller
mjw@1623 492 self.props = {}
mjw@1623 493
mjw@1975 494 def getidx(self):
mjw@1975 495 return self.idx
mjw@1975 496
mjw@1623 497 def setprop(self, k, v):
mjw@1623 498 self.props[k] = v
mjw@1623 499
mjw@1623 500 def getprop(self, k, v=None):
mjw@1623 501 return self.props.get(k, v)
mjw@1623 502
mjw@1623 503 def hasprop(self, k):
mjw@1623 504 return k in self.props
mjw@1623 505
mjw@1623 506 def delprop(self, k):
mjw@1623 507 if k in self.props:
mjw@1623 508 del self.props[k]
mjw@1623 509
mjw@1623 510 def sxpr(self):
mjw@2185 511 """Get the s-expression for the deivice.
mjw@2185 512 Implement in a subclass.
mjw@2185 513
mjw@2185 514 @return: sxpr
mjw@2185 515 """
mjw@1623 516 raise NotImplementedError()
mjw@1623 517
mjw@1623 518