direct-io.hg

view tools/python/xen/xend/image.py @ 7477:5a7baecb1c70

Fix an issue for passing arguement from control panel to deivce model
for some arguemnt like 'localtime', 'isa', device model need an argument
"-localtime", instead of "-localtime 1"
Signed-off-by: Xiaofeng Ling <xiaofeng.ling@intel.com>
author kaf24@firebug.cl.cam.ac.uk
date Sun Oct 23 16:51:47 2005 +0100 (2005-10-23)
parents 6f5b94da963a
children cc23d4236b20 8928c89a8d0a
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) 2005 Mike Wray <mike.wray@hp.com>
16 # Copyright (C) 2005 XenSource Ltd
17 #============================================================================
20 import os, string
21 import re
23 import xen.lowlevel.xc
24 from xen.xend import sxp
25 from xen.xend.XendError import VmError
26 from xen.xend.XendLogging import log
29 xc = xen.lowlevel.xc.new()
32 MAX_GUEST_CMDLINE = 1024
35 def create(vm, imageConfig, deviceConfig):
36 """Create an image handler for a vm.
38 @return ImageHandler instance
39 """
40 return findImageHandlerClass(imageConfig)(vm, imageConfig, deviceConfig)
43 class ImageHandler:
44 """Abstract base class for image handlers.
46 createImage() is called to configure and build the domain from its
47 kernel image and ramdisk etc.
49 The method buildDomain() is used to build the domain, and must be
50 defined in a subclass. Usually this is the only method that needs
51 defining in a subclass.
53 The method createDeviceModel() is called to create the domain device
54 model if it needs one. The default is to do nothing.
56 The method destroy() is called when the domain is destroyed.
57 The default is to do nothing.
58 """
60 ostype = None
63 def __init__(self, vm, imageConfig, deviceConfig):
64 self.vm = vm
66 self.kernel = None
67 self.ramdisk = None
68 self.cmdline = None
70 self.configure(imageConfig, deviceConfig)
72 def configure(self, imageConfig, _):
73 """Config actions common to all unix-like domains."""
75 def get_cfg(name, default = None):
76 return sxp.child_value(imageConfig, name, default)
78 self.kernel = get_cfg("kernel")
79 self.cmdline = ""
80 ip = get_cfg("ip")
81 if ip:
82 self.cmdline += " ip=" + ip
83 root = get_cfg("root")
84 if root:
85 self.cmdline += " root=" + root
86 args = get_cfg("args")
87 if args:
88 self.cmdline += " " + args
89 self.ramdisk = get_cfg("ramdisk", '')
91 self.vm.storeVm(("image/ostype", self.ostype),
92 ("image/kernel", self.kernel),
93 ("image/cmdline", self.cmdline),
94 ("image/ramdisk", self.ramdisk))
97 def handleBootloading(self):
98 self.unlink(self.kernel)
99 self.unlink(self.ramdisk)
102 def unlink(self, f):
103 if not f: return
104 try:
105 os.unlink(f)
106 except OSError, ex:
107 log.warning("error removing bootloader file '%s': %s", f, ex)
110 def createImage(self):
111 """Entry point to create domain memory image.
112 Override in subclass if needed.
113 """
114 return self.createDomain()
117 def createDomain(self):
118 """Build the domain boot image.
119 """
120 # Set params and call buildDomain().
122 if not os.path.isfile(self.kernel):
123 raise VmError('Kernel image does not exist: %s' % self.kernel)
124 if self.ramdisk and not os.path.isfile(self.ramdisk):
125 raise VmError('Kernel ramdisk does not exist: %s' % self.ramdisk)
126 if len(self.cmdline) >= MAX_GUEST_CMDLINE:
127 log.warning('kernel cmdline too long, domain %d',
128 self.vm.getDomid())
130 log.info("buildDomain os=%s dom=%d vcpus=%d", self.ostype,
131 self.vm.getDomid(), self.vm.getVCpuCount())
133 result = self.buildDomain()
135 if isinstance(result, dict):
136 return result
137 else:
138 raise VmError('Building domain failed: ostype=%s dom=%d err=%s'
139 % (self.ostype, self.vm.getDomid(), str(result)))
142 def getDomainMemory(self, mem):
143 """@return The memory required, in KiB, by the domain to store the
144 given amount, also in KiB. This is normally just mem, but VMX domains
145 have overheads to account for."""
146 return mem
148 def buildDomain(self):
149 """Build the domain. Define in subclass."""
150 raise NotImplementedError()
152 def createDeviceModel(self):
153 """Create device model for the domain (define in subclass if needed)."""
154 pass
156 def destroy(self):
157 """Extra cleanup on domain destroy (define in subclass if needed)."""
158 pass
161 class LinuxImageHandler(ImageHandler):
163 ostype = "linux"
165 def buildDomain(self):
166 store_evtchn = self.vm.getStorePort()
167 console_evtchn = self.vm.getConsolePort()
169 log.debug("dom = %d", self.vm.getDomid())
170 log.debug("image = %s", self.kernel)
171 log.debug("store_evtchn = %d", store_evtchn)
172 log.debug("console_evtchn = %d", console_evtchn)
173 log.debug("cmdline = %s", self.cmdline)
174 log.debug("ramdisk = %s", self.ramdisk)
175 log.debug("vcpus = %d", self.vm.getVCpuCount())
177 return xc.linux_build(dom = self.vm.getDomid(),
178 image = self.kernel,
179 store_evtchn = store_evtchn,
180 console_evtchn = console_evtchn,
181 cmdline = self.cmdline,
182 ramdisk = self.ramdisk)
184 class VmxImageHandler(ImageHandler):
186 ostype = "vmx"
188 def configure(self, imageConfig, deviceConfig):
189 ImageHandler.configure(self, imageConfig, deviceConfig)
191 self.dmargs = self.parseDeviceModelArgs(imageConfig, deviceConfig)
192 self.device_model = sxp.child_value(imageConfig, 'device_model')
193 if not self.device_model:
194 raise VmError("vmx: missing device model")
195 self.display = sxp.child_value(imageConfig, 'display')
197 self.vm.storeVm(("image/dmargs", " ".join(self.dmargs)),
198 ("image/device-model", self.device_model),
199 ("image/display", self.display))
201 self.device_channel = None
202 self.pid = 0
204 self.dmargs += self.configVNC(imageConfig)
207 def buildDomain(self):
208 # Create an event channel
209 self.device_channel = xc.evtchn_alloc_unbound(dom=self.vm.getDomid(),
210 remote_dom=0)
211 log.info("VMX device model port: %d", self.device_channel)
213 store_evtchn = self.vm.getStorePort()
215 log.debug("dom = %d", self.vm.getDomid())
216 log.debug("image = %s", self.kernel)
217 log.debug("control_evtchn = %d", self.device_channel)
218 log.debug("store_evtchn = %d", store_evtchn)
219 log.debug("memsize = %d", self.vm.getMemoryTarget() / 1024)
220 log.debug("vcpus = %d", self.vm.getVCpuCount())
222 return xc.vmx_build(dom = self.vm.getDomid(),
223 image = self.kernel,
224 control_evtchn = self.device_channel,
225 store_evtchn = store_evtchn,
226 memsize = self.vm.getMemoryTarget() / 1024,
227 vcpus = self.vm.getVCpuCount())
230 # Return a list of cmd line args to the device models based on the
231 # xm config file
232 def parseDeviceModelArgs(self, imageConfig, deviceConfig):
233 dmargs = [ 'cdrom', 'boot', 'fda', 'fdb', 'ne2000',
234 'localtime', 'serial', 'stdvga', 'isa', 'vcpus' ]
235 ret = []
236 for a in dmargs:
237 v = sxp.child_value(imageConfig, a)
239 # python doesn't allow '-' in variable names
240 if a == 'stdvga': a = 'std-vga'
241 if a == 'ne2000': a = 'nic-ne2000'
243 # Handle booleans gracefully
244 if a in ['localtime', 'std-vga', 'isa', 'nic-ne2000']:
245 if v != None: v = int(v)
246 if v: ret.append("-%s" % a)
247 else:
248 if v:
249 ret.append("-%s" % a)
250 ret.append("%s" % v)
251 log.debug("args: %s, val: %s" % (a,v))
253 # Handle disk/network related options
254 for (name, info) in deviceConfig:
255 if name == 'vbd':
256 uname = sxp.child_value(info, 'uname')
257 typedev = sxp.child_value(info, 'dev')
258 (_, vbdparam) = string.split(uname, ':', 1)
259 if re.match('^ioemu:', typedev):
260 (emtype, vbddev) = string.split(typedev, ':', 1)
261 else:
262 emtype = 'vbd'
263 vbddev = typedev
264 if emtype != 'ioemu':
265 continue;
266 vbddev_list = ['hda', 'hdb', 'hdc', 'hdd']
267 if vbddev not in vbddev_list:
268 raise VmError("vmx: for qemu vbd type=file&dev=hda~hdd")
269 ret.append("-%s" % vbddev)
270 ret.append("%s" % vbdparam)
271 if name == 'vif':
272 mac = sxp.child_value(info, 'mac')
273 ret.append("-macaddr")
274 ret.append("%s" % mac)
275 if name == 'vtpm':
276 instance = sxp.child_value(info, 'instance')
277 ret.append("-instance")
278 ret.append("%s" % instance)
279 return ret
281 def configVNC(self, config):
282 # Handle graphics library related options
283 vnc = sxp.child_value(config, 'vnc')
284 sdl = sxp.child_value(config, 'sdl')
285 ret = []
286 nographic = sxp.child_value(config, 'nographic')
287 if nographic:
288 ret.append('-nographic')
289 return ret
291 if vnc and sdl:
292 ret = ret + ['-vnc-and-sdl', '-k', 'en-us']
293 elif vnc:
294 ret = ret + ['-vnc', '-k', 'en-us']
295 if vnc:
296 vncport = int(self.vm.getDomid()) + 5900
297 ret = ret + ['-vncport', '%d' % vncport]
298 return ret
300 def createDeviceModel(self):
301 if self.pid:
302 return
303 # Execute device model.
304 #todo: Error handling
305 # XXX RN: note that the order of args matter!
306 args = [self.device_model]
307 vnc = self.vncParams()
308 if len(vnc):
309 args = args + vnc
310 args = args + ([ "-d", "%d" % self.vm.getDomid(),
311 "-p", "%d" % self.device_channel,
312 "-m", "%s" % (self.vm.getMemoryTarget() / 1024)])
313 args = args + self.dmargs
314 env = dict(os.environ)
315 if self.display:
316 env['DISPLAY'] = self.display
317 log.info("spawning device models: %s %s", self.device_model, args)
318 self.pid = os.spawnve(os.P_NOWAIT, self.device_model, args, env)
319 log.info("device model pid: %d", self.pid)
321 def vncParams(self):
322 # see if a vncviewer was specified
323 # XXX RN: bit of a hack. should unify this, maybe stick in config space
324 vncconnect=[]
325 args = self.cmdline
326 if args:
327 arg_list = string.split(args)
328 for arg in arg_list:
329 al = string.split(arg, '=')
330 if al[0] == "VNC_VIEWER":
331 vncconnect=["-vncconnect", "%s" % al[1]]
332 break
333 return vncconnect
335 def destroy(self):
336 import signal
337 if not self.pid:
338 return
339 os.kill(self.pid, signal.SIGKILL)
340 os.waitpid(self.pid, 0)
341 self.pid = 0
343 def getDomainMemory(self, mem):
344 """@see ImageHandler.getDomainMemory"""
345 # for ioreq_t and xenstore
346 static_pages = 2
347 return mem + self.getPageTableSize(mem / 1024) + 4 * static_pages
349 def getPageTableSize(self, mem_mb):
350 """Return the size of memory needed for 1:1 page tables for physical
351 mode.
353 @param mem_mb: size in MB
354 @return size in KB
355 """
356 # 1 page for the PGD + 1 pte page for 4MB of memory (rounded)
357 if os.uname()[4] == 'x86_64':
358 return (5 + ((mem_mb + 1) >> 1)) * 4
359 elif os.uname()[4] == 'ia64':
360 # XEN/IA64 has p2m table allocated on demand, so only return
361 # guest firmware size here.
362 return 16 * 1024
363 else:
364 return (1 + ((mem_mb + 3) >> 2)) * 4
367 """Table of image handler classes for virtual machine images. Indexed by
368 image type.
369 """
370 imageHandlerClasses = {}
373 for h in LinuxImageHandler, VmxImageHandler:
374 imageHandlerClasses[h.ostype] = h
377 def findImageHandlerClass(image):
378 """Find the image handler class for an image config.
380 @param image config
381 @return ImageHandler subclass or None
382 """
383 ty = sxp.name(image)
384 if ty is None:
385 raise VmError('missing image type')
386 imageClass = imageHandlerClasses.get(ty)
387 if imageClass is None:
388 raise VmError('unknown image type: ' + ty)
389 return imageClass