ia64/xen-unstable

view tools/python/xen/xend/server/controller.py @ 5346:cf712d7c809c

bitkeeper revision 1.1662.1.9 (42a485d0ePlJLabsERQDyPFBJ1tF9Q)

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