xen-vtx-unstable

annotate tools/python/xen/xend/server/controller.py @ 2267:45db83f2cdd0

bitkeeper revision 1.1159.38.3 (4123550cLBAC07otAj8ftsT6MzujHQ)

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