ia64/xen-unstable

view tools/python/xen/xend/server/controller.py @ 6689: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 b2f4823b6ff0 5aa6a2eff69f 4d899a738d59 8ca0f98ba8e2
line source
1 #============================================================================
2 # This library is free software; you can redistribute it and/or
3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
4 # License as published by the Free Software Foundation.
5 #
6 # This library is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 # Lesser General Public License for more details.
10 #
11 # You should have received a copy of the GNU Lesser General Public
12 # License along with this library; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 #============================================================================
15 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
16 #============================================================================
18 """General support for controllers, which handle devices
19 for a domain.
20 """
22 from xen.xend.XendError import XendError
23 from xen.xend.xenstore import DBVar
25 DEBUG = 0
27 class DevControllerTable:
28 """Table of device controller classes, indexed by type name.
29 """
31 def __init__(self):
32 self.controllerClasses = {}
34 def getDevControllerClass(self, type):
35 return self.controllerClasses.get(type)
37 def addDevControllerClass(self, cls):
38 self.controllerClasses[cls.getType()] = cls
40 def delDevControllerClass(self, type):
41 if type in self.controllerClasses:
42 del self.controllerClasses[type]
44 def createDevController(self, type, vm, recreate=False):
45 cls = self.getDevControllerClass(type)
46 if not cls:
47 raise XendError("unknown device type: " + str(type))
48 return cls.createDevController(vm, recreate=recreate)
50 def getDevControllerTable():
51 """Singleton constructor for the controller table.
52 """
53 global devControllerTable
54 try:
55 devControllerTable
56 except:
57 devControllerTable = DevControllerTable()
58 return devControllerTable
60 def addDevControllerClass(name, cls):
61 """Add a device controller class to the controller table.
62 """
63 cls.type = name
64 getDevControllerTable().addDevControllerClass(cls)
66 def createDevController(name, vm, recreate=False):
67 return getDevControllerTable().createDevController(name, vm, recreate=recreate)
69 class DevController:
70 """Abstract class for a device controller attached to a domain.
71 A device controller manages all the devices of a given type for a domain.
72 There is exactly one device controller for each device type for
73 a domain.
75 """
77 # State:
78 # controller/<type> : for controller
79 # device/<type>/<id> : for each device
81 def createDevController(cls, vm, recreate=False):
82 """Class method to create a dev controller.
83 """
84 ctrl = cls(vm, recreate=recreate)
85 ctrl.initController(recreate=recreate)
86 ctrl.exportToDB()
87 return ctrl
89 createDevController = classmethod(createDevController)
91 def getType(cls):
92 return cls.type
94 getType = classmethod(getType)
96 __exports__ = [
97 DBVar('type', 'str'),
98 DBVar('destroyed', 'bool'),
99 ]
101 # Set when registered.
102 type = None
104 def __init__(self, vm, recreate=False):
105 self.destroyed = False
106 self.vm = vm
107 self.db = self.getDB()
108 self.deviceId = 0
109 self.devices = {}
110 self.device_order = []
112 def getDB(self):
113 """Get the db node to use for a controller.
114 """
115 return self.vm.db.addChild("/controller/%s" % self.getType())
117 def getDevDB(self, id):
118 """Get the db node to use for a device.
119 """
120 return self.vm.db.addChild("/device/%s/%s" % (self.getType(), id))
122 def exportToDB(self, save=False):
123 self.db.exportToDB(self, fields=self.__exports__, save=save)
125 def importFromDB(self):
126 self.db.importFromDB(self, fields=self.__exports__)
128 def getDevControllerType(self):
129 return self.dctype
131 def getDomain(self):
132 return self.vm.getDomain()
134 def getDomainName(self):
135 return self.vm.getName()
137 def getDomainInfo(self):
138 return self.vm
140 #----------------------------------------------------------------------------
141 # Subclass interface.
142 # Subclasses should define the unimplemented methods..
143 # Redefinitions must have the same arguments.
145 def initController(self, recreate=False, reboot=False):
146 """Initialise the controller. Called when the controller is
147 first created, and again after the domain is rebooted (with reboot True).
148 If called with recreate True (and reboot False) the controller is being
149 recreated after a xend restart.
151 As this can be a re-init (after reboot) any controller state should
152 be reset. For example the destroyed flag.
153 """
154 self.destroyed = False
155 if reboot:
156 self.rebootDevices()
158 def newDevice(self, id, config, recreate=False):
159 """Create a device with the given config.
160 Must be defined in subclass.
161 Called with recreate True when the device is being recreated after a
162 xend restart.
164 @return device
165 """
166 raise NotImplementedError()
168 def createDevice(self, config, recreate=False, change=False):
169 """Create a device and attach to its front- and back-ends.
170 If recreate is true the device is being recreated after a xend restart.
171 If change is true the device is a change to an existing domain,
172 i.e. it is being added at runtime rather than when the domain is created.
173 """
174 dev = self.newDevice(self.nextDeviceId(), config, recreate=recreate)
175 if self.vm.recreate:
176 dev.importFromDB()
177 dev.init(recreate=recreate)
178 self.addDevice(dev)
179 if not recreate:
180 dev.exportToDB()
181 dev.attach(recreate=recreate, change=change)
182 dev.exportToDB()
184 return dev
186 def configureDevice(self, id, config, change=False):
187 """Reconfigure an existing device.
188 May be defined in subclass."""
189 dev = self.getDevice(id, error=True)
190 dev.configure(config, change=change)
192 def destroyDevice(self, id, change=False, reboot=False):
193 """Destroy a device.
194 May be defined in subclass.
196 If reboot is true the device is being destroyed for a domain reboot.
198 The device is not deleted, since it may be recreated later.
199 """
200 dev = self.getDevice(id, error=True)
201 dev.destroy(change=change, reboot=reboot)
202 return dev
204 def deleteDevice(self, id, change=True):
205 """Destroy a device and delete it.
206 Normally called to remove a device from a domain at runtime.
207 """
208 dev = self.destroyDevice(id, change=change)
209 self.removeDevice(dev)
211 def destroyController(self, reboot=False):
212 """Destroy all devices and clean up.
213 May be defined in subclass.
214 If reboot is true the controller is being destroyed for a domain reboot.
215 Called at domain shutdown.
216 """
217 self.destroyed = True
218 self.destroyDevices(reboot=reboot)
220 #----------------------------------------------------------------------------
222 def isDestroyed(self):
223 return self.destroyed
225 def getDevice(self, id, error=False):
226 dev = self.devices.get(int(id))
227 if error and not dev:
228 raise XendError("invalid device id: " + str(id))
229 return dev
231 def getDeviceIds(self):
232 return [ dev.getId() for dev in self.device_order ]
234 def getDevices(self):
235 return self.device_order
237 def getDeviceConfig(self, id):
238 return self.getDevice(id).getConfig()
240 def getDeviceConfigs(self):
241 return [ dev.getConfig() for dev in self.device_order ]
243 def getDeviceSxprs(self):
244 return [ dev.sxpr() for dev in self.device_order ]
246 def addDevice(self, dev):
247 self.devices[dev.getId()] = dev
248 self.device_order.append(dev)
249 return dev
251 def removeDevice(self, dev):
252 if dev.getId() in self.devices:
253 del self.devices[dev.getId()]
254 if dev in self.device_order:
255 self.device_order.remove(dev)
257 def rebootDevices(self):
258 for dev in self.getDevices():
259 dev.reboot()
261 def destroyDevices(self, reboot=False):
262 """Destroy all devices.
263 """
264 for dev in self.getDevices():
265 dev.destroy(reboot=reboot)
267 def getMaxDeviceId(self):
268 maxid = 0
269 for id in self.devices:
270 if id > maxid:
271 maxid = id
272 return maxid
274 def nextDeviceId(self):
275 id = self.deviceId
276 self.deviceId += 1
277 return id
279 def getDeviceCount(self):
280 return len(self.devices)
282 class Dev:
283 """Abstract class for a device attached to a device controller.
285 @ivar id: identifier
286 @type id: int
287 @ivar controller: device controller
288 @type controller: DevController
289 """
291 # ./status : need 2: actual and requested?
292 # down-down: initial.
293 # up-up: fully up.
294 # down-up: down requested, still up. Watch front and back, when both
295 # down go to down-down. But what if one (or both) is not connected?
296 # Still have front/back trees with status? Watch front/status, back/status?
297 # up-down: up requested, still down.
298 # Back-end watches ./status, front/status
299 # Front-end watches ./status, back/status
300 # i.e. each watches the other 2.
301 # Each is status/request status/actual?
302 #
303 # backend?
304 # frontend?
306 __exports__ = [
307 DBVar('id', ty='int'),
308 DBVar('type', ty='str'),
309 DBVar('config', ty='sxpr'),
310 DBVar('destroyed', ty='bool'),
311 ]
313 def __init__(self, controller, id, config, recreate=False):
314 self.controller = controller
315 self.id = id
316 self.config = config
317 self.destroyed = False
318 self.type = self.getType()
320 self.db = controller.getDevDB(id)
322 def exportToDB(self, save=False):
323 self.db.exportToDB(self, fields=self.__exports__, save=save)
325 def importFromDB(self):
326 self.db.importFromDB(self, fields=self.__exports__)
328 def getDomain(self):
329 return self.controller.getDomain()
331 def getDomainName(self):
332 return self.controller.getDomainName()
334 def getDomainInfo(self):
335 return self.controller.getDomainInfo()
337 def getController(self):
338 return self.controller
340 def getType(self):
341 return self.controller.getType()
343 def getId(self):
344 return self.id
346 def getConfig(self):
347 return self.config
349 def isDestroyed(self):
350 return self.destroyed
352 #----------------------------------------------------------------------------
353 # Subclass interface.
354 # Define methods in subclass as needed.
355 # Redefinitions must have the same arguments.
357 def init(self, recreate=False, reboot=False):
358 """Initialization. Called on initial create (when reboot is False)
359 and on reboot (when reboot is True). When xend is restarting is
360 called with recreate True. Define in subclass if needed.
362 Device instance variables must be defined in the class constructor,
363 but given null or default values. The real values should be initialised
364 in this method. This allows devices to be re-initialised.
366 Since this can be called to re-initialise a device any state flags
367 should be reset.
368 """
369 self.destroyed = False
371 def attach(self, recreate=False, change=False):
372 """Attach the device to its front and back ends.
373 Define in subclass if needed.
374 """
375 pass
377 def reboot(self):
378 """Reconnect the device when the domain is rebooted.
379 """
380 self.init(reboot=True)
381 self.attach()
383 def sxpr(self):
384 """Get the s-expression for the deivice.
385 Implement in a subclass if needed.
387 @return: sxpr
388 """
389 return self.getConfig()
391 def configure(self, config, change=False):
392 """Reconfigure the device.
394 Implement in subclass.
395 """
396 raise NotImplementedError()
398 def refresh(self):
399 """Refresh the device..
400 Default no-op. Define in subclass if needed.
401 """
402 pass
404 def destroy(self, change=False, reboot=False):
405 """Destroy the device.
406 If change is True notify destruction (runtime change).
407 If reboot is True the device is being destroyed for a reboot.
408 Redefine in subclass if needed.
410 Called at domain shutdown and when a device is deleted from
411 a running domain (with change True).
412 """
413 self.destroyed = True
414 pass
416 #----------------------------------------------------------------------------