xen-vtx-unstable

annotate tools/python/xen/xend/server/controller.py @ 5338:c3febeed5ba7

bitkeeper revision 1.1662.1.5 (42a46588UuohS0CHY1F3XZtrchaAwA)

Many files:
Remove device indexing.
Signed-off-by: Mike Wray <mike.wray@hp.com>
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Mon Jun 06 15:02:32 2005 +0000 (2005-06-06)
parents 7d8015b52943
children cf712d7c809c
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@4580 6 from xen.xend.XendError import XendError
cl349@5336 7 from xen.xend.server.messages import msgTypeName, printMsg, getMessageType
mjw@1623 8
mjw@2397 9 DEBUG = 0
mjw@1677 10
mjw@4580 11 class CtrlMsgRcvr:
mjw@4668 12 """Utility class to dispatch messages on a control channel.
mjw@4580 13 Once I{registerChannel} has been called, our message types are registered
mjw@4580 14 with the channel. The channel will call I{requestReceived}
mjw@4580 15 when a request arrives if it has one of our message types.
mjw@4580 16
mjw@4580 17 @ivar channel: channel to a domain
mjw@4580 18 @type channel: Channel
mjw@4580 19 @ivar majorTypes: major message types we are interested in
mjw@4580 20 @type majorTypes: {int:{int:method}}
mjw@4580 21
mjw@1677 22 """
mjw@1677 23
mjw@4580 24 def __init__(self, channel):
mjw@4580 25 self.majorTypes = {}
mjw@4580 26 self.channel = channel
mjw@1677 27
mjw@4580 28 def getHandler(self, type, subtype):
mjw@2224 29 """Get the method for a type and subtype.
mjw@2224 30
mjw@2224 31 @param type: major message type
mjw@2224 32 @param subtype: minor message type
mjw@2224 33 @return: method or None
mjw@2224 34 """
mjw@2224 35 method = None
mjw@2224 36 subtypes = self.majorTypes.get(type)
mjw@2224 37 if subtypes:
mjw@2224 38 method = subtypes.get(subtype)
mjw@2224 39 return method
mjw@2224 40
mjw@4580 41 def addHandler(self, type, subtype, method):
mjw@2224 42 """Add a method to handle a message type and subtype.
mjw@2224 43
mjw@2224 44 @param type: major message type
mjw@2224 45 @param subtype: minor message type
mjw@2224 46 @param method: method
mjw@2224 47 """
mjw@2224 48 subtypes = self.majorTypes.get(type)
mjw@2224 49 if not subtypes:
mjw@2224 50 subtypes = {}
mjw@2224 51 self.majorTypes[type] = subtypes
mjw@2224 52 subtypes[subtype] = method
mjw@2224 53
mjw@2224 54 def getMajorTypes(self):
mjw@2224 55 """Get the list of major message types handled.
mjw@2224 56 """
mjw@2224 57 return self.majorTypes.keys()
mjw@2224 58
mjw@1623 59 def requestReceived(self, msg, type, subtype):
mjw@1719 60 """Dispatch a request message to handlers.
mjw@1719 61 Called by the channel for requests with one of our types.
mjw@1654 62
mjw@1719 63 @param msg: message
mjw@1719 64 @type msg: xu message
mjw@1719 65 @param type: major message type
mjw@1719 66 @type type: int
mjw@1719 67 @param subtype: minor message type
mjw@1719 68 @type subtype: int
mjw@1654 69 """
mjw@1677 70 if DEBUG:
mjw@1719 71 print 'requestReceived>',
mjw@4580 72 printMsg(msg, all=True)
mjw@2265 73 responded = 0
mjw@4580 74 method = self.getHandler(type, subtype)
mjw@1623 75 if method:
mjw@4580 76 responded = method(msg)
mjw@1677 77 elif DEBUG:
mjw@1623 78 print ('requestReceived> No handler: Message type %s %d:%d'
mjw@1623 79 % (msgTypeName(type, subtype), type, subtype)), self
mjw@2265 80 return responded
mjw@1623 81
mjw@1677 82
mjw@1623 83 def lostChannel(self):
mjw@1654 84 """Called when the channel to the domain is lost.
mjw@1654 85 """
mjw@4617 86 if DEBUG:
mjw@4617 87 print 'CtrlMsgRcvr>lostChannel>',
mjw@4580 88 self.channel = None
mjw@1623 89
mjw@1623 90 def registerChannel(self):
mjw@1654 91 """Register interest in our major message types with the
mjw@1719 92 channel to our domain. Once we have registered, the channel
mjw@4580 93 will call requestReceived for our messages.
mjw@1654 94 """
mjw@4580 95 if DEBUG:
mjw@4580 96 print 'CtrlMsgRcvr>registerChannel>', self.channel, self.getMajorTypes()
mjw@4580 97 if self.channel:
mjw@2224 98 self.channel.registerDevice(self.getMajorTypes(), self)
mjw@1623 99
mjw@1623 100 def deregisterChannel(self):
mjw@1654 101 """Deregister interest in our major message types with the
mjw@1719 102 channel to our domain. After this the channel won't call
mjw@1719 103 us any more.
mjw@1654 104 """
mjw@1623 105 if self.channel:
mjw@1623 106 self.channel.deregisterDevice(self)
mjw@1623 107
mjw@4580 108 class DevControllerTable:
mjw@4668 109 """Table of device controller classes, indexed by type name.
mjw@2332 110 """
mjw@2332 111
mjw@2332 112 def __init__(self):
mjw@4668 113 self.controllerClasses = {}
mjw@4580 114
mjw@4668 115 def getDevControllerClass(self, type):
mjw@4668 116 return self.controllerClasses.get(type)
mjw@4580 117
mjw@4668 118 def addDevControllerClass(self, klass):
mjw@4668 119 self.controllerClasses[klass.getType()] = klass
mjw@2332 120
mjw@4668 121 def delDevControllerClass(self, type):
mjw@4668 122 if type in self.controllerClasses:
mjw@4668 123 del self.controllerClasses[type]
mjw@2332 124
mjw@4580 125 def createDevController(self, type, vm, recreate=False):
mjw@4668 126 klass = self.getDevControllerClass(type)
mjw@4668 127 if not klass:
mjw@4580 128 raise XendError("unknown device type: " + type)
mjw@4668 129 return klass.createDevController(vm, recreate=recreate)
mjw@2332 130
mjw@4580 131 def getDevControllerTable():
mjw@4668 132 """Singleton constructor for the controller table.
mjw@4668 133 """
mjw@4580 134 global devControllerTable
mjw@4580 135 try:
mjw@4580 136 devControllerTable
mjw@4580 137 except:
mjw@4580 138 devControllerTable = DevControllerTable()
mjw@4580 139 return devControllerTable
mjw@1623 140
mjw@4580 141 def addDevControllerClass(name, klass):
mjw@4668 142 """Add a device controller class to the controller table.
mjw@4668 143 """
mjw@4668 144 klass.name = name
mjw@4668 145 getDevControllerTable().addDevControllerClass(klass)
mjw@4580 146
mjw@4580 147 def createDevController(name, vm, recreate=False):
mjw@4580 148 return getDevControllerTable().createDevController(name, vm, recreate=recreate)
mjw@4580 149
mjw@4580 150 class DevController:
mjw@4580 151 """Abstract class for a device controller attached to a domain.
mjw@4580 152 A device controller manages all the devices of a given type for a domain.
mjw@4580 153 There is exactly one device controller for each device type for
mjw@4580 154 a domain.
mjw@2332 155
mjw@4580 156 """
mjw@4580 157
mjw@4668 158 name = None
mjw@4668 159
mjw@4668 160 def createDevController(klass, vm, recreate=False):
mjw@4668 161 """Class method to create a dev controller.
mjw@4668 162 """
mjw@4668 163 ctrl = klass(vm, recreate=recreate)
mjw@4668 164 ctrl.initController(recreate=recreate)
mjw@4668 165 return ctrl
mjw@4668 166
mjw@4668 167 createDevController = classmethod(createDevController)
mjw@4668 168
mjw@4668 169 def getType(klass):
mjw@4668 170 return klass.name
mjw@4668 171
mjw@4668 172 getType = classmethod(getType)
mjw@4668 173
mjw@4668 174 def __init__(self, vm, recreate=False):
mjw@4580 175 self.destroyed = False
mjw@4580 176 self.vm = vm
mjw@4580 177 self.deviceId = 0
mjw@4580 178 self.devices = {}
mjw@4580 179 self.device_order = []
mjw@2332 180
mjw@4580 181 def getDevControllerType(self):
mjw@4580 182 return self.dctype
mjw@2332 183
mjw@4580 184 def getDomain(self):
mjw@4580 185 return self.vm.getDomain()
mjw@4580 186
mjw@4580 187 def getDomainName(self):
mjw@4580 188 return self.vm.getName()
mjw@2332 189
mjw@4580 190 def getChannel(self):
mjw@4580 191 chan = self.vm.getChannel()
mjw@4580 192 return chan
mjw@4580 193
mjw@4580 194 def getDomainInfo(self):
mjw@4580 195 return self.vm
mjw@2332 196
mjw@4580 197 #----------------------------------------------------------------------------
mjw@4580 198 # Subclass interface.
mjw@4580 199 # Subclasses should define the unimplemented methods..
mjw@4580 200 # Redefinitions must have the same arguments.
mjw@2332 201
mjw@4580 202 def initController(self, recreate=False, reboot=False):
mjw@4668 203 """Initialise the controller. Called when the controller is
mjw@4668 204 first created, and again after the domain is rebooted (with reboot True).
mjw@4668 205 If called with recreate True (and reboot False) the controller is being
mjw@4668 206 recreated after a xend restart.
mjw@4668 207
mjw@4668 208 As this can be a re-init (after reboot) any controller state should
mjw@4668 209 be reset. For example the destroyed flag.
mjw@4668 210 """
mjw@4580 211 self.destroyed = False
mjw@4580 212 if reboot:
mjw@4580 213 self.rebootDevices()
mjw@4580 214
mjw@4580 215 def newDevice(self, id, config, recreate=False):
mjw@4580 216 """Create a device with the given config.
mjw@4580 217 Must be defined in subclass.
mjw@4668 218 Called with recreate True when the device is being recreated after a
mjw@4668 219 xend restart.
mjw@4580 220
mjw@4580 221 @return device
mjw@2332 222 """
mjw@2332 223 raise NotImplementedError()
mjw@2332 224
mjw@4580 225 def createDevice(self, config, recreate=False, change=False):
mjw@4668 226 """Create a device and attach to its front- and back-ends.
mjw@4668 227 If recreate is true the device is being recreated after a xend restart.
mjw@4668 228 If change is true the device is a change to an existing domain,
mjw@4668 229 i.e. it is being added at runtime rather than when the domain is created.
mjw@4668 230 """
cl349@5338 231 # skanky hack: we use the device ids to maybe find the savedinfo
cl349@5338 232 # of the device...
cl349@5338 233 id = self.nextDeviceId()
cl349@5338 234 if recreate:
cl349@5338 235 recreate = self.vm.get_device_savedinfo(self.getType(), id)
cl349@5338 236 dev = self.newDevice(id, config, recreate=recreate)
mjw@4580 237 dev.init(recreate=recreate)
mjw@4580 238 self.addDevice(dev)
mjw@4580 239 dev.attach(recreate=recreate, change=change)
mjw@4580 240
mjw@4580 241 def configureDevice(self, id, config, change=False):
mjw@4580 242 """Reconfigure an existing device.
mjw@4580 243 May be defined in subclass."""
cl349@5338 244 dev = self.getDevice(id, error=True)
mjw@4580 245 dev.configure(config, change=change)
mjw@2267 246
mjw@4580 247 def destroyDevice(self, id, change=False, reboot=False):
mjw@4580 248 """Destroy a device.
mjw@4668 249 May be defined in subclass.
mjw@4668 250
mjw@4668 251 If reboot is true the device is being destroyed for a domain reboot.
mjw@4668 252
mjw@4668 253 The device is not deleted, since it may be recreated later.
mjw@4668 254 """
cl349@5338 255 dev = self.getDevice(id, error=True)
mjw@4580 256 dev.destroy(change=change, reboot=reboot)
mjw@4580 257 return dev
mjw@4580 258
mjw@4580 259 def deleteDevice(self, id, change=True):
mjw@4668 260 """Destroy a device and delete it.
mjw@4668 261 Normally called to remove a device from a domain at runtime.
mjw@4668 262 """
mjw@4580 263 dev = self.destroyDevice(id, change=change)
mjw@4580 264 self.removeDevice(dev)
mjw@4580 265
mjw@4580 266 def destroyController(self, reboot=False):
mjw@4580 267 """Destroy all devices and clean up.
mjw@4668 268 May be defined in subclass.
mjw@4668 269 If reboot is true the controller is being destroyed for a domain reboot.
mjw@4668 270 Called at domain shutdown.
mjw@4668 271 """
mjw@4580 272 self.destroyed = True
mjw@4580 273 self.destroyDevices(reboot=reboot)
mjw@4580 274
mjw@4580 275 #----------------------------------------------------------------------------
mjw@4580 276
mjw@4580 277 def isDestroyed(self):
mjw@4580 278 return self.destroyed
mjw@4580 279
cl349@5338 280 def getDevice(self, id, error=False):
cl349@5338 281 dev = self.devices.get(id)
cl349@5338 282 if error and not dev:
cl349@5338 283 raise XendError("invalid device id: " + id)
cl349@5338 284 return dev
mjw@4580 285
mjw@4580 286 def getDeviceIds(self):
mjw@4580 287 return [ dev.getId() for dev in self.device_order ]
mjw@4580 288
mjw@4580 289 def getDevices(self):
mjw@4580 290 return self.device_order
mjw@4580 291
mjw@4580 292 def getDeviceConfig(self, id):
mjw@4580 293 return self.getDevice(id).getConfig()
mjw@4580 294
mjw@4580 295 def getDeviceConfigs(self):
mjw@4580 296 return [ dev.getConfig() for dev in self.device_order ]
mjw@4580 297
mjw@4580 298 def getDeviceSxprs(self):
mjw@4580 299 return [ dev.sxpr() for dev in self.device_order ]
mjw@4580 300
mjw@4580 301 def addDevice(self, dev):
mjw@4580 302 self.devices[dev.getId()] = dev
mjw@4580 303 self.device_order.append(dev)
mjw@4580 304 return dev
mjw@4580 305
mjw@4580 306 def removeDevice(self, dev):
mjw@4580 307 if dev.getId() in self.devices:
mjw@4580 308 del self.devices[dev.getId()]
mjw@4580 309 if dev in self.device_order:
mjw@4580 310 self.device_order.remove(dev)
mjw@4580 311
mjw@4580 312 def rebootDevices(self):
mjw@4580 313 for dev in self.getDevices():
mjw@4580 314 dev.reboot()
mjw@4580 315
mjw@4580 316 def destroyDevices(self, reboot=False):
mjw@4580 317 """Destroy all devices.
mjw@4580 318 """
mjw@4580 319 for dev in self.getDevices():
mjw@4580 320 dev.destroy(reboot=reboot)
mjw@2225 321
mjw@4580 322 def getMaxDeviceId(self):
mjw@4580 323 maxid = 0
mjw@4580 324 for id in self.devices:
mjw@4580 325 if id > maxid:
mjw@4580 326 maxid = id
mjw@4580 327 return maxid
mjw@4580 328
mjw@4580 329 def nextDeviceId(self):
mjw@4580 330 id = self.deviceId
mjw@4580 331 self.deviceId += 1
mjw@4580 332 return id
mjw@4580 333
mjw@4580 334 def getDeviceCount(self):
mjw@4580 335 return len(self.devices)
mjw@4580 336
mjw@4580 337 class Dev:
mjw@4580 338 """Abstract class for a device attached to a device controller.
mjw@2332 339
mjw@4580 340 @ivar id: identifier
mjw@4580 341 @type id: int
mjw@4580 342 @ivar controller: device controller
mjw@4580 343 @type controller: DevController
mjw@4580 344 """
mjw@4580 345
mjw@4580 346 def __init__(self, controller, id, config, recreate=False):
mjw@4580 347 self.controller = controller
mjw@4580 348 self.id = id
mjw@4580 349 self.config = config
mjw@4580 350 self.destroyed = False
mjw@4580 351
mjw@4580 352 def getDomain(self):
mjw@4580 353 return self.controller.getDomain()
mjw@4580 354
mjw@4580 355 def getDomainName(self):
mjw@4580 356 return self.controller.getDomainName()
mjw@4580 357
mjw@4580 358 def getChannel(self):
mjw@4580 359 return self.controller.getChannel()
mjw@4580 360
mjw@4580 361 def getDomainInfo(self):
mjw@4580 362 return self.controller.getDomainInfo()
mjw@4580 363
mjw@4580 364 def getController(self):
mjw@4580 365 return self.controller
mjw@4580 366
mjw@4580 367 def getType(self):
mjw@4580 368 return self.controller.getType()
mjw@2332 369
mjw@4580 370 def getId(self):
mjw@4580 371 return self.id
mjw@4580 372
mjw@4580 373 def getConfig(self):
mjw@4580 374 return self.config
mjw@4580 375
mjw@4580 376 def isDestroyed(self):
mjw@4580 377 return self.destroyed
mjw@4580 378
mjw@4580 379 #----------------------------------------------------------------------------
mjw@4580 380 # Subclass interface.
mjw@4580 381 # Define methods in subclass as needed.
mjw@4580 382 # Redefinitions must have the same arguments.
mjw@4580 383
mjw@4580 384 def init(self, recreate=False, reboot=False):
mjw@4580 385 """Initialization. Called on initial create (when reboot is False)
mjw@4580 386 and on reboot (when reboot is True). When xend is restarting is
mjw@4580 387 called with recreate True. Define in subclass if needed.
mjw@4668 388
mjw@4668 389 Device instance variables must be defined in the class constructor,
mjw@4668 390 but given null or default values. The real values should be initialised
mjw@4668 391 in this method. This allows devices to be re-initialised.
mjw@4668 392
mjw@4668 393 Since this can be called to re-initialise a device any state flags
mjw@4668 394 should be reset.
mjw@4580 395 """
mjw@4580 396 self.destroyed = False
mjw@2332 397
mjw@4580 398 def attach(self, recreate=False, change=False):
mjw@4580 399 """Attach the device to its front and back ends.
mjw@4580 400 Define in subclass if needed.
mjw@4580 401 """
mjw@4580 402 pass
mjw@4580 403
mjw@4580 404 def reboot(self):
mjw@4668 405 """Reconnect the device when the domain is rebooted.
mjw@4580 406 """
mjw@4580 407 self.init(reboot=True)
mjw@4580 408 self.attach()
mjw@2332 409
mjw@4580 410 def sxpr(self):
mjw@4580 411 """Get the s-expression for the deivice.
mjw@4580 412 Implement in a subclass if needed.
mjw@2332 413
mjw@4580 414 @return: sxpr
mjw@4580 415 """
mjw@4580 416 return self.getConfig()
mjw@4580 417
mjw@4580 418 def configure(self, config, change=False):
mjw@4580 419 """Reconfigure the device.
mjw@4580 420
mjw@4580 421 Implement in subclass.
mjw@2332 422 """
mjw@2332 423 raise NotImplementedError()
mjw@2332 424
mjw@4580 425 def refresh(self):
mjw@4580 426 """Refresh the device..
mjw@4580 427 Default no-op. Define in subclass if needed.
mjw@2520 428 """
mjw@4580 429 pass
mjw@2185 430
mjw@4580 431 def destroy(self, change=False, reboot=False):
mjw@4580 432 """Destroy the device.
mjw@4580 433 If change is True notify destruction (runtime change).
mjw@4580 434 If reboot is True the device is being destroyed for a reboot.
mjw@4580 435 Redefine in subclass if needed.
mjw@4668 436
mjw@4668 437 Called at domain shutdown and when a device is deleted from
mjw@4668 438 a running domain (with change True).
mjw@4580 439 """
mjw@4580 440 self.destroyed = True
mjw@4580 441 pass
mjw@1654 442
mjw@4580 443 #----------------------------------------------------------------------------