xen-vtx-unstable
annotate tools/python/xen/xend/server/controller.py @ 4580:c69fbe48a357
bitkeeper revision 1.1327.2.1 (4266169fT9qqykPCJWENnvnqwf71kQ)
Refactor domain construction and device controllers to
remove use of twisted. Use threads to dispatch channel
input. Move device controllers into domains.
Signed-off-by: Mike Wray <mike.wray@hp.com>
Refactor domain construction and device controllers to
remove use of twisted. Use threads to dispatch channel
input. Move device controllers into domains.
Signed-off-by: Mike Wray <mike.wray@hp.com>
author | mjw@wray-m-3.hpl.hp.com |
---|---|
date | Wed Apr 20 08:45:19 2005 +0000 (2005-04-20) |
parents | 0a4b76b6b5a0 |
children | a838a908e38e |
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 |
mjw@4580 | 7 from messages import msgTypeName, printMsg, getMessageType |
mjw@1623 | 8 |
mjw@2397 | 9 DEBUG = 0 |
mjw@1677 | 10 |
mjw@4580 | 11 class CtrlMsgRcvr: |
mjw@4580 | 12 """Dispatcher class for 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@4580 | 86 print 'CtrlMsgRcvr>lostChannel>', |
mjw@4580 | 87 self.channel = None |
mjw@1623 | 88 |
mjw@1623 | 89 def registerChannel(self): |
mjw@1654 | 90 """Register interest in our major message types with the |
mjw@1719 | 91 channel to our domain. Once we have registered, the channel |
mjw@4580 | 92 will call requestReceived for our messages. |
mjw@1654 | 93 """ |
mjw@4580 | 94 if DEBUG: |
mjw@4580 | 95 print 'CtrlMsgRcvr>registerChannel>', self.channel, self.getMajorTypes() |
mjw@4580 | 96 if self.channel: |
mjw@2224 | 97 self.channel.registerDevice(self.getMajorTypes(), self) |
mjw@1623 | 98 |
mjw@1623 | 99 def deregisterChannel(self): |
mjw@1654 | 100 """Deregister interest in our major message types with the |
mjw@1719 | 101 channel to our domain. After this the channel won't call |
mjw@1719 | 102 us any more. |
mjw@1654 | 103 """ |
mjw@1623 | 104 if self.channel: |
mjw@1623 | 105 self.channel.deregisterDevice(self) |
mjw@1623 | 106 |
mjw@4580 | 107 class DevControllerType: |
mjw@4580 | 108 """Abstract class for device controller types. |
mjw@1623 | 109 """ |
mjw@1623 | 110 |
mjw@4580 | 111 def __init__(self, type): |
mjw@4580 | 112 self.type = type |
mjw@1623 | 113 |
mjw@4580 | 114 def getType(self): |
mjw@4580 | 115 """Get the device controller type name. |
mjw@1654 | 116 """ |
mjw@4580 | 117 return self.type |
mjw@2185 | 118 |
mjw@4580 | 119 def createDevController(self, vm, recreate=False): |
mjw@4580 | 120 """Create a device controller for a domain. |
mjw@4580 | 121 Must be implemented in subclass. |
mjw@1654 | 122 """ |
mjw@1623 | 123 raise NotImplementedError() |
mjw@1623 | 124 |
mjw@4580 | 125 class SimpleDevControllerType(DevControllerType): |
mjw@4580 | 126 """Device controller type that simply wraps a controller |
mjw@4580 | 127 class and uses its constructor to create instances. |
mjw@4580 | 128 """ |
mjw@4580 | 129 |
mjw@4580 | 130 def __init__(self, type, devControllerClass): |
mjw@4580 | 131 DevControllerType.__init__(self, type) |
mjw@4580 | 132 self.devControllerClass = devControllerClass |
mjw@2185 | 133 |
mjw@4580 | 134 def createDevController(self, vm, recreate=False): |
mjw@4580 | 135 """Create a device controller for a domain. |
mjw@4580 | 136 """ |
mjw@4580 | 137 ctrl = self.devControllerClass(self, vm, recreate=recreate) |
mjw@4580 | 138 ctrl.initController(recreate=recreate) |
mjw@4580 | 139 return ctrl |
mjw@1623 | 140 |
mjw@4580 | 141 class DevControllerTable: |
mjw@4580 | 142 """Table of device controller types, indexed by type name. |
mjw@2332 | 143 """ |
mjw@2332 | 144 |
mjw@2332 | 145 def __init__(self): |
mjw@4580 | 146 self.controllerTypes = {} |
mjw@4580 | 147 |
mjw@4580 | 148 def getDevControllerType(self, type): |
mjw@4580 | 149 return self.controllerTypes.get(type) |
mjw@4580 | 150 |
mjw@4580 | 151 def addDevControllerType(self, dctype): |
mjw@4580 | 152 self.controllerTypes[dctype.getType()] = dctype |
mjw@4580 | 153 return dctype |
mjw@2332 | 154 |
mjw@4580 | 155 def delDevControllerType(self, type): |
mjw@4580 | 156 if type in self.controllerTypes: |
mjw@4580 | 157 del self.controllerTypes[type] |
mjw@2332 | 158 |
mjw@4580 | 159 def createDevController(self, type, vm, recreate=False): |
mjw@4580 | 160 dctype = self.getDevControllerType(type) |
mjw@4580 | 161 if not dctype: |
mjw@4580 | 162 raise XendError("unknown device type: " + type) |
mjw@4580 | 163 return dctype.createDevController(vm, recreate=recreate) |
mjw@2332 | 164 |
mjw@4580 | 165 def getDevControllerTable(): |
mjw@4580 | 166 global devControllerTable |
mjw@4580 | 167 try: |
mjw@4580 | 168 devControllerTable |
mjw@4580 | 169 except: |
mjw@4580 | 170 devControllerTable = DevControllerTable() |
mjw@4580 | 171 return devControllerTable |
mjw@1623 | 172 |
mjw@4580 | 173 def addDevControllerType(dctype): |
mjw@4580 | 174 return getDevControllerTable().addDevControllerType(dctype) |
mjw@4580 | 175 |
mjw@4580 | 176 def addDevControllerClass(name, klass): |
mjw@4580 | 177 ty = SimpleDevControllerType(name, klass) |
mjw@4580 | 178 return addDevControllerType(ty) |
mjw@4580 | 179 |
mjw@4580 | 180 def createDevController(name, vm, recreate=False): |
mjw@4580 | 181 return getDevControllerTable().createDevController(name, vm, recreate=recreate) |
mjw@4580 | 182 |
mjw@4580 | 183 class DevController: |
mjw@4580 | 184 """Abstract class for a device controller attached to a domain. |
mjw@4580 | 185 A device controller manages all the devices of a given type for a domain. |
mjw@4580 | 186 There is exactly one device controller for each device type for |
mjw@4580 | 187 a domain. |
mjw@2332 | 188 |
mjw@4580 | 189 """ |
mjw@4580 | 190 |
mjw@4580 | 191 def __init__(self, dctype, vm, recreate=False): |
mjw@4580 | 192 self.dctype = dctype |
mjw@4580 | 193 self.destroyed = False |
mjw@4580 | 194 self.vm = vm |
mjw@4580 | 195 self.deviceId = 0 |
mjw@4580 | 196 self.devices = {} |
mjw@4580 | 197 self.device_order = [] |
mjw@2332 | 198 |
mjw@4580 | 199 def getType(self): |
mjw@4580 | 200 return self.dctype.getType() |
mjw@4580 | 201 |
mjw@4580 | 202 def getDevControllerType(self): |
mjw@4580 | 203 return self.dctype |
mjw@2332 | 204 |
mjw@4580 | 205 def getDomain(self): |
mjw@4580 | 206 return self.vm.getDomain() |
mjw@4580 | 207 |
mjw@4580 | 208 def getDomainName(self): |
mjw@4580 | 209 return self.vm.getName() |
mjw@2332 | 210 |
mjw@4580 | 211 def getChannel(self): |
mjw@4580 | 212 chan = self.vm.getChannel() |
mjw@4580 | 213 return chan |
mjw@4580 | 214 |
mjw@4580 | 215 def getDomainInfo(self): |
mjw@4580 | 216 return self.vm |
mjw@2332 | 217 |
mjw@4580 | 218 #---------------------------------------------------------------------------- |
mjw@4580 | 219 # Subclass interface. |
mjw@4580 | 220 # Subclasses should define the unimplemented methods.. |
mjw@4580 | 221 # Redefinitions must have the same arguments. |
mjw@2332 | 222 |
mjw@4580 | 223 def initController(self, recreate=False, reboot=False): |
mjw@4580 | 224 self.destroyed = False |
mjw@4580 | 225 if reboot: |
mjw@4580 | 226 self.rebootDevices() |
mjw@4580 | 227 |
mjw@4580 | 228 def newDevice(self, id, config, recreate=False): |
mjw@4580 | 229 """Create a device with the given config. |
mjw@4580 | 230 Must be defined in subclass. |
mjw@4580 | 231 |
mjw@4580 | 232 @return device |
mjw@2332 | 233 """ |
mjw@2332 | 234 raise NotImplementedError() |
mjw@2332 | 235 |
mjw@4580 | 236 def createDevice(self, config, recreate=False, change=False): |
mjw@4580 | 237 print 'DevController>createDevice>', 'config=', config, 'recreate=', recreate, 'change=', change |
mjw@4580 | 238 dev = self.newDevice(self.nextDeviceId(), config, recreate=recreate) |
mjw@4580 | 239 dev.init(recreate=recreate) |
mjw@4580 | 240 self.addDevice(dev) |
mjw@4580 | 241 idx = self.getDeviceIndex(dev) |
mjw@4580 | 242 recreate = self.vm.get_device_recreate(self.getType(), idx) |
mjw@4580 | 243 dev.attach(recreate=recreate, change=change) |
mjw@4580 | 244 print 'DevController>createDevice<' |
mjw@4580 | 245 |
mjw@4580 | 246 def configureDevice(self, id, config, change=False): |
mjw@4580 | 247 """Reconfigure an existing device. |
mjw@4580 | 248 May be defined in subclass.""" |
mjw@4580 | 249 dev = self.getDevice(id) |
mjw@4580 | 250 if not dev: |
mjw@4580 | 251 raise XendError("invalid device id: " + id) |
mjw@4580 | 252 dev.configure(config, change=change) |
mjw@2267 | 253 |
mjw@4580 | 254 def destroyDevice(self, id, change=False, reboot=False): |
mjw@4580 | 255 """Destroy a device. |
mjw@4580 | 256 May be defined in subclass.""" |
mjw@4580 | 257 dev = self.getDevice(id) |
mjw@4580 | 258 if not dev: |
mjw@4580 | 259 raise XendError("invalid device id: " + id) |
mjw@4580 | 260 dev.destroy(change=change, reboot=reboot) |
mjw@4580 | 261 return dev |
mjw@4580 | 262 |
mjw@4580 | 263 def deleteDevice(self, id, change=True): |
mjw@4580 | 264 dev = self.destroyDevice(id, change=change) |
mjw@4580 | 265 self.removeDevice(dev) |
mjw@4580 | 266 |
mjw@4580 | 267 def destroyController(self, reboot=False): |
mjw@4580 | 268 """Destroy all devices and clean up. |
mjw@4580 | 269 May be defined in subclass.""" |
mjw@4580 | 270 self.destroyed = True |
mjw@4580 | 271 self.destroyDevices(reboot=reboot) |
mjw@4580 | 272 |
mjw@4580 | 273 #---------------------------------------------------------------------------- |
mjw@4580 | 274 |
mjw@4580 | 275 def isDestroyed(self): |
mjw@4580 | 276 return self.destroyed |
mjw@4580 | 277 |
mjw@4580 | 278 def getDevice(self, id): |
mjw@4580 | 279 return self.devices.get(id) |
mjw@2267 | 280 |
mjw@4580 | 281 def getDeviceByIndex(self, idx): |
mjw@4580 | 282 if 0 <= idx < len(self.device_order): |
mjw@4580 | 283 return self.device_order[idx] |
mjw@4580 | 284 else: |
mjw@4580 | 285 return None |
mjw@4580 | 286 |
mjw@4580 | 287 def getDeviceIndex(self, dev): |
mjw@4580 | 288 return self.device_order.index(dev) |
mjw@4580 | 289 |
mjw@4580 | 290 def getDeviceIds(self): |
mjw@4580 | 291 return [ dev.getId() for dev in self.device_order ] |
mjw@4580 | 292 |
mjw@4580 | 293 def getDevices(self): |
mjw@4580 | 294 return self.device_order |
mjw@4580 | 295 |
mjw@4580 | 296 def getDeviceConfig(self, id): |
mjw@4580 | 297 return self.getDevice(id).getConfig() |
mjw@4580 | 298 |
mjw@4580 | 299 def getDeviceConfigs(self): |
mjw@4580 | 300 return [ dev.getConfig() for dev in self.device_order ] |
mjw@4580 | 301 |
mjw@4580 | 302 def getDeviceSxprs(self): |
mjw@4580 | 303 return [ dev.sxpr() for dev in self.device_order ] |
mjw@4580 | 304 |
mjw@4580 | 305 def addDevice(self, dev): |
mjw@4580 | 306 self.devices[dev.getId()] = dev |
mjw@4580 | 307 self.device_order.append(dev) |
mjw@4580 | 308 return dev |
mjw@4580 | 309 |
mjw@4580 | 310 def removeDevice(self, dev): |
mjw@4580 | 311 if dev.getId() in self.devices: |
mjw@4580 | 312 del self.devices[dev.getId()] |
mjw@4580 | 313 if dev in self.device_order: |
mjw@4580 | 314 self.device_order.remove(dev) |
mjw@4580 | 315 |
mjw@4580 | 316 def rebootDevices(self): |
mjw@4580 | 317 print 'DevController>rebootDevices>', self |
mjw@4580 | 318 for dev in self.getDevices(): |
mjw@4580 | 319 dev.reboot() |
mjw@4580 | 320 |
mjw@4580 | 321 def destroyDevices(self, reboot=False): |
mjw@4580 | 322 """Destroy all devices. |
mjw@4580 | 323 """ |
mjw@4580 | 324 for dev in self.getDevices(): |
mjw@4580 | 325 dev.destroy(reboot=reboot) |
mjw@2225 | 326 |
mjw@4580 | 327 def getMaxDeviceId(self): |
mjw@4580 | 328 maxid = 0 |
mjw@4580 | 329 for id in self.devices: |
mjw@4580 | 330 if id > maxid: |
mjw@4580 | 331 maxid = id |
mjw@4580 | 332 return maxid |
mjw@4580 | 333 |
mjw@4580 | 334 def nextDeviceId(self): |
mjw@4580 | 335 id = self.deviceId |
mjw@4580 | 336 self.deviceId += 1 |
mjw@4580 | 337 return id |
mjw@4580 | 338 |
mjw@4580 | 339 def getDeviceCount(self): |
mjw@4580 | 340 return len(self.devices) |
mjw@4580 | 341 |
mjw@4580 | 342 class Dev: |
mjw@4580 | 343 """Abstract class for a device attached to a device controller. |
mjw@2332 | 344 |
mjw@4580 | 345 @ivar id: identifier |
mjw@4580 | 346 @type id: int |
mjw@4580 | 347 @ivar controller: device controller |
mjw@4580 | 348 @type controller: DevController |
mjw@4580 | 349 """ |
mjw@4580 | 350 |
mjw@4580 | 351 def __init__(self, controller, id, config, recreate=False): |
mjw@4580 | 352 self.controller = controller |
mjw@4580 | 353 self.id = id |
mjw@4580 | 354 self.config = config |
mjw@4580 | 355 self.destroyed = False |
mjw@4580 | 356 |
mjw@4580 | 357 def getDomain(self): |
mjw@4580 | 358 return self.controller.getDomain() |
mjw@4580 | 359 |
mjw@4580 | 360 def getDomainName(self): |
mjw@4580 | 361 return self.controller.getDomainName() |
mjw@4580 | 362 |
mjw@4580 | 363 def getChannel(self): |
mjw@4580 | 364 return self.controller.getChannel() |
mjw@4580 | 365 |
mjw@4580 | 366 def getDomainInfo(self): |
mjw@4580 | 367 return self.controller.getDomainInfo() |
mjw@4580 | 368 |
mjw@4580 | 369 def getController(self): |
mjw@4580 | 370 return self.controller |
mjw@4580 | 371 |
mjw@4580 | 372 def getType(self): |
mjw@4580 | 373 return self.controller.getType() |
mjw@2332 | 374 |
mjw@4580 | 375 def getId(self): |
mjw@4580 | 376 return self.id |
mjw@4580 | 377 |
mjw@4580 | 378 def getIndex(self): |
mjw@4580 | 379 return self.controller.getDeviceIndex(self) |
mjw@4580 | 380 |
mjw@4580 | 381 def getConfig(self): |
mjw@4580 | 382 return self.config |
mjw@4580 | 383 |
mjw@4580 | 384 def isDestroyed(self): |
mjw@4580 | 385 return self.destroyed |
mjw@4580 | 386 |
mjw@4580 | 387 #---------------------------------------------------------------------------- |
mjw@4580 | 388 # Subclass interface. |
mjw@4580 | 389 # Define methods in subclass as needed. |
mjw@4580 | 390 # Redefinitions must have the same arguments. |
mjw@4580 | 391 |
mjw@4580 | 392 def init(self, recreate=False, reboot=False): |
mjw@4580 | 393 """Initialization. Called on initial create (when reboot is False) |
mjw@4580 | 394 and on reboot (when reboot is True). When xend is restarting is |
mjw@4580 | 395 called with recreate True. Define in subclass if needed. |
mjw@4580 | 396 """ |
mjw@4580 | 397 self.destroyed = False |
mjw@2332 | 398 |
mjw@4580 | 399 def attach(self, recreate=False, change=False): |
mjw@4580 | 400 """Attach the device to its front and back ends. |
mjw@4580 | 401 Define in subclass if needed. |
mjw@4580 | 402 """ |
mjw@4580 | 403 pass |
mjw@4580 | 404 |
mjw@4580 | 405 def reboot(self): |
mjw@4580 | 406 """Reconnect device when the domain is rebooted. |
mjw@4580 | 407 """ |
mjw@4580 | 408 print 'Dev>reboot>', self |
mjw@4580 | 409 self.init(reboot=True) |
mjw@4580 | 410 self.attach() |
mjw@2332 | 411 |
mjw@4580 | 412 def sxpr(self): |
mjw@4580 | 413 """Get the s-expression for the deivice. |
mjw@4580 | 414 Implement in a subclass if needed. |
mjw@2332 | 415 |
mjw@4580 | 416 @return: sxpr |
mjw@4580 | 417 """ |
mjw@4580 | 418 return self.getConfig() |
mjw@4580 | 419 |
mjw@4580 | 420 def configure(self, config, change=False): |
mjw@4580 | 421 """Reconfigure the device. |
mjw@4580 | 422 |
mjw@4580 | 423 Implement in subclass. |
mjw@2332 | 424 """ |
mjw@2332 | 425 raise NotImplementedError() |
mjw@2332 | 426 |
mjw@4580 | 427 def refresh(self): |
mjw@4580 | 428 """Refresh the device.. |
mjw@4580 | 429 Default no-op. Define in subclass if needed. |
mjw@2520 | 430 """ |
mjw@4580 | 431 pass |
mjw@2185 | 432 |
mjw@4580 | 433 def destroy(self, change=False, reboot=False): |
mjw@4580 | 434 """Destroy the device. |
mjw@4580 | 435 If change is True notify destruction (runtime change). |
mjw@4580 | 436 If reboot is True the device is being destroyed for a reboot. |
mjw@4580 | 437 Redefine in subclass if needed. |
mjw@4580 | 438 """ |
mjw@4580 | 439 self.destroyed = True |
mjw@4580 | 440 pass |
mjw@1654 | 441 |
mjw@4580 | 442 #---------------------------------------------------------------------------- |