xen-vtx-unstable

view tools/python/xen/xend/server/controller.py @ 6774:4d899a738d59

merge?
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 15:05:49 2005 +0000 (2005-09-13)
parents 7d0fb56b4a91 5aa6a2eff69f
children e7c7196fa329 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)
67 def isDevControllerClass(name):
68 """@return True if a device controller class has been registered with
69 the controller table under the given name."""
70 return name in getDevControllerTable().controllerClasses
73 def createDevController(name, vm, recreate=False):
74 return getDevControllerTable().createDevController(name, vm, recreate=recreate)
76 class DevController:
77 """Abstract class for a device controller attached to a domain.
78 A device controller manages all the devices of a given type for a domain.
79 There is exactly one device controller for each device type for
80 a domain.
82 """
84 # State:
85 # controller/<type> : for controller
86 # device/<type>/<id> : for each device
88 def createDevController(cls, vm, recreate=False):
89 """Class method to create a dev controller.
90 """
91 ctrl = cls(vm, recreate=recreate)
92 ctrl.initController(recreate=recreate)
93 ctrl.exportToDB()
94 return ctrl
96 createDevController = classmethod(createDevController)
98 def getType(cls):
99 return cls.type
101 getType = classmethod(getType)
103 __exports__ = [
104 DBVar('type', 'str'),
105 DBVar('destroyed', 'bool'),
106 ]
108 # Set when registered.
109 type = None
111 def __init__(self, vm, recreate=False):
112 self.destroyed = False
113 self.vm = vm
114 self.db = self.getDB()
115 self.deviceId = 0
116 self.devices = {}
117 self.device_order = []
119 def getDB(self):
120 """Get the db node to use for a controller.
121 """
122 return self.vm.db.addChild("/controller/%s" % self.getType())
124 def getDevDB(self, id):
125 """Get the db node to use for a device.
126 """
127 return self.vm.db.addChild("/device/%s/%s" % (self.getType(), id))
129 def exportToDB(self, save=False):
130 self.db.exportToDB(self, fields=self.__exports__, save=save)
132 def importFromDB(self):
133 self.db.importFromDB(self, fields=self.__exports__)
135 def getDevControllerType(self):
136 return self.dctype
138 def getDomain(self):
139 return self.vm.getDomain()
141 def getDomainName(self):
142 return self.vm.getName()
144 def getDomainInfo(self):
145 return self.vm
147 #----------------------------------------------------------------------------
148 # Subclass interface.
149 # Subclasses should define the unimplemented methods..
150 # Redefinitions must have the same arguments.
152 def initController(self, recreate=False, reboot=False):
153 """Initialise the controller. Called when the controller is
154 first created, and again after the domain is rebooted (with reboot True).
155 If called with recreate True (and reboot False) the controller is being
156 recreated after a xend restart.
158 As this can be a re-init (after reboot) any controller state should
159 be reset. For example the destroyed flag.
160 """
161 self.destroyed = False
162 if reboot:
163 self.rebootDevices()
165 def newDevice(self, id, config, recreate=False):
166 """Create a device with the given config.
167 Must be defined in subclass.
168 Called with recreate True when the device is being recreated after a
169 xend restart.
171 @return device
172 """
173 raise NotImplementedError()
175 def createDevice(self, config, recreate=False, change=False):
176 """Create a device and attach to its front- and back-ends.
177 If recreate is true the device is being recreated after a xend restart.
178 If change is true the device is a change to an existing domain,
179 i.e. it is being added at runtime rather than when the domain is created.
180 """
181 dev = self.newDevice(self.nextDeviceId(), config, recreate=recreate)
182 if self.vm.recreate:
183 dev.importFromDB()
184 dev.init(recreate=recreate)
185 self.addDevice(dev)
186 if not recreate:
187 dev.exportToDB()
188 dev.attach(recreate=recreate, change=change)
189 dev.exportToDB()
191 return dev
193 def configureDevice(self, id, config, change=False):
194 """Reconfigure an existing device.
195 May be defined in subclass."""
196 dev = self.getDevice(id, error=True)
197 dev.configure(config, change=change)
199 def destroyDevice(self, id, change=False, reboot=False):
200 """Destroy a device.
201 May be defined in subclass.
203 If reboot is true the device is being destroyed for a domain reboot.
205 The device is not deleted, since it may be recreated later.
206 """
207 dev = self.getDevice(id, error=True)
208 dev.destroy(change=change, reboot=reboot)
209 return dev
211 def deleteDevice(self, id, change=True):
212 """Destroy a device and delete it.
213 Normally called to remove a device from a domain at runtime.
214 """
215 dev = self.destroyDevice(id, change=change)
216 self.removeDevice(dev)
218 def destroyController(self, reboot=False):
219 """Destroy all devices and clean up.
220 May be defined in subclass.
221 If reboot is true the controller is being destroyed for a domain reboot.
222 Called at domain shutdown.
223 """
224 self.destroyed = True
225 self.destroyDevices(reboot=reboot)
227 #----------------------------------------------------------------------------
229 def isDestroyed(self):
230 return self.destroyed
232 def getDevice(self, id, error=False):
233 dev = self.devices.get(int(id))
234 if error and not dev:
235 raise XendError("invalid device id: " + str(id))
236 return dev
238 def getDeviceIds(self):
239 return [ dev.getId() for dev in self.device_order ]
241 def getDevices(self):
242 return self.device_order
244 def getDeviceConfig(self, id):
245 return self.getDevice(id).getConfig()
247 def getDeviceConfigs(self):
248 return [ dev.getConfig() for dev in self.device_order ]
250 def getDeviceSxprs(self):
251 return [ dev.sxpr() for dev in self.device_order ]
253 def addDevice(self, dev):
254 self.devices[dev.getId()] = dev
255 self.device_order.append(dev)
256 return dev
258 def removeDevice(self, dev):
259 if dev.getId() in self.devices:
260 del self.devices[dev.getId()]
261 if dev in self.device_order:
262 self.device_order.remove(dev)
264 def rebootDevices(self):
265 for dev in self.getDevices():
266 dev.reboot()
268 def destroyDevices(self, reboot=False):
269 """Destroy all devices.
270 """
271 for dev in self.getDevices():
272 dev.destroy(reboot=reboot)
274 def getMaxDeviceId(self):
275 maxid = 0
276 for id in self.devices:
277 if id > maxid:
278 maxid = id
279 return maxid
281 def nextDeviceId(self):
282 id = self.deviceId
283 self.deviceId += 1
284 return id
286 def getDeviceCount(self):
287 return len(self.devices)
289 class Dev:
290 """Abstract class for a device attached to a device controller.
292 @ivar id: identifier
293 @type id: int
294 @ivar controller: device controller
295 @type controller: DevController
296 """
298 # ./status : need 2: actual and requested?
299 # down-down: initial.
300 # up-up: fully up.
301 # down-up: down requested, still up. Watch front and back, when both
302 # down go to down-down. But what if one (or both) is not connected?
303 # Still have front/back trees with status? Watch front/status, back/status?
304 # up-down: up requested, still down.
305 # Back-end watches ./status, front/status
306 # Front-end watches ./status, back/status
307 # i.e. each watches the other 2.
308 # Each is status/request status/actual?
309 #
310 # backend?
311 # frontend?
313 __exports__ = [
314 DBVar('id', ty='int'),
315 DBVar('type', ty='str'),
316 DBVar('config', ty='sxpr'),
317 DBVar('destroyed', ty='bool'),
318 ]
320 def __init__(self, controller, id, config, recreate=False):
321 self.controller = controller
322 self.id = id
323 self.config = config
324 self.destroyed = False
325 self.type = self.getType()
327 self.db = controller.getDevDB(id)
329 def exportToDB(self, save=False):
330 self.db.exportToDB(self, fields=self.__exports__, save=save)
332 def importFromDB(self):
333 self.db.importFromDB(self, fields=self.__exports__)
335 def getDomain(self):
336 return self.controller.getDomain()
338 def getDomainName(self):
339 return self.controller.getDomainName()
341 def getDomainInfo(self):
342 return self.controller.getDomainInfo()
344 def getController(self):
345 return self.controller
347 def getType(self):
348 return self.controller.getType()
350 def getId(self):
351 return self.id
353 def getConfig(self):
354 return self.config
356 def isDestroyed(self):
357 return self.destroyed
359 #----------------------------------------------------------------------------
360 # Subclass interface.
361 # Define methods in subclass as needed.
362 # Redefinitions must have the same arguments.
364 def init(self, recreate=False, reboot=False):
365 """Initialization. Called on initial create (when reboot is False)
366 and on reboot (when reboot is True). When xend is restarting is
367 called with recreate True. Define in subclass if needed.
369 Device instance variables must be defined in the class constructor,
370 but given null or default values. The real values should be initialised
371 in this method. This allows devices to be re-initialised.
373 Since this can be called to re-initialise a device any state flags
374 should be reset.
375 """
376 self.destroyed = False
378 def attach(self, recreate=False, change=False):
379 """Attach the device to its front and back ends.
380 Define in subclass if needed.
381 """
382 pass
384 def reboot(self):
385 """Reconnect the device when the domain is rebooted.
386 """
387 self.init(reboot=True)
388 self.attach()
390 def sxpr(self):
391 """Get the s-expression for the deivice.
392 Implement in a subclass if needed.
394 @return: sxpr
395 """
396 return self.getConfig()
398 def configure(self, config, change=False):
399 """Reconfigure the device.
401 Implement in subclass.
402 """
403 raise NotImplementedError()
405 def refresh(self):
406 """Refresh the device..
407 Default no-op. Define in subclass if needed.
408 """
409 pass
411 def destroy(self, change=False, reboot=False):
412 """Destroy the device.
413 If change is True notify destruction (runtime change).
414 If reboot is True the device is being destroyed for a reboot.
415 Redefine in subclass if needed.
417 Called at domain shutdown and when a device is deleted from
418 a running domain (with change True).
419 """
420 self.destroyed = True
421 pass
423 #----------------------------------------------------------------------------