xen-vtx-unstable

annotate tools/python/xen/xend/server/controller.py @ 6671:7d0fb56b4a91

merge?
author cl349@firebug.cl.cam.ac.uk
date Wed Sep 07 19:01:31 2005 +0000 (2005-09-07)
parents 0e2b1e04d4cb dd668f7527cb
children 5aa6a2eff69f 4d899a738d59 8ca0f98ba8e2
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
mjw@1623 24
mjw@2397 25 DEBUG = 0
mjw@1677 26
mjw@4580 27 class DevControllerTable:
mjw@4668 28 """Table of device controller classes, indexed by type name.
mjw@2332 29 """
mjw@2332 30
mjw@2332 31 def __init__(self):
mjw@4668 32 self.controllerClasses = {}
mjw@4580 33
mjw@4668 34 def getDevControllerClass(self, type):
mjw@4668 35 return self.controllerClasses.get(type)
mjw@4580 36
cl349@5346 37 def addDevControllerClass(self, cls):
cl349@5346 38 self.controllerClasses[cls.getType()] = cls
mjw@2332 39
mjw@4668 40 def delDevControllerClass(self, type):
mjw@4668 41 if type in self.controllerClasses:
mjw@4668 42 del self.controllerClasses[type]
mjw@2332 43
mjw@4580 44 def createDevController(self, type, vm, recreate=False):
cl349@5346 45 cls = self.getDevControllerClass(type)
cl349@5346 46 if not cls:
kaf24@6131 47 raise XendError("unknown device type: " + str(type))
cl349@5346 48 return cls.createDevController(vm, recreate=recreate)
mjw@2332 49
mjw@4580 50 def getDevControllerTable():
mjw@4668 51 """Singleton constructor for the controller table.
mjw@4668 52 """
mjw@4580 53 global devControllerTable
mjw@4580 54 try:
mjw@4580 55 devControllerTable
mjw@4580 56 except:
mjw@4580 57 devControllerTable = DevControllerTable()
mjw@4580 58 return devControllerTable
mjw@1623 59
cl349@5346 60 def addDevControllerClass(name, cls):
mjw@4668 61 """Add a device controller class to the controller table.
mjw@4668 62 """
cl349@5346 63 cls.type = name
cl349@5346 64 getDevControllerTable().addDevControllerClass(cls)
mjw@4580 65
mjw@4580 66 def createDevController(name, vm, recreate=False):
mjw@4580 67 return getDevControllerTable().createDevController(name, vm, recreate=recreate)
mjw@4580 68
mjw@4580 69 class DevController:
mjw@4580 70 """Abstract class for a device controller attached to a domain.
mjw@4580 71 A device controller manages all the devices of a given type for a domain.
mjw@4580 72 There is exactly one device controller for each device type for
mjw@4580 73 a domain.
mjw@2332 74
mjw@4580 75 """
mjw@4580 76
cl349@5388 77 # State:
cl349@5388 78 # controller/<type> : for controller
cl349@5388 79 # device/<type>/<id> : for each device
cl349@5388 80
cl349@5346 81 def createDevController(cls, vm, recreate=False):
mjw@4668 82 """Class method to create a dev controller.
mjw@4668 83 """
cl349@5346 84 ctrl = cls(vm, recreate=recreate)
mjw@4668 85 ctrl.initController(recreate=recreate)
cl349@5388 86 ctrl.exportToDB()
mjw@4668 87 return ctrl
mjw@4668 88
mjw@4668 89 createDevController = classmethod(createDevController)
mjw@4668 90
cl349@5346 91 def getType(cls):
cl349@5346 92 return cls.type
mjw@4668 93
mjw@4668 94 getType = classmethod(getType)
mjw@4668 95
cl349@5388 96 __exports__ = [
cl349@5388 97 DBVar('type', 'str'),
cl349@5388 98 DBVar('destroyed', 'bool'),
cl349@5388 99 ]
cl349@5388 100
cl349@5346 101 # Set when registered.
cl349@5346 102 type = None
cl349@5346 103
mjw@4668 104 def __init__(self, vm, recreate=False):
mjw@4580 105 self.destroyed = False
mjw@4580 106 self.vm = vm
cl349@5388 107 self.db = self.getDB()
mjw@4580 108 self.deviceId = 0
mjw@4580 109 self.devices = {}
mjw@4580 110 self.device_order = []
mjw@2332 111
cl349@5388 112 def getDB(self):
cl349@5388 113 """Get the db node to use for a controller.
cl349@5388 114 """
cl349@5388 115 return self.vm.db.addChild("/controller/%s" % self.getType())
cl349@5388 116
cl349@5388 117 def getDevDB(self, id):
cl349@5388 118 """Get the db node to use for a device.
cl349@5388 119 """
cl349@5388 120 return self.vm.db.addChild("/device/%s/%s" % (self.getType(), id))
cl349@5388 121
cl349@5388 122 def exportToDB(self, save=False):
cl349@5388 123 self.db.exportToDB(self, fields=self.__exports__, save=save)
cl349@5388 124
cl349@5388 125 def importFromDB(self):
cl349@5388 126 self.db.importFromDB(self, fields=self.__exports__)
cl349@5388 127
mjw@4580 128 def getDevControllerType(self):
mjw@4580 129 return self.dctype
mjw@2332 130
mjw@4580 131 def getDomain(self):
mjw@4580 132 return self.vm.getDomain()
mjw@4580 133
mjw@4580 134 def getDomainName(self):
mjw@4580 135 return self.vm.getName()
mjw@2332 136
mjw@4580 137 def getDomainInfo(self):
mjw@4580 138 return self.vm
mjw@2332 139
mjw@4580 140 #----------------------------------------------------------------------------
mjw@4580 141 # Subclass interface.
mjw@4580 142 # Subclasses should define the unimplemented methods..
mjw@4580 143 # Redefinitions must have the same arguments.
mjw@2332 144
mjw@4580 145 def initController(self, recreate=False, reboot=False):
mjw@4668 146 """Initialise the controller. Called when the controller is
mjw@4668 147 first created, and again after the domain is rebooted (with reboot True).
mjw@4668 148 If called with recreate True (and reboot False) the controller is being
mjw@4668 149 recreated after a xend restart.
mjw@4668 150
mjw@4668 151 As this can be a re-init (after reboot) any controller state should
mjw@4668 152 be reset. For example the destroyed flag.
mjw@4668 153 """
mjw@4580 154 self.destroyed = False
mjw@4580 155 if reboot:
mjw@4580 156 self.rebootDevices()
mjw@4580 157
mjw@4580 158 def newDevice(self, id, config, recreate=False):
mjw@4580 159 """Create a device with the given config.
mjw@4580 160 Must be defined in subclass.
mjw@4668 161 Called with recreate True when the device is being recreated after a
mjw@4668 162 xend restart.
mjw@4580 163
mjw@4580 164 @return device
mjw@2332 165 """
mjw@2332 166 raise NotImplementedError()
mjw@2332 167
mjw@4580 168 def createDevice(self, config, recreate=False, change=False):
mjw@4668 169 """Create a device and attach to its front- and back-ends.
mjw@4668 170 If recreate is true the device is being recreated after a xend restart.
mjw@4668 171 If change is true the device is a change to an existing domain,
mjw@4668 172 i.e. it is being added at runtime rather than when the domain is created.
mjw@4668 173 """
cl349@5388 174 dev = self.newDevice(self.nextDeviceId(), config, recreate=recreate)
cl349@5388 175 if self.vm.recreate:
cl349@5388 176 dev.importFromDB()
mjw@4580 177 dev.init(recreate=recreate)
mjw@4580 178 self.addDevice(dev)
cl349@5388 179 if not recreate:
cl349@5388 180 dev.exportToDB()
mjw@4580 181 dev.attach(recreate=recreate, change=change)
cl349@5388 182 dev.exportToDB()
mjw@4580 183
kaf24@6131 184 return dev
kaf24@6131 185
mjw@4580 186 def configureDevice(self, id, config, change=False):
mjw@4580 187 """Reconfigure an existing device.
mjw@4580 188 May be defined in subclass."""
cl349@5338 189 dev = self.getDevice(id, error=True)
mjw@4580 190 dev.configure(config, change=change)
mjw@2267 191
mjw@4580 192 def destroyDevice(self, id, change=False, reboot=False):
mjw@4580 193 """Destroy a device.
mjw@4668 194 May be defined in subclass.
mjw@4668 195
mjw@4668 196 If reboot is true the device is being destroyed for a domain reboot.
mjw@4668 197
mjw@4668 198 The device is not deleted, since it may be recreated later.
mjw@4668 199 """
cl349@5338 200 dev = self.getDevice(id, error=True)
mjw@4580 201 dev.destroy(change=change, reboot=reboot)
mjw@4580 202 return dev
mjw@4580 203
mjw@4580 204 def deleteDevice(self, id, change=True):
mjw@4668 205 """Destroy a device and delete it.
mjw@4668 206 Normally called to remove a device from a domain at runtime.
mjw@4668 207 """
mjw@4580 208 dev = self.destroyDevice(id, change=change)
mjw@4580 209 self.removeDevice(dev)
mjw@4580 210
mjw@4580 211 def destroyController(self, reboot=False):
mjw@4580 212 """Destroy all devices and clean up.
mjw@4668 213 May be defined in subclass.
mjw@4668 214 If reboot is true the controller is being destroyed for a domain reboot.
mjw@4668 215 Called at domain shutdown.
mjw@4668 216 """
mjw@4580 217 self.destroyed = True
mjw@4580 218 self.destroyDevices(reboot=reboot)
mjw@4580 219
mjw@4580 220 #----------------------------------------------------------------------------
mjw@4580 221
mjw@4580 222 def isDestroyed(self):
mjw@4580 223 return self.destroyed
mjw@4580 224
cl349@5338 225 def getDevice(self, id, error=False):
kaf24@6132 226 dev = self.devices.get(int(id))
cl349@5338 227 if error and not dev:
kaf24@6131 228 raise XendError("invalid device id: " + str(id))
cl349@5338 229 return dev
mjw@4580 230
mjw@4580 231 def getDeviceIds(self):
mjw@4580 232 return [ dev.getId() for dev in self.device_order ]
mjw@4580 233
mjw@4580 234 def getDevices(self):
mjw@4580 235 return self.device_order
mjw@4580 236
mjw@4580 237 def getDeviceConfig(self, id):
mjw@4580 238 return self.getDevice(id).getConfig()
mjw@4580 239
mjw@4580 240 def getDeviceConfigs(self):
mjw@4580 241 return [ dev.getConfig() for dev in self.device_order ]
mjw@4580 242
mjw@4580 243 def getDeviceSxprs(self):
mjw@4580 244 return [ dev.sxpr() for dev in self.device_order ]
mjw@4580 245
mjw@4580 246 def addDevice(self, dev):
mjw@4580 247 self.devices[dev.getId()] = dev
mjw@4580 248 self.device_order.append(dev)
mjw@4580 249 return dev
mjw@4580 250
mjw@4580 251 def removeDevice(self, dev):
mjw@4580 252 if dev.getId() in self.devices:
mjw@4580 253 del self.devices[dev.getId()]
mjw@4580 254 if dev in self.device_order:
mjw@4580 255 self.device_order.remove(dev)
mjw@4580 256
mjw@4580 257 def rebootDevices(self):
mjw@4580 258 for dev in self.getDevices():
mjw@4580 259 dev.reboot()
mjw@4580 260
mjw@4580 261 def destroyDevices(self, reboot=False):
mjw@4580 262 """Destroy all devices.
mjw@4580 263 """
mjw@4580 264 for dev in self.getDevices():
mjw@4580 265 dev.destroy(reboot=reboot)
mjw@2225 266
mjw@4580 267 def getMaxDeviceId(self):
mjw@4580 268 maxid = 0
mjw@4580 269 for id in self.devices:
mjw@4580 270 if id > maxid:
mjw@4580 271 maxid = id
mjw@4580 272 return maxid
mjw@4580 273
mjw@4580 274 def nextDeviceId(self):
mjw@4580 275 id = self.deviceId
mjw@4580 276 self.deviceId += 1
mjw@4580 277 return id
mjw@4580 278
mjw@4580 279 def getDeviceCount(self):
mjw@4580 280 return len(self.devices)
mjw@4580 281
mjw@4580 282 class Dev:
mjw@4580 283 """Abstract class for a device attached to a device controller.
mjw@2332 284
mjw@4580 285 @ivar id: identifier
mjw@4580 286 @type id: int
mjw@4580 287 @ivar controller: device controller
mjw@4580 288 @type controller: DevController
mjw@4580 289 """
mjw@4580 290
cl349@5388 291 # ./status : need 2: actual and requested?
cl349@5388 292 # down-down: initial.
cl349@5388 293 # up-up: fully up.
cl349@5388 294 # down-up: down requested, still up. Watch front and back, when both
cl349@5388 295 # down go to down-down. But what if one (or both) is not connected?
cl349@5388 296 # Still have front/back trees with status? Watch front/status, back/status?
cl349@5388 297 # up-down: up requested, still down.
cl349@5388 298 # Back-end watches ./status, front/status
cl349@5388 299 # Front-end watches ./status, back/status
cl349@5388 300 # i.e. each watches the other 2.
cl349@5388 301 # Each is status/request status/actual?
cl349@5388 302 #
cl349@5388 303 # backend?
cl349@5388 304 # frontend?
cl349@5388 305
cl349@5388 306 __exports__ = [
cl349@5388 307 DBVar('id', ty='int'),
cl349@5388 308 DBVar('type', ty='str'),
cl349@5388 309 DBVar('config', ty='sxpr'),
cl349@5388 310 DBVar('destroyed', ty='bool'),
cl349@5388 311 ]
cl349@5388 312
mjw@4580 313 def __init__(self, controller, id, config, recreate=False):
mjw@4580 314 self.controller = controller
mjw@4580 315 self.id = id
mjw@4580 316 self.config = config
mjw@4580 317 self.destroyed = False
cl349@5388 318 self.type = self.getType()
cl349@5388 319
cl349@5388 320 self.db = controller.getDevDB(id)
cl349@5388 321
cl349@5388 322 def exportToDB(self, save=False):
cl349@5388 323 self.db.exportToDB(self, fields=self.__exports__, save=save)
cl349@5388 324
cl349@5388 325 def importFromDB(self):
cl349@5388 326 self.db.importFromDB(self, fields=self.__exports__)
mjw@4580 327
mjw@4580 328 def getDomain(self):
mjw@4580 329 return self.controller.getDomain()
mjw@4580 330
mjw@4580 331 def getDomainName(self):
mjw@4580 332 return self.controller.getDomainName()
mjw@4580 333
mjw@4580 334 def getDomainInfo(self):
mjw@4580 335 return self.controller.getDomainInfo()
mjw@4580 336
mjw@4580 337 def getController(self):
mjw@4580 338 return self.controller
mjw@4580 339
mjw@4580 340 def getType(self):
mjw@4580 341 return self.controller.getType()
mjw@2332 342
mjw@4580 343 def getId(self):
mjw@4580 344 return self.id
mjw@4580 345
mjw@4580 346 def getConfig(self):
mjw@4580 347 return self.config
mjw@4580 348
mjw@4580 349 def isDestroyed(self):
mjw@4580 350 return self.destroyed
mjw@4580 351
mjw@4580 352 #----------------------------------------------------------------------------
mjw@4580 353 # Subclass interface.
mjw@4580 354 # Define methods in subclass as needed.
mjw@4580 355 # Redefinitions must have the same arguments.
mjw@4580 356
mjw@4580 357 def init(self, recreate=False, reboot=False):
mjw@4580 358 """Initialization. Called on initial create (when reboot is False)
mjw@4580 359 and on reboot (when reboot is True). When xend is restarting is
mjw@4580 360 called with recreate True. Define in subclass if needed.
mjw@4668 361
mjw@4668 362 Device instance variables must be defined in the class constructor,
mjw@4668 363 but given null or default values. The real values should be initialised
mjw@4668 364 in this method. This allows devices to be re-initialised.
mjw@4668 365
mjw@4668 366 Since this can be called to re-initialise a device any state flags
mjw@4668 367 should be reset.
mjw@4580 368 """
mjw@4580 369 self.destroyed = False
mjw@2332 370
mjw@4580 371 def attach(self, recreate=False, change=False):
mjw@4580 372 """Attach the device to its front and back ends.
mjw@4580 373 Define in subclass if needed.
mjw@4580 374 """
mjw@4580 375 pass
mjw@4580 376
mjw@4580 377 def reboot(self):
mjw@4668 378 """Reconnect the device when the domain is rebooted.
mjw@4580 379 """
mjw@4580 380 self.init(reboot=True)
mjw@4580 381 self.attach()
mjw@2332 382
mjw@4580 383 def sxpr(self):
mjw@4580 384 """Get the s-expression for the deivice.
mjw@4580 385 Implement in a subclass if needed.
mjw@2332 386
mjw@4580 387 @return: sxpr
mjw@4580 388 """
mjw@4580 389 return self.getConfig()
mjw@4580 390
mjw@4580 391 def configure(self, config, change=False):
mjw@4580 392 """Reconfigure the device.
mjw@4580 393
mjw@4580 394 Implement in subclass.
mjw@2332 395 """
mjw@2332 396 raise NotImplementedError()
mjw@2332 397
mjw@4580 398 def refresh(self):
mjw@4580 399 """Refresh the device..
mjw@4580 400 Default no-op. Define in subclass if needed.
mjw@2520 401 """
mjw@4580 402 pass
mjw@2185 403
mjw@4580 404 def destroy(self, change=False, reboot=False):
mjw@4580 405 """Destroy the device.
mjw@4580 406 If change is True notify destruction (runtime change).
mjw@4580 407 If reboot is True the device is being destroyed for a reboot.
mjw@4580 408 Redefine in subclass if needed.
mjw@4668 409
mjw@4668 410 Called at domain shutdown and when a device is deleted from
mjw@4668 411 a running domain (with change True).
mjw@4580 412 """
mjw@4580 413 self.destroyed = True
mjw@4580 414 pass
mjw@1654 415
mjw@4580 416 #----------------------------------------------------------------------------