xen-vtx-unstable

annotate tools/python/xen/xend/server/controller.py @ 6132:058e8087d36a

If block-create didn't work, then chances are block-destroy doesn't work
either right :-)

In this case, XendDomain.py is just calling a function that doesn't
exist (device_destroy instead of device_delete).

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
author kaf24@firebug.cl.cam.ac.uk
date Sat Aug 13 09:06:44 2005 +0000 (2005-08-13)
parents f056b0cc171e
children 8864f0be80c6
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:
kaf24@6131 145 raise XendError("unknown device type: " + str(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
kaf24@6131 286 return dev
kaf24@6131 287
mjw@4580 288 def configureDevice(self, id, config, change=False):
mjw@4580 289 """Reconfigure an existing device.
mjw@4580 290 May be defined in subclass."""
cl349@5338 291 dev = self.getDevice(id, error=True)
mjw@4580 292 dev.configure(config, change=change)
mjw@2267 293
mjw@4580 294 def destroyDevice(self, id, change=False, reboot=False):
mjw@4580 295 """Destroy a device.
mjw@4668 296 May be defined in subclass.
mjw@4668 297
mjw@4668 298 If reboot is true the device is being destroyed for a domain reboot.
mjw@4668 299
mjw@4668 300 The device is not deleted, since it may be recreated later.
mjw@4668 301 """
cl349@5338 302 dev = self.getDevice(id, error=True)
mjw@4580 303 dev.destroy(change=change, reboot=reboot)
mjw@4580 304 return dev
mjw@4580 305
mjw@4580 306 def deleteDevice(self, id, change=True):
mjw@4668 307 """Destroy a device and delete it.
mjw@4668 308 Normally called to remove a device from a domain at runtime.
mjw@4668 309 """
mjw@4580 310 dev = self.destroyDevice(id, change=change)
mjw@4580 311 self.removeDevice(dev)
mjw@4580 312
mjw@4580 313 def destroyController(self, reboot=False):
mjw@4580 314 """Destroy all devices and clean up.
mjw@4668 315 May be defined in subclass.
mjw@4668 316 If reboot is true the controller is being destroyed for a domain reboot.
mjw@4668 317 Called at domain shutdown.
mjw@4668 318 """
mjw@4580 319 self.destroyed = True
mjw@4580 320 self.destroyDevices(reboot=reboot)
mjw@4580 321
mjw@4580 322 #----------------------------------------------------------------------------
mjw@4580 323
mjw@4580 324 def isDestroyed(self):
mjw@4580 325 return self.destroyed
mjw@4580 326
cl349@5338 327 def getDevice(self, id, error=False):
kaf24@6132 328 dev = self.devices.get(int(id))
cl349@5338 329 if error and not dev:
kaf24@6131 330 raise XendError("invalid device id: " + str(id))
cl349@5338 331 return dev
mjw@4580 332
mjw@4580 333 def getDeviceIds(self):
mjw@4580 334 return [ dev.getId() for dev in self.device_order ]
mjw@4580 335
mjw@4580 336 def getDevices(self):
mjw@4580 337 return self.device_order
mjw@4580 338
mjw@4580 339 def getDeviceConfig(self, id):
mjw@4580 340 return self.getDevice(id).getConfig()
mjw@4580 341
mjw@4580 342 def getDeviceConfigs(self):
mjw@4580 343 return [ dev.getConfig() for dev in self.device_order ]
mjw@4580 344
mjw@4580 345 def getDeviceSxprs(self):
mjw@4580 346 return [ dev.sxpr() for dev in self.device_order ]
mjw@4580 347
mjw@4580 348 def addDevice(self, dev):
mjw@4580 349 self.devices[dev.getId()] = dev
mjw@4580 350 self.device_order.append(dev)
mjw@4580 351 return dev
mjw@4580 352
mjw@4580 353 def removeDevice(self, dev):
mjw@4580 354 if dev.getId() in self.devices:
mjw@4580 355 del self.devices[dev.getId()]
mjw@4580 356 if dev in self.device_order:
mjw@4580 357 self.device_order.remove(dev)
mjw@4580 358
mjw@4580 359 def rebootDevices(self):
mjw@4580 360 for dev in self.getDevices():
mjw@4580 361 dev.reboot()
mjw@4580 362
mjw@4580 363 def destroyDevices(self, reboot=False):
mjw@4580 364 """Destroy all devices.
mjw@4580 365 """
mjw@4580 366 for dev in self.getDevices():
mjw@4580 367 dev.destroy(reboot=reboot)
mjw@2225 368
mjw@4580 369 def getMaxDeviceId(self):
mjw@4580 370 maxid = 0
mjw@4580 371 for id in self.devices:
mjw@4580 372 if id > maxid:
mjw@4580 373 maxid = id
mjw@4580 374 return maxid
mjw@4580 375
mjw@4580 376 def nextDeviceId(self):
mjw@4580 377 id = self.deviceId
mjw@4580 378 self.deviceId += 1
mjw@4580 379 return id
mjw@4580 380
mjw@4580 381 def getDeviceCount(self):
mjw@4580 382 return len(self.devices)
mjw@4580 383
mjw@4580 384 class Dev:
mjw@4580 385 """Abstract class for a device attached to a device controller.
mjw@2332 386
mjw@4580 387 @ivar id: identifier
mjw@4580 388 @type id: int
mjw@4580 389 @ivar controller: device controller
mjw@4580 390 @type controller: DevController
mjw@4580 391 """
mjw@4580 392
cl349@5388 393 # ./status : need 2: actual and requested?
cl349@5388 394 # down-down: initial.
cl349@5388 395 # up-up: fully up.
cl349@5388 396 # down-up: down requested, still up. Watch front and back, when both
cl349@5388 397 # down go to down-down. But what if one (or both) is not connected?
cl349@5388 398 # Still have front/back trees with status? Watch front/status, back/status?
cl349@5388 399 # up-down: up requested, still down.
cl349@5388 400 # Back-end watches ./status, front/status
cl349@5388 401 # Front-end watches ./status, back/status
cl349@5388 402 # i.e. each watches the other 2.
cl349@5388 403 # Each is status/request status/actual?
cl349@5388 404 #
cl349@5388 405 # backend?
cl349@5388 406 # frontend?
cl349@5388 407
cl349@5388 408 __exports__ = [
cl349@5388 409 DBVar('id', ty='int'),
cl349@5388 410 DBVar('type', ty='str'),
cl349@5388 411 DBVar('config', ty='sxpr'),
cl349@5388 412 DBVar('destroyed', ty='bool'),
cl349@5388 413 ]
cl349@5388 414
mjw@4580 415 def __init__(self, controller, id, config, recreate=False):
mjw@4580 416 self.controller = controller
mjw@4580 417 self.id = id
mjw@4580 418 self.config = config
mjw@4580 419 self.destroyed = False
cl349@5388 420 self.type = self.getType()
cl349@5388 421
cl349@5388 422 self.db = controller.getDevDB(id)
cl349@5388 423
cl349@5388 424 def exportToDB(self, save=False):
cl349@5388 425 self.db.exportToDB(self, fields=self.__exports__, save=save)
cl349@5388 426
cl349@5388 427 def importFromDB(self):
cl349@5388 428 self.db.importFromDB(self, fields=self.__exports__)
mjw@4580 429
mjw@4580 430 def getDomain(self):
mjw@4580 431 return self.controller.getDomain()
mjw@4580 432
mjw@4580 433 def getDomainName(self):
mjw@4580 434 return self.controller.getDomainName()
mjw@4580 435
mjw@4580 436 def getChannel(self):
mjw@4580 437 return self.controller.getChannel()
mjw@4580 438
mjw@4580 439 def getDomainInfo(self):
mjw@4580 440 return self.controller.getDomainInfo()
mjw@4580 441
mjw@4580 442 def getController(self):
mjw@4580 443 return self.controller
mjw@4580 444
mjw@4580 445 def getType(self):
mjw@4580 446 return self.controller.getType()
mjw@2332 447
mjw@4580 448 def getId(self):
mjw@4580 449 return self.id
mjw@4580 450
mjw@4580 451 def getConfig(self):
mjw@4580 452 return self.config
mjw@4580 453
mjw@4580 454 def isDestroyed(self):
mjw@4580 455 return self.destroyed
mjw@4580 456
mjw@4580 457 #----------------------------------------------------------------------------
mjw@4580 458 # Subclass interface.
mjw@4580 459 # Define methods in subclass as needed.
mjw@4580 460 # Redefinitions must have the same arguments.
mjw@4580 461
mjw@4580 462 def init(self, recreate=False, reboot=False):
mjw@4580 463 """Initialization. Called on initial create (when reboot is False)
mjw@4580 464 and on reboot (when reboot is True). When xend is restarting is
mjw@4580 465 called with recreate True. Define in subclass if needed.
mjw@4668 466
mjw@4668 467 Device instance variables must be defined in the class constructor,
mjw@4668 468 but given null or default values. The real values should be initialised
mjw@4668 469 in this method. This allows devices to be re-initialised.
mjw@4668 470
mjw@4668 471 Since this can be called to re-initialise a device any state flags
mjw@4668 472 should be reset.
mjw@4580 473 """
mjw@4580 474 self.destroyed = False
mjw@2332 475
mjw@4580 476 def attach(self, recreate=False, change=False):
mjw@4580 477 """Attach the device to its front and back ends.
mjw@4580 478 Define in subclass if needed.
mjw@4580 479 """
mjw@4580 480 pass
mjw@4580 481
mjw@4580 482 def reboot(self):
mjw@4668 483 """Reconnect the device when the domain is rebooted.
mjw@4580 484 """
mjw@4580 485 self.init(reboot=True)
mjw@4580 486 self.attach()
mjw@2332 487
mjw@4580 488 def sxpr(self):
mjw@4580 489 """Get the s-expression for the deivice.
mjw@4580 490 Implement in a subclass if needed.
mjw@2332 491
mjw@4580 492 @return: sxpr
mjw@4580 493 """
mjw@4580 494 return self.getConfig()
mjw@4580 495
mjw@4580 496 def configure(self, config, change=False):
mjw@4580 497 """Reconfigure the device.
mjw@4580 498
mjw@4580 499 Implement in subclass.
mjw@2332 500 """
mjw@2332 501 raise NotImplementedError()
mjw@2332 502
mjw@4580 503 def refresh(self):
mjw@4580 504 """Refresh the device..
mjw@4580 505 Default no-op. Define in subclass if needed.
mjw@2520 506 """
mjw@4580 507 pass
mjw@2185 508
mjw@4580 509 def destroy(self, change=False, reboot=False):
mjw@4580 510 """Destroy the device.
mjw@4580 511 If change is True notify destruction (runtime change).
mjw@4580 512 If reboot is True the device is being destroyed for a reboot.
mjw@4580 513 Redefine in subclass if needed.
mjw@4668 514
mjw@4668 515 Called at domain shutdown and when a device is deleted from
mjw@4668 516 a running domain (with change True).
mjw@4580 517 """
mjw@4580 518 self.destroyed = True
mjw@4580 519 pass
mjw@1654 520
mjw@4580 521 #----------------------------------------------------------------------------