ia64/xen-unstable

view tools/python/xen/xend/server/DevController.py @ 7357:3dd931842e71

Improve error message.
author emellor@ewan
date Wed Oct 12 12:54:43 2005 +0100 (2005-10-12)
parents 4e0c94871be2
children 18eb059ae471
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 # Copyright (C) 2005 XenSource Ltd
17 #============================================================================
20 from xen.xend import sxp
21 from xen.xend.XendError import VmError
22 from xen.xend.XendLogging import log
23 from xen.xend.xenstore.xstransact import xstransact
26 class DevController:
27 """Abstract base class for a device controller. Device controllers create
28 appropriate entries in the store to trigger the creation, reconfiguration,
29 and destruction of devices in guest domains. Each subclass of
30 DevController is responsible for a particular device-class, and
31 understands the details of configuration specific to that device-class.
33 DevController itself provides the functionality common to all device
34 creation tasks, as well as providing an interface to XendDomainInfo for
35 triggering those events themselves.
36 """
38 # Set when registered.
39 deviceClass = None
42 ## public:
44 def __init__(self, vm):
45 self.vm = vm
48 def createDevice(self, config):
49 """Trigger the creation of a device with the given configuration.
51 @return The ID for the newly created device.
52 """
53 (devid, back, front) = self.getDeviceDetails(config)
55 self.writeDetails(config, devid, back, front)
57 return devid
60 def reconfigureDevice(self, devid, config):
61 """Reconfigure the specified device.
63 The implementation here just raises VmError. This may be overridden
64 by those subclasses that can reconfigure their devices.
65 """
66 raise VmError('%s devices may not be reconfigured' % self.deviceClass)
69 def destroyDevice(self, devid):
70 """Destroy the specified device.
72 The implementation here simply deletes the appropriate paths from
73 the store. This may be overridden by subclasses who need to perform
74 other tasks on destruction.
75 """
77 frontpath = self.frontendPath(devid)
78 backpath = xstransact.Read(frontpath, "backend")
80 xstransact.Remove(frontpath)
82 if backpath:
83 xstransact.Remove(backpath)
84 else:
85 raise VmError("Device %s not connected" % devid)
88 def configurations(self):
89 return map(self.configuration, self.deviceIDs())
92 def configuration(self, devid):
93 """@return an s-expression giving the current configuration of the
94 specified device. This would be suitable for giving to {@link
95 #createDevice} in order to recreate that device."""
97 backdomid = int(xstransact.Read(self.frontendPath(devid),
98 "backend-id"))
100 return [self.deviceClass, ['backend', backdomid]]
103 def sxprs(self):
104 """@return an s-expression describing all the devices of this
105 controller's device-class.
106 """
107 return xstransact.ListRecursive(self.frontendRoot())
110 def sxpr(self, devid):
111 """@return an s-expression describing the specified device.
112 """
113 return [self.deviceClass, ['dom', self.vm.getDomid(),
114 'id', devid]]
117 ## protected:
119 def getDeviceDetails(self, config):
120 """Compute the details for creation of a device corresponding to the
121 given configuration. These details consist of a tuple of (devID,
122 backDetails, frontDetails), where devID is the ID for the new device,
123 and backDetails and frontDetails are the device configuration
124 specifics for the backend and frontend respectively.
126 backDetails and frontDetails should be dictionaries, the keys and
127 values of which will be used as paths in the store. There is no need
128 for these dictionaries to include the references from frontend to
129 backend, nor vice versa, as these will be handled by DevController.
131 Abstract; must be implemented by every subclass.
133 @return (devID, backDetails, frontDetails), as specified above.
134 """
136 raise NotImplementedError()
139 def getDomid(self):
140 """Stub to {@link XendDomainInfo.getDomid}, for use by our
141 subclasses.
142 """
143 return self.vm.getDomid()
146 def allocateDeviceID(self):
147 """Allocate a device ID, allocating them consecutively on a
148 per-domain, per-device-class basis, and using the store to record the
149 next available ID.
151 This method is available to our subclasses, though it is not
152 compulsory to use it; subclasses may prefer to allocate IDs based upon
153 the device configuration instead.
154 """
155 path = self.frontendMiscPath()
156 while True:
157 t = xstransact(path)
158 try:
159 result = t.read("nextDeviceID")
160 if result:
161 result = int(result)
162 else:
163 result = 1
164 t.write("nextDeviceID", str(result + 1))
165 if t.commit():
166 return result
167 except:
168 t.abort()
169 raise
172 def readBackend(self, devid, *args):
173 frontpath = self.frontendPath(devid)
174 backpath = xstransact.Read(frontpath, "backend")
175 return xstransact.Read(backpath, *args)
178 def deviceIDs(self):
179 """@return The IDs of each of the devices currently configured for
180 this instance's deviceClass.
181 """
182 return map(int, xstransact.List(self.frontendRoot()))
185 ## private:
187 def writeDetails(self, config, devid, backDetails, frontDetails):
188 """Write the details in the store to trigger creation of a device.
189 The backend domain ID is taken from the given config, paths for
190 frontend and backend are computed, and these are written to the store
191 appropriately, including references from frontend to backend and vice
192 versa.
194 @param config The configuration of the device, as given to
195 {@link #createDevice}.
196 @param devid As returned by {@link #getDeviceDetails}.
197 @param backDetails As returned by {@link #getDeviceDetails}.
198 @param frontDetails As returned by {@link #getDeviceDetails}.
199 """
201 import xen.xend.XendDomain
202 xd = xen.xend.XendDomain.instance()
204 backdom_name = sxp.child_value(config, 'backend')
205 if backdom_name:
206 backdom = xd.domain_lookup_by_name_or_id_nr(backdom_name)
207 else:
208 backdom = xd.privilegedDomain()
210 if not backdom:
211 raise VmError("Cannot configure device for unknown backend %s" %
212 backdom_name)
214 frontpath = self.frontendPath(devid)
215 backpath = self.backendPath(backdom, devid)
217 frontDetails.update({
218 'backend' : backpath,
219 'backend-id' : "%i" % backdom.getDomid()
220 })
223 backDetails.update({
224 'domain' : self.vm.getName(),
225 'frontend' : frontpath,
226 'frontend-id' : "%i" % self.vm.getDomid()
227 })
229 log.debug('DevController: writing %s to %s.', str(frontDetails),
230 frontpath)
231 log.debug('DevController: writing %s to %s.', str(backDetails),
232 backpath)
234 xstransact.Write(frontpath, frontDetails)
235 xstransact.Write(backpath, backDetails)
238 def backendPath(self, backdom, devid):
239 """@param backdom [XendDomainInfo] The backend domain info."""
241 return "%s/backend/%s/%s/%d" % (backdom.getDomainPath(),
242 self.deviceClass,
243 self.vm.getDomid(), devid)
246 def frontendPath(self, devid):
247 return "%s/%d" % (self.frontendRoot(), devid)
250 def frontendRoot(self):
251 return "%s/device/%s" % (self.vm.getDomainPath(), self.deviceClass)
254 def frontendMiscPath(self):
255 return "%s/device-misc/%s" % (self.vm.getDomainPath(),
256 self.deviceClass)