xen-vtx-unstable

annotate tools/python/xen/xend/server/controller.py @ 6064:f40c6650152e

Add missing LGPL license notice to python sources
that didn't have them.

Signed-off-by: Mike Wray <mike.wray@hp.com>
author kaf24@firebug.cl.cam.ac.uk
date Tue Aug 09 13:17:37 2005 +0000 (2005-08-09)
parents 6d3e8f90c2df
children f056b0cc171e 8864f0be80c6 1de047fc56f5 323a46d272ff 48da5e506589 dc27fd3392b1 f51fe43c5d1c 6783e59e1c45
rev   line source
kaf24@6064 1 #============================================================================
kaf24@6064 2 # This library is free software; you can redistribute it and/or
kaf24@6064 3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
kaf24@6064 4 # License as published by the Free Software Foundation.
kaf24@6064 5 #
kaf24@6064 6 # This library is distributed in the hope that it will be useful,
kaf24@6064 7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
kaf24@6064 8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
kaf24@6064 9 # Lesser General Public License for more details.
kaf24@6064 10 #
kaf24@6064 11 # You should have received a copy of the GNU Lesser General Public
kaf24@6064 12 # License along with this library; if not, write to the Free Software
kaf24@6064 13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
kaf24@6064 14 #============================================================================
kaf24@6064 15 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
kaf24@6064 16 #============================================================================
kaf24@6064 17
mjw@1719 18 """General support for controllers, which handle devices
mjw@1719 19 for a domain.
mjw@1719 20 """
mjw@1654 21
mjw@4580 22 from xen.xend.XendError import XendError
cl349@5388 23 from xen.xend.xenstore import DBVar
cl349@5336 24 from xen.xend.server.messages import msgTypeName, printMsg, getMessageType
mjw@1623 25
mjw@2397 26 DEBUG = 0
mjw@1677 27
mjw@4580 28 class CtrlMsgRcvr:
mjw@4668 29 """Utility class to dispatch messages on a control channel.
mjw@4580 30 Once I{registerChannel} has been called, our message types are registered
mjw@4580 31 with the channel. The channel will call I{requestReceived}
mjw@4580 32 when a request arrives if it has one of our message types.
mjw@4580 33
mjw@4580 34 @ivar channel: channel to a domain
mjw@4580 35 @type channel: Channel
mjw@4580 36 @ivar majorTypes: major message types we are interested in
mjw@4580 37 @type majorTypes: {int:{int:method}}
mjw@4580 38
mjw@1677 39 """
mjw@1677 40
mjw@4580 41 def __init__(self, channel):
mjw@4580 42 self.majorTypes = {}
mjw@4580 43 self.channel = channel
mjw@1677 44
mjw@4580 45 def getHandler(self, type, subtype):
mjw@2224 46 """Get the method for a type and subtype.
mjw@2224 47
mjw@2224 48 @param type: major message type
mjw@2224 49 @param subtype: minor message type
mjw@2224 50 @return: method or None
mjw@2224 51 """
mjw@2224 52 method = None
mjw@2224 53 subtypes = self.majorTypes.get(type)
mjw@2224 54 if subtypes:
mjw@2224 55 method = subtypes.get(subtype)
mjw@2224 56 return method
mjw@2224 57
mjw@4580 58 def addHandler(self, type, subtype, method):
mjw@2224 59 """Add a method to handle a message type and subtype.
mjw@2224 60
mjw@2224 61 @param type: major message type
mjw@2224 62 @param subtype: minor message type
mjw@2224 63 @param method: method
mjw@2224 64 """
mjw@2224 65 subtypes = self.majorTypes.get(type)
mjw@2224 66 if not subtypes:
mjw@2224 67 subtypes = {}
mjw@2224 68 self.majorTypes[type] = subtypes
mjw@2224 69 subtypes[subtype] = method
mjw@2224 70
mjw@2224 71 def getMajorTypes(self):
mjw@2224 72 """Get the list of major message types handled.
mjw@2224 73 """
mjw@2224 74 return self.majorTypes.keys()
mjw@2224 75
mjw@1623 76 def requestReceived(self, msg, type, subtype):
mjw@1719 77 """Dispatch a request message to handlers.
mjw@1719 78 Called by the channel for requests with one of our types.
mjw@1654 79
mjw@1719 80 @param msg: message
mjw@1719 81 @type msg: xu message
mjw@1719 82 @param type: major message type
mjw@1719 83 @type type: int
mjw@1719 84 @param subtype: minor message type
mjw@1719 85 @type subtype: int
mjw@1654 86 """
mjw@1677 87 if DEBUG:
mjw@1719 88 print 'requestReceived>',
mjw@4580 89 printMsg(msg, all=True)
mjw@2265 90 responded = 0
mjw@4580 91 method = self.getHandler(type, subtype)
mjw@1623 92 if method:
mjw@4580 93 responded = method(msg)
mjw@1677 94 elif DEBUG:
mjw@1623 95 print ('requestReceived> No handler: Message type %s %d:%d'
mjw@1623 96 % (msgTypeName(type, subtype), type, subtype)), self
mjw@2265 97 return responded
mjw@1623 98
mjw@1677 99
mjw@1623 100 def lostChannel(self):
mjw@1654 101 """Called when the channel to the domain is lost.
mjw@1654 102 """
mjw@4617 103 if DEBUG:
mjw@4617 104 print 'CtrlMsgRcvr>lostChannel>',
mjw@4580 105 self.channel = None
mjw@1623 106
mjw@1623 107 def registerChannel(self):
mjw@1654 108 """Register interest in our major message types with the
mjw@1719 109 channel to our domain. Once we have registered, the channel
mjw@4580 110 will call requestReceived for our messages.
mjw@1654 111 """
mjw@4580 112 if DEBUG:
mjw@4580 113 print 'CtrlMsgRcvr>registerChannel>', self.channel, self.getMajorTypes()
mjw@4580 114 if self.channel:
mjw@2224 115 self.channel.registerDevice(self.getMajorTypes(), self)
mjw@1623 116
mjw@1623 117 def deregisterChannel(self):
mjw@1654 118 """Deregister interest in our major message types with the
mjw@1719 119 channel to our domain. After this the channel won't call
mjw@1719 120 us any more.
mjw@1654 121 """
mjw@1623 122 if self.channel:
mjw@1623 123 self.channel.deregisterDevice(self)
mjw@1623 124
mjw@4580 125 class DevControllerTable:
mjw@4668 126 """Table of device controller classes, indexed by type name.
mjw@2332 127 """
mjw@2332 128
mjw@2332 129 def __init__(self):
mjw@4668 130 self.controllerClasses = {}
mjw@4580 131
mjw@4668 132 def getDevControllerClass(self, type):
mjw@4668 133 return self.controllerClasses.get(type)
mjw@4580 134
cl349@5346 135 def addDevControllerClass(self, cls):
cl349@5346 136 self.controllerClasses[cls.getType()] = cls
mjw@2332 137
mjw@4668 138 def delDevControllerClass(self, type):
mjw@4668 139 if type in self.controllerClasses:
mjw@4668 140 del self.controllerClasses[type]
mjw@2332 141
mjw@4580 142 def createDevController(self, type, vm, recreate=False):
cl349@5346 143 cls = self.getDevControllerClass(type)
cl349@5346 144 if not cls:
mjw@4580 145 raise XendError("unknown device type: " + type)
cl349@5346 146 return cls.createDevController(vm, recreate=recreate)
mjw@2332 147
mjw@4580 148 def getDevControllerTable():
mjw@4668 149 """Singleton constructor for the controller table.
mjw@4668 150 """
mjw@4580 151 global devControllerTable
mjw@4580 152 try:
mjw@4580 153 devControllerTable
mjw@4580 154 except:
mjw@4580 155 devControllerTable = DevControllerTable()
mjw@4580 156 return devControllerTable
mjw@1623 157
cl349@5346 158 def addDevControllerClass(name, cls):
mjw@4668 159 """Add a device controller class to the controller table.
mjw@4668 160 """
cl349@5346 161 cls.type = name
cl349@5346 162 getDevControllerTable().addDevControllerClass(cls)
mjw@4580 163
mjw@4580 164 def createDevController(name, vm, recreate=False):
mjw@4580 165 return getDevControllerTable().createDevController(name, vm, recreate=recreate)
mjw@4580 166
mjw@4580 167 class DevController:
mjw@4580 168 """Abstract class for a device controller attached to a domain.
mjw@4580 169 A device controller manages all the devices of a given type for a domain.
mjw@4580 170 There is exactly one device controller for each device type for
mjw@4580 171 a domain.
mjw@2332 172
mjw@4580 173 """
mjw@4580 174
cl349@5388 175 # State:
cl349@5388 176 # controller/<type> : for controller
cl349@5388 177 # device/<type>/<id> : for each device
cl349@5388 178
cl349@5346 179 def createDevController(cls, vm, recreate=False):
mjw@4668 180 """Class method to create a dev controller.
mjw@4668 181 """
cl349@5346 182 ctrl = cls(vm, recreate=recreate)
mjw@4668 183 ctrl.initController(recreate=recreate)
cl349@5388 184 ctrl.exportToDB()
mjw@4668 185 return ctrl
mjw@4668 186
mjw@4668 187 createDevController = classmethod(createDevController)
mjw@4668 188
cl349@5346 189 def getType(cls):
cl349@5346 190 return cls.type
mjw@4668 191
mjw@4668 192 getType = classmethod(getType)
mjw@4668 193
cl349@5388 194 __exports__ = [
cl349@5388 195 DBVar('type', 'str'),
cl349@5388 196 DBVar('destroyed', 'bool'),
cl349@5388 197 ]
cl349@5388 198
cl349@5346 199 # Set when registered.
cl349@5346 200 type = None
cl349@5346 201
mjw@4668 202 def __init__(self, vm, recreate=False):
mjw@4580 203 self.destroyed = False
mjw@4580 204 self.vm = vm
cl349@5388 205 self.db = self.getDB()
mjw@4580 206 self.deviceId = 0
mjw@4580 207 self.devices = {}
mjw@4580 208 self.device_order = []
mjw@2332 209
cl349@5388 210 def getDB(self):
cl349@5388 211 """Get the db node to use for a controller.
cl349@5388 212 """
cl349@5388 213 return self.vm.db.addChild("/controller/%s" % self.getType())
cl349@5388 214
cl349@5388 215 def getDevDB(self, id):
cl349@5388 216 """Get the db node to use for a device.
cl349@5388 217 """
cl349@5388 218 return self.vm.db.addChild("/device/%s/%s" % (self.getType(), id))
cl349@5388 219
cl349@5388 220 def exportToDB(self, save=False):
cl349@5388 221 self.db.exportToDB(self, fields=self.__exports__, save=save)
cl349@5388 222
cl349@5388 223 def importFromDB(self):
cl349@5388 224 self.db.importFromDB(self, fields=self.__exports__)
cl349@5388 225
mjw@4580 226 def getDevControllerType(self):
mjw@4580 227 return self.dctype
mjw@2332 228
mjw@4580 229 def getDomain(self):
mjw@4580 230 return self.vm.getDomain()
mjw@4580 231
mjw@4580 232 def getDomainName(self):
mjw@4580 233 return self.vm.getName()
mjw@2332 234
mjw@4580 235 def getChannel(self):
mjw@4580 236 chan = self.vm.getChannel()
mjw@4580 237 return chan
mjw@4580 238
mjw@4580 239 def getDomainInfo(self):
mjw@4580 240 return self.vm
mjw@2332 241
mjw@4580 242 #----------------------------------------------------------------------------
mjw@4580 243 # Subclass interface.
mjw@4580 244 # Subclasses should define the unimplemented methods..
mjw@4580 245 # Redefinitions must have the same arguments.
mjw@2332 246
mjw@4580 247 def initController(self, recreate=False, reboot=False):
mjw@4668 248 """Initialise the controller. Called when the controller is
mjw@4668 249 first created, and again after the domain is rebooted (with reboot True).
mjw@4668 250 If called with recreate True (and reboot False) the controller is being
mjw@4668 251 recreated after a xend restart.
mjw@4668 252
mjw@4668 253 As this can be a re-init (after reboot) any controller state should
mjw@4668 254 be reset. For example the destroyed flag.
mjw@4668 255 """
mjw@4580 256 self.destroyed = False
mjw@4580 257 if reboot:
mjw@4580 258 self.rebootDevices()
mjw@4580 259
mjw@4580 260 def newDevice(self, id, config, recreate=False):
mjw@4580 261 """Create a device with the given config.
mjw@4580 262 Must be defined in subclass.
mjw@4668 263 Called with recreate True when the device is being recreated after a
mjw@4668 264 xend restart.
mjw@4580 265
mjw@4580 266 @return device
mjw@2332 267 """
mjw@2332 268 raise NotImplementedError()
mjw@2332 269
mjw@4580 270 def createDevice(self, config, recreate=False, change=False):
mjw@4668 271 """Create a device and attach to its front- and back-ends.
mjw@4668 272 If recreate is true the device is being recreated after a xend restart.
mjw@4668 273 If change is true the device is a change to an existing domain,
mjw@4668 274 i.e. it is being added at runtime rather than when the domain is created.
mjw@4668 275 """
cl349@5388 276 dev = self.newDevice(self.nextDeviceId(), config, recreate=recreate)
cl349@5388 277 if self.vm.recreate:
cl349@5388 278 dev.importFromDB()
mjw@4580 279 dev.init(recreate=recreate)
mjw@4580 280 self.addDevice(dev)
cl349@5388 281 if not recreate:
cl349@5388 282 dev.exportToDB()
mjw@4580 283 dev.attach(recreate=recreate, change=change)
cl349@5388 284 dev.exportToDB()
mjw@4580 285
mjw@4580 286 def configureDevice(self, id, config, change=False):
mjw@4580 287 """Reconfigure an existing device.
mjw@4580 288 May be defined in subclass."""
cl349@5338 289 dev = self.getDevice(id, error=True)
mjw@4580 290 dev.configure(config, change=change)
mjw@2267 291
mjw@4580 292 def destroyDevice(self, id, change=False, reboot=False):
mjw@4580 293 """Destroy a device.
mjw@4668 294 May be defined in subclass.
mjw@4668 295
mjw@4668 296 If reboot is true the device is being destroyed for a domain reboot.
mjw@4668 297
mjw@4668 298 The device is not deleted, since it may be recreated later.
mjw@4668 299 """
cl349@5338 300 dev = self.getDevice(id, error=True)
mjw@4580 301 dev.destroy(change=change, reboot=reboot)
mjw@4580 302 return dev
mjw@4580 303
mjw@4580 304 def deleteDevice(self, id, change=True):
mjw@4668 305 """Destroy a device and delete it.
mjw@4668 306 Normally called to remove a device from a domain at runtime.
mjw@4668 307 """
mjw@4580 308 dev = self.destroyDevice(id, change=change)
mjw@4580 309 self.removeDevice(dev)
mjw@4580 310
mjw@4580 311 def destroyController(self, reboot=False):
mjw@4580 312 """Destroy all devices and clean up.
mjw@4668 313 May be defined in subclass.
mjw@4668 314 If reboot is true the controller is being destroyed for a domain reboot.
mjw@4668 315 Called at domain shutdown.
mjw@4668 316 """
mjw@4580 317 self.destroyed = True
mjw@4580 318 self.destroyDevices(reboot=reboot)
mjw@4580 319
mjw@4580 320 #----------------------------------------------------------------------------
mjw@4580 321
mjw@4580 322 def isDestroyed(self):
mjw@4580 323 return self.destroyed
mjw@4580 324
cl349@5338 325 def getDevice(self, id, error=False):
cl349@5338 326 dev = self.devices.get(id)
cl349@5338 327 if error and not dev:
cl349@5338 328 raise XendError("invalid device id: " + id)
cl349@5338 329 return dev
mjw@4580 330
mjw@4580 331 def getDeviceIds(self):
mjw@4580 332 return [ dev.getId() for dev in self.device_order ]
mjw@4580 333
mjw@4580 334 def getDevices(self):
mjw@4580 335 return self.device_order
mjw@4580 336
mjw@4580 337 def getDeviceConfig(self, id):
mjw@4580 338 return self.getDevice(id).getConfig()
mjw@4580 339
mjw@4580 340 def getDeviceConfigs(self):
mjw@4580 341 return [ dev.getConfig() for dev in self.device_order ]
mjw@4580 342
mjw@4580 343 def getDeviceSxprs(self):
mjw@4580 344 return [ dev.sxpr() for dev in self.device_order ]
mjw@4580 345
mjw@4580 346 def addDevice(self, dev):
mjw@4580 347 self.devices[dev.getId()] = dev
mjw@4580 348 self.device_order.append(dev)
mjw@4580 349 return dev
mjw@4580 350
mjw@4580 351 def removeDevice(self, dev):
mjw@4580 352 if dev.getId() in self.devices:
mjw@4580 353 del self.devices[dev.getId()]
mjw@4580 354 if dev in self.device_order:
mjw@4580 355 self.device_order.remove(dev)
mjw@4580 356
mjw@4580 357 def rebootDevices(self):
mjw@4580 358 for dev in self.getDevices():
mjw@4580 359 dev.reboot()
mjw@4580 360
mjw@4580 361 def destroyDevices(self, reboot=False):
mjw@4580 362 """Destroy all devices.
mjw@4580 363 """
mjw@4580 364 for dev in self.getDevices():
mjw@4580 365 dev.destroy(reboot=reboot)
mjw@2225 366
mjw@4580 367 def getMaxDeviceId(self):
mjw@4580 368 maxid = 0
mjw@4580 369 for id in self.devices:
mjw@4580 370 if id > maxid:
mjw@4580 371 maxid = id
mjw@4580 372 return maxid
mjw@4580 373
mjw@4580 374 def nextDeviceId(self):
mjw@4580 375 id = self.deviceId
mjw@4580 376 self.deviceId += 1
mjw@4580 377 return id
mjw@4580 378
mjw@4580 379 def getDeviceCount(self):
mjw@4580 380 return len(self.devices)
mjw@4580 381
mjw@4580 382 class Dev:
mjw@4580 383 """Abstract class for a device attached to a device controller.
mjw@2332 384
mjw@4580 385 @ivar id: identifier
mjw@4580 386 @type id: int
mjw@4580 387 @ivar controller: device controller
mjw@4580 388 @type controller: DevController
mjw@4580 389 """
mjw@4580 390
cl349@5388 391 # ./status : need 2: actual and requested?
cl349@5388 392 # down-down: initial.
cl349@5388 393 # up-up: fully up.
cl349@5388 394 # down-up: down requested, still up. Watch front and back, when both
cl349@5388 395 # down go to down-down. But what if one (or both) is not connected?
cl349@5388 396 # Still have front/back trees with status? Watch front/status, back/status?
cl349@5388 397 # up-down: up requested, still down.
cl349@5388 398 # Back-end watches ./status, front/status
cl349@5388 399 # Front-end watches ./status, back/status
cl349@5388 400 # i.e. each watches the other 2.
cl349@5388 401 # Each is status/request status/actual?
cl349@5388 402 #
cl349@5388 403 # backend?
cl349@5388 404 # frontend?
cl349@5388 405
cl349@5388 406 __exports__ = [
cl349@5388 407 DBVar('id', ty='int'),
cl349@5388 408 DBVar('type', ty='str'),
cl349@5388 409 DBVar('config', ty='sxpr'),
cl349@5388 410 DBVar('destroyed', ty='bool'),
cl349@5388 411 ]
cl349@5388 412
mjw@4580 413 def __init__(self, controller, id, config, recreate=False):
mjw@4580 414 self.controller = controller
mjw@4580 415 self.id = id
mjw@4580 416 self.config = config
mjw@4580 417 self.destroyed = False
cl349@5388 418 self.type = self.getType()
cl349@5388 419
cl349@5388 420 self.db = controller.getDevDB(id)
cl349@5388 421
cl349@5388 422 def exportToDB(self, save=False):
cl349@5388 423 self.db.exportToDB(self, fields=self.__exports__, save=save)
cl349@5388 424
cl349@5388 425 def importFromDB(self):
cl349@5388 426 self.db.importFromDB(self, fields=self.__exports__)
mjw@4580 427
mjw@4580 428 def getDomain(self):
mjw@4580 429 return self.controller.getDomain()
mjw@4580 430
mjw@4580 431 def getDomainName(self):
mjw@4580 432 return self.controller.getDomainName()
mjw@4580 433
mjw@4580 434 def getChannel(self):
mjw@4580 435 return self.controller.getChannel()
mjw@4580 436
mjw@4580 437 def getDomainInfo(self):
mjw@4580 438 return self.controller.getDomainInfo()
mjw@4580 439
mjw@4580 440 def getController(self):
mjw@4580 441 return self.controller
mjw@4580 442
mjw@4580 443 def getType(self):
mjw@4580 444 return self.controller.getType()
mjw@2332 445
mjw@4580 446 def getId(self):
mjw@4580 447 return self.id
mjw@4580 448
mjw@4580 449 def getConfig(self):
mjw@4580 450 return self.config
mjw@4580 451
mjw@4580 452 def isDestroyed(self):
mjw@4580 453 return self.destroyed
mjw@4580 454
mjw@4580 455 #----------------------------------------------------------------------------
mjw@4580 456 # Subclass interface.
mjw@4580 457 # Define methods in subclass as needed.
mjw@4580 458 # Redefinitions must have the same arguments.
mjw@4580 459
mjw@4580 460 def init(self, recreate=False, reboot=False):
mjw@4580 461 """Initialization. Called on initial create (when reboot is False)
mjw@4580 462 and on reboot (when reboot is True). When xend is restarting is
mjw@4580 463 called with recreate True. Define in subclass if needed.
mjw@4668 464
mjw@4668 465 Device instance variables must be defined in the class constructor,
mjw@4668 466 but given null or default values. The real values should be initialised
mjw@4668 467 in this method. This allows devices to be re-initialised.
mjw@4668 468
mjw@4668 469 Since this can be called to re-initialise a device any state flags
mjw@4668 470 should be reset.
mjw@4580 471 """
mjw@4580 472 self.destroyed = False
mjw@2332 473
mjw@4580 474 def attach(self, recreate=False, change=False):
mjw@4580 475 """Attach the device to its front and back ends.
mjw@4580 476 Define in subclass if needed.
mjw@4580 477 """
mjw@4580 478 pass
mjw@4580 479
mjw@4580 480 def reboot(self):
mjw@4668 481 """Reconnect the device when the domain is rebooted.
mjw@4580 482 """
mjw@4580 483 self.init(reboot=True)
mjw@4580 484 self.attach()
mjw@2332 485
mjw@4580 486 def sxpr(self):
mjw@4580 487 """Get the s-expression for the deivice.
mjw@4580 488 Implement in a subclass if needed.
mjw@2332 489
mjw@4580 490 @return: sxpr
mjw@4580 491 """
mjw@4580 492 return self.getConfig()
mjw@4580 493
mjw@4580 494 def configure(self, config, change=False):
mjw@4580 495 """Reconfigure the device.
mjw@4580 496
mjw@4580 497 Implement in subclass.
mjw@2332 498 """
mjw@2332 499 raise NotImplementedError()
mjw@2332 500
mjw@4580 501 def refresh(self):
mjw@4580 502 """Refresh the device..
mjw@4580 503 Default no-op. Define in subclass if needed.
mjw@2520 504 """
mjw@4580 505 pass
mjw@2185 506
mjw@4580 507 def destroy(self, change=False, reboot=False):
mjw@4580 508 """Destroy the device.
mjw@4580 509 If change is True notify destruction (runtime change).
mjw@4580 510 If reboot is True the device is being destroyed for a reboot.
mjw@4580 511 Redefine in subclass if needed.
mjw@4668 512
mjw@4668 513 Called at domain shutdown and when a device is deleted from
mjw@4668 514 a running domain (with change True).
mjw@4580 515 """
mjw@4580 516 self.destroyed = True
mjw@4580 517 pass
mjw@1654 518
mjw@4580 519 #----------------------------------------------------------------------------