ia64/xen-unstable

view tools/python/xen/xend/server/DevController.py @ 7180:a6154af4fc43

Use the domain ID to refer to backends, not the UUID. This means that a new
backend is used on a localhost live migrate; migration was failing otherwise.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@ewan
date Tue Oct 04 11:01:38 2005 +0100 (2005-10-04)
parents 0e1838de9db8
children 33cd9a7a903b
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)
81 xstransact.Remove(backpath)
84 def configurations(self):
85 return map(lambda x: self.configuration(int(x)),
86 xstransact.List(self.frontendRoot()))
89 def configuration(self, devid):
90 """@return an s-expression giving the current configuration of the
91 specified device. This would be suitable for giving to {@link
92 #createDevice} in order to recreate that device."""
94 backdomid = int(xstransact.Read(self.frontendPath(devid),
95 "backend-id"))
97 return [self.deviceClass, ['backend', backdomid]]
100 def sxprs(self):
101 """@return an s-expression describing all the devices of this
102 controller's device-class.
103 """
104 return xstransact.ListRecursive(self.frontendRoot())
107 def sxpr(self, devid):
108 """@return an s-expression describing the specified device.
109 """
110 return [self.deviceClass, ['dom', self.vm.getDomid(),
111 'id', devid]]
114 ## protected:
116 def getDeviceDetails(self, config):
117 """Compute the details for creation of a device corresponding to the
118 given configuration. These details consist of a tuple of (devID,
119 backDetails, frontDetails), where devID is the ID for the new device,
120 and backDetails and frontDetails are the device configuration
121 specifics for the backend and frontend respectively.
123 backDetails and frontDetails should be dictionaries, the keys and
124 values of which will be used as paths in the store. There is no need
125 for these dictionaries to include the references from frontend to
126 backend, nor vice versa, as these will be handled by DevController.
128 Abstract; must be implemented by every subclass.
130 @return (devID, backDetails, frontDetails), as specified above.
131 """
133 raise NotImplementedError()
136 def getDomid(self):
137 """Stub to {@link XendDomainInfo.getDomid}, for use by our
138 subclasses.
139 """
140 return self.vm.getDomid()
143 def allocateDeviceID(self):
144 """Allocate a device ID, allocating them consecutively on a
145 per-domain, per-device-class basis, and using the store to record the
146 next available ID.
148 This method is available to our subclasses, though it is not
149 compulsory to use it; subclasses may prefer to allocate IDs based upon
150 the device configuration instead.
151 """
152 path = self.frontendMiscPath()
153 while True:
154 t = xstransact(path)
155 try:
156 result = t.read("nextDeviceID")
157 if result:
158 result = int(result)
159 else:
160 result = 1
161 t.write("nextDeviceID", str(result + 1))
162 if t.commit():
163 return result
164 except:
165 t.abort()
166 raise
169 def readBackend(self, devid, *args):
170 frontpath = self.frontendPath(devid)
171 backpath = xstransact.Read(frontpath, "backend")
172 return xstransact.Read(backpath, *args)
175 ## private:
177 def writeDetails(self, config, devid, backDetails, frontDetails):
178 """Write the details in the store to trigger creation of a device.
179 The backend domain ID is taken from the given config, paths for
180 frontend and backend are computed, and these are written to the store
181 appropriately, including references from frontend to backend and vice
182 versa.
184 @param config The configuration of the device, as given to
185 {@link #createDevice}.
186 @param devid As returned by {@link #getDeviceDetails}.
187 @param backDetails As returned by {@link #getDeviceDetails}.
188 @param frontDetails As returned by {@link #getDeviceDetails}.
189 """
191 import xen.xend.XendDomain
192 xd = xen.xend.XendDomain.instance()
194 backdom_name = sxp.child_value(config, 'backend')
195 if backdom_name:
196 backdom = xd.domain_lookup_by_name_or_id_nr(backdom_name)
197 else:
198 backdom = xd.privilegedDomain()
200 if not backdom:
201 raise VmError("Cannot configure device for unknown backend %s" %
202 backdom_name)
204 frontpath = self.frontendPath(devid)
205 backpath = self.backendPath(backdom, devid)
207 frontDetails.update({
208 'backend' : backpath,
209 'backend-id' : "%i" % backdom.getDomid()
210 })
213 backDetails.update({
214 'domain' : self.vm.getName(),
215 'frontend' : frontpath,
216 'frontend-id' : "%i" % self.vm.getDomid()
217 })
219 log.debug('DevController: writing %s to %s.', str(frontDetails),
220 frontpath)
221 log.debug('DevController: writing %s to %s.', str(backDetails),
222 backpath)
224 xstransact.Write(frontpath, frontDetails)
225 xstransact.Write(backpath, backDetails)
228 def backendPath(self, backdom, devid):
229 """@param backdom [XendDomainInfo] The backend domain info."""
231 return "%s/backend/%s/%s/%d" % (backdom.getDomainPath(),
232 self.deviceClass,
233 self.vm.getDomid(), devid)
236 def frontendPath(self, devid):
237 return "%s/%d" % (self.frontendRoot(), devid)
240 def frontendRoot(self):
241 return "%s/device/%s" % (self.vm.getDomainPath(), self.deviceClass)
244 def frontendMiscPath(self):
245 return "%s/device-misc/%s" % (self.vm.getDomainPath(),
246 self.deviceClass)