ia64/xen-unstable

view tools/python/xen/xm/create.py @ 17794:9126c09738da

xm: Set device_model option value default to None.
If device_model is set to '', xend will fail to execute the device
model. If None, xend will detect it and set a sensible qemu-dm path
instead.

Signed-off-by: Yosuke Iwamatsu <y-iwamatsu@ab.jp.nec.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Jun 09 09:36:27 2008 +0100 (2008-06-09)
parents 049459aec2b1
children 6ae87b27ccea
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 Nguyen Anh Quynh <aquynh@gmail.com>
17 # Copyright (C) 2005-2006 XenSource Ltd
18 #============================================================================
20 """Domain creation.
21 """
22 import os
23 import os.path
24 import sys
25 import socket
26 import re
27 import time
28 import xmlrpclib
30 from xen.xend import sxp
31 from xen.xend import PrettyPrint as SXPPrettyPrint
32 from xen.xend import osdep
33 import xen.xend.XendClient
34 from xen.xend.XendBootloader import bootloader
35 from xen.util import blkif
36 import xen.util.xsm.xsm as security
37 from xen.xm.main import serverType, SERVER_XEN_API, get_single_vm
39 from xen.xm.opts import *
41 from main import server
42 import console
45 gopts = Opts(use="""[options] [vars]
47 Create a domain.
49 Domain creation parameters can be set by command-line switches, from
50 a python configuration script or an SXP config file. See documentation
51 for --defconfig, --config. Configuration variables can be set using
52 VAR=VAL on the command line. For example vmid=3 sets vmid to 3.
54 """)
56 gopts.opt('help', short='h',
57 fn=set_true, default=0,
58 use="Print this help.")
60 gopts.opt('help_config',
61 fn=set_true, default=0,
62 use="Print the available configuration variables (vars) for the "
63 "configuration script.")
65 gopts.opt('quiet', short='q',
66 fn=set_true, default=0,
67 use="Quiet.")
69 gopts.opt('path', val='PATH',
70 fn=set_value, default='.:/etc/xen',
71 use="Search path for configuration scripts. "
72 "The value of PATH is a colon-separated directory list.")
74 gopts.opt('defconfig', short='f', val='FILE',
75 fn=set_value, default='xmdefconfig',
76 use="Use the given Python configuration script."
77 "The configuration script is loaded after arguments have been "
78 "processed. Each command-line option sets a configuration "
79 "variable named after its long option name, and these "
80 "variables are placed in the environment of the script before "
81 "it is loaded. Variables for options that may be repeated have "
82 "list values. Other variables can be set using VAR=VAL on the "
83 "command line. "
84 "After the script is loaded, option values that were not set "
85 "on the command line are replaced by the values set in the script.")
87 gopts.default('defconfig')
89 gopts.opt('config', short='F', val='FILE',
90 fn=set_value, default=None,
91 use="Domain configuration to use (SXP).\n"
92 "SXP is the underlying configuration format used by Xen.\n"
93 "SXP configurations can be hand-written or generated from Python "
94 "configuration scripts, using the -n (dryrun) option to print "
95 "the configuration.")
97 gopts.opt('dryrun', short='n',
98 fn=set_true, default=0,
99 use="Dry run - prints the resulting configuration in SXP but "
100 "does not create the domain.")
102 gopts.opt('xmldryrun', short='x',
103 fn=set_true, default=0,
104 use="XML dry run - prints the resulting configuration in XML but "
105 "does not create the domain.")
107 gopts.opt('skipdtd', short='s',
108 fn=set_true, default=0,
109 use="Skip DTD checking - skips checks on XML before creating. "
110 " Experimental. Can decrease create time." )
112 gopts.opt('paused', short='p',
113 fn=set_true, default=0,
114 use='Leave the domain paused after it is created.')
116 gopts.opt('console_autoconnect', short='c',
117 fn=set_true, default=0,
118 use="Connect to the console after the domain is created.")
120 gopts.var('vncpasswd', val='NAME',
121 fn=set_value, default=None,
122 use="Password for VNC console on HVM domain.")
124 gopts.var('vncviewer', val='no|yes',
125 fn=set_bool, default=None,
126 use="Spawn a vncviewer listening for a vnc server in the domain.\n"
127 "The address of the vncviewer is passed to the domain on the "
128 "kernel command line using 'VNC_SERVER=<host>:<port>'. The port "
129 "used by vnc is 5500 + DISPLAY. A display value with a free port "
130 "is chosen if possible.\nOnly valid when vnc=1.")
132 gopts.var('vncconsole', val='no|yes',
133 fn=set_bool, default=None,
134 use="Spawn a vncviewer process for the domain's graphical console.\n"
135 "Only valid when vnc=1.")
137 gopts.var('name', val='NAME',
138 fn=set_value, default=None,
139 use="Domain name. Must be unique.")
141 gopts.var('bootloader', val='FILE',
142 fn=set_value, default=None,
143 use="Path to bootloader.")
145 gopts.var('bootargs', val='NAME',
146 fn=set_value, default=None,
147 use="Arguments to pass to boot loader")
149 gopts.var('bootentry', val='NAME',
150 fn=set_value, default=None,
151 use="DEPRECATED. Entry to boot via boot loader. Use bootargs.")
153 gopts.var('kernel', val='FILE',
154 fn=set_value, default=None,
155 use="Path to kernel image.")
157 gopts.var('ramdisk', val='FILE',
158 fn=set_value, default='',
159 use="Path to ramdisk.")
161 gopts.var('loader', val='FILE',
162 fn=set_value, default='',
163 use="Path to HVM firmware.")
165 gopts.var('features', val='FEATURES',
166 fn=set_value, default='',
167 use="Features to enable in guest kernel")
169 gopts.var('builder', val='FUNCTION',
170 fn=set_value, default='linux',
171 use="Function to use to build the domain.")
173 gopts.var('memory', val='MEMORY',
174 fn=set_int, default=128,
175 use="Domain memory in MB.")
177 gopts.var('maxmem', val='MEMORY',
178 fn=set_int, default=None,
179 use="Maximum domain memory in MB.")
181 gopts.var('shadow_memory', val='MEMORY',
182 fn=set_int, default=0,
183 use="Domain shadow memory in MB.")
185 gopts.var('cpu', val='CPU',
186 fn=set_int, default=None,
187 use="CPU to run the VCPU0 on.")
189 gopts.var('cpus', val='CPUS',
190 fn=set_value, default=None,
191 use="CPUS to run the domain on.")
193 gopts.var('rtc_timeoffset', val='RTC_TIMEOFFSET',
194 fn=set_value, default="0",
195 use="Set RTC offset.")
197 gopts.var('pae', val='PAE',
198 fn=set_int, default=1,
199 use="Disable or enable PAE of HVM domain.")
201 gopts.var('hpet', val='HPET',
202 fn=set_int, default=0,
203 use="Enable virtual high-precision event timer.")
205 gopts.var('timer_mode', val='TIMER_MODE',
206 fn=set_int, default=0,
207 use="""Timer mode (0=delay virtual time when ticks are missed;
208 1=virtual time is always wallclock time.""")
210 gopts.var('acpi', val='ACPI',
211 fn=set_int, default=1,
212 use="Disable or enable ACPI of HVM domain.")
214 gopts.var('apic', val='APIC',
215 fn=set_int, default=1,
216 use="Disable or enable APIC mode.")
218 gopts.var('vcpus', val='VCPUS',
219 fn=set_int, default=1,
220 use="# of Virtual CPUS in domain.")
222 gopts.var('vcpu_avail', val='VCPUS',
223 fn=set_long, default=None,
224 use="Bitmask for virtual CPUs to make available immediately.")
226 gopts.var('vhpt', val='VHPT',
227 fn=set_int, default=0,
228 use="Log2 of domain VHPT size for IA64.")
230 gopts.var('cpu_cap', val='CAP',
231 fn=set_int, default=None,
232 use="""Set the maximum amount of cpu.
233 CAP is a percentage that fixes the maximum amount of cpu.""")
235 gopts.var('cpu_weight', val='WEIGHT',
236 fn=set_int, default=None,
237 use="""Set the cpu time ratio to be allocated to the domain.""")
239 gopts.var('restart', val='onreboot|always|never',
240 fn=set_value, default=None,
241 use="""Deprecated. Use on_poweroff, on_reboot, and on_crash
242 instead.
244 Whether the domain should be restarted on exit.
245 - onreboot: restart on exit with shutdown code reboot
246 - always: always restart on exit, ignore exit code
247 - never: never restart on exit, ignore exit code""")
249 gopts.var('on_poweroff', val='destroy|restart|preserve|rename-restart',
250 fn=set_value, default=None,
251 use="""Behaviour when a domain exits with reason 'poweroff'.
252 - destroy: the domain is cleaned up as normal;
253 - restart: a new domain is started in place of the old one;
254 - preserve: no clean-up is done until the domain is manually
255 destroyed (using xm destroy, for example);
256 - rename-restart: the old domain is not cleaned up, but is
257 renamed and a new domain started in its place.
258 """)
260 gopts.var('on_reboot', val='destroy|restart|preserve|rename-restart',
261 fn=set_value, default=None,
262 use="""Behaviour when a domain exits with reason 'reboot'.
263 - destroy: the domain is cleaned up as normal;
264 - restart: a new domain is started in place of the old one;
265 - preserve: no clean-up is done until the domain is manually
266 destroyed (using xm destroy, for example);
267 - rename-restart: the old domain is not cleaned up, but is
268 renamed and a new domain started in its place.
269 """)
271 gopts.var('on_crash', val='destroy|restart|preserve|rename-restart|coredump-destroy|ciredump-restart',
272 fn=set_value, default=None,
273 use="""Behaviour when a domain exits with reason 'crash'.
274 - destroy: the domain is cleaned up as normal;
275 - restart: a new domain is started in place of the old one;
276 - preserve: no clean-up is done until the domain is manually
277 destroyed (using xm destroy, for example);
278 - rename-restart: the old domain is not cleaned up, but is
279 renamed and a new domain started in its place.
280 - coredump-destroy: dump the domain's core, followed by destroy
281 - coredump-restart: dump the domain's core, followed by restart
282 """)
284 gopts.var('blkif', val='no|yes',
285 fn=set_bool, default=0,
286 use="Make the domain a block device backend.")
288 gopts.var('netif', val='no|yes',
289 fn=set_bool, default=0,
290 use="Make the domain a network interface backend.")
292 gopts.var('tpmif', val='no|yes',
293 fn=append_value, default=0,
294 use="Make the domain a TPM interface backend.")
296 gopts.var('disk', val='phy:DEV,VDEV,MODE[,DOM]',
297 fn=append_value, default=[],
298 use="""Add a disk device to a domain. The physical device is DEV,
299 which is exported to the domain as VDEV. The disk is read-only if MODE
300 is 'r', read-write if MODE is 'w'. If DOM is specified it defines the
301 backend driver domain to use for the disk.
302 The option may be repeated to add more than one disk.""")
304 gopts.var('pci', val='BUS:DEV.FUNC',
305 fn=append_value, default=[],
306 use="""Add a PCI device to a domain, using given params (in hex).
307 For example 'pci=c0:02.1'.
308 The option may be repeated to add more than one pci device.""")
310 gopts.var('ioports', val='FROM[-TO]',
311 fn=append_value, default=[],
312 use="""Add a legacy I/O range to a domain, using given params (in hex).
313 For example 'ioports=02f8-02ff'.
314 The option may be repeated to add more than one i/o range.""")
316 gopts.var('irq', val='IRQ',
317 fn=append_value, default=[],
318 use="""Add an IRQ (interrupt line) to a domain.
319 For example 'irq=7'.
320 This option may be repeated to add more than one IRQ.""")
322 gopts.var('vfb', val="type={vnc,sdl},vncunused=1,vncdisplay=N,vnclisten=ADDR,display=DISPLAY,xauthority=XAUTHORITY,vncpasswd=PASSWORD,opengl=1",
323 fn=append_value, default=[],
324 use="""Make the domain a framebuffer backend.
325 The backend type should be either sdl or vnc.
326 For type=vnc, connect an external vncviewer. The server will listen
327 on ADDR (default 127.0.0.1) on port N+5900. N defaults to the
328 domain id. If vncunused=1, the server will try to find an arbitrary
329 unused port above 5900. vncpasswd overrides the XenD configured
330 default password.
331 For type=sdl, a viewer will be started automatically using the
332 given DISPLAY and XAUTHORITY, which default to the current user's
333 ones. OpenGL will be used by default unless opengl is set to 0.""")
335 gopts.var('vif', val="type=TYPE,mac=MAC,bridge=BRIDGE,ip=IPADDR,script=SCRIPT," + \
336 "backend=DOM,vifname=NAME,rate=RATE,model=MODEL,accel=ACCEL",
337 fn=append_value, default=[],
338 use="""Add a network interface with the given MAC address and bridge.
339 The vif is configured by calling the given configuration script.
340 If type is not specified, default is netfront.
341 If mac is not specified a random MAC address is used.
342 If not specified then the network backend chooses it's own MAC address.
343 If bridge is not specified the first bridge found is used.
344 If script is not specified the default script is used.
345 If backend is not specified the default backend driver domain is used.
346 If vifname is not specified the backend virtual interface will have name vifD.N
347 where D is the domain id and N is the interface id.
348 If rate is not specified the default rate is used.
349 If model is not specified the default model is used.
350 If accel is not specified an accelerator plugin module is not used.
351 This option may be repeated to add more than one vif.
352 Specifying vifs will increase the number of interfaces as needed.""")
354 gopts.var('vtpm', val="instance=INSTANCE,backend=DOM,type=TYPE",
355 fn=append_value, default=[],
356 use="""Add a TPM interface. On the backend side use the given
357 instance as virtual TPM instance. The given number is merely the
358 preferred instance number. The hotplug script will determine
359 which instance number will actually be assigned to the domain.
360 The associtation between virtual machine and the TPM instance
361 number can be found in /etc/xen/vtpm.db. Use the backend in the
362 given domain.
363 The type parameter can be used to select a specific driver type
364 that the VM can use. To prevent a fully virtualized domain (HVM)
365 from being able to access an emulated device model, you may specify
366 'paravirtualized' here.""")
368 gopts.var('access_control', val="policy=POLICY,label=LABEL",
369 fn=append_value, default=[],
370 use="""Add a security label and the security policy reference that defines it.
371 The local ssid reference is calculated when starting/resuming the domain. At
372 this time, the policy is checked against the active policy as well. This way,
373 migrating through save/restore is covered and local labels are automatically
374 created correctly on the system where a domain is started / resumed.""")
376 gopts.var('nics', val="NUM",
377 fn=set_int, default=-1,
378 use="""DEPRECATED. Use empty vif entries instead.
380 Set the number of network interfaces.
381 Use the vif option to define interface parameters, otherwise
382 defaults are used. Specifying vifs will increase the
383 number of interfaces as needed.""")
385 gopts.var('root', val='DEVICE',
386 fn=set_value, default='',
387 use="""Set the root= parameter on the kernel command line.
388 Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""")
390 gopts.var('extra', val="ARGS",
391 fn=set_value, default='',
392 use="Set extra arguments to append to the kernel command line.")
394 gopts.var('ip', val='IPADDR',
395 fn=set_value, default='',
396 use="Set the kernel IP interface address.")
398 gopts.var('gateway', val="IPADDR",
399 fn=set_value, default='',
400 use="Set the kernel IP gateway.")
402 gopts.var('netmask', val="MASK",
403 fn=set_value, default = '',
404 use="Set the kernel IP netmask.")
406 gopts.var('hostname', val="NAME",
407 fn=set_value, default='',
408 use="Set the kernel IP hostname.")
410 gopts.var('interface', val="INTF",
411 fn=set_value, default="eth0",
412 use="Set the kernel IP interface name.")
414 gopts.var('dhcp', val="off|dhcp",
415 fn=set_value, default='off',
416 use="Set the kernel dhcp option.")
418 gopts.var('nfs_server', val="IPADDR",
419 fn=set_value, default=None,
420 use="Set the address of the NFS server for NFS root.")
422 gopts.var('nfs_root', val="PATH",
423 fn=set_value, default=None,
424 use="Set the path of the root NFS directory.")
426 gopts.var('device_model', val='FILE',
427 fn=set_value, default=None,
428 use="Path to device model program.")
430 gopts.var('fda', val='FILE',
431 fn=set_value, default='',
432 use="Path to fda")
434 gopts.var('fdb', val='FILE',
435 fn=set_value, default='',
436 use="Path to fdb")
438 gopts.var('serial', val='FILE',
439 fn=set_value, default='',
440 use="Path to serial or pty or vc")
442 gopts.var('monitor', val='no|yes',
443 fn=set_bool, default=0,
444 use="""Should the device model use monitor?""")
446 gopts.var('localtime', val='no|yes',
447 fn=set_bool, default=0,
448 use="Is RTC set to localtime?")
450 gopts.var('keymap', val='FILE',
451 fn=set_value, default='',
452 use="Set keyboard layout used")
454 gopts.var('usb', val='no|yes',
455 fn=set_bool, default=0,
456 use="Emulate USB devices?")
458 gopts.var('usbdevice', val='NAME',
459 fn=set_value, default='',
460 use="Name of USB device to add?")
462 gopts.var('guest_os_type', val='NAME',
463 fn=set_value, default='default',
464 use="Guest OS type running in HVM")
466 gopts.var('stdvga', val='no|yes',
467 fn=set_bool, default=0,
468 use="Use std vga or cirrhus logic graphics")
470 gopts.var('isa', val='no|yes',
471 fn=set_bool, default=0,
472 use="Simulate an ISA only system?")
474 gopts.var('boot', val="a|b|c|d",
475 fn=set_value, default='c',
476 use="Default boot device")
478 gopts.var('nographic', val='no|yes',
479 fn=set_bool, default=0,
480 use="Should device models use graphics?")
482 gopts.var('soundhw', val='audiodev',
483 fn=set_value, default='',
484 use="Should device models enable audio device?")
486 gopts.var('vnc', val='',
487 fn=set_value, default=None,
488 use="""Should the device model use VNC?""")
490 gopts.var('vncdisplay', val='',
491 fn=set_value, default=None,
492 use="""VNC display to use""")
494 gopts.var('vnclisten', val='',
495 fn=set_value, default=None,
496 use="""Address for VNC server to listen on.""")
498 gopts.var('vncunused', val='',
499 fn=set_bool, default=1,
500 use="""Try to find an unused port for the VNC server.
501 Only valid when vnc=1.""")
503 gopts.var('videoram', val='',
504 fn=set_value, default=None,
505 use="""Maximum amount of videoram PV guest can allocate
506 for frame buffer.""")
508 gopts.var('sdl', val='',
509 fn=set_value, default=None,
510 use="""Should the device model use SDL?""")
512 gopts.var('opengl', val='',
513 fn=set_value, default=None,
514 use="""Enable\Disable OpenGL""")
516 gopts.var('display', val='DISPLAY',
517 fn=set_value, default=None,
518 use="X11 display to use")
520 gopts.var('xauthority', val='XAUTHORITY',
521 fn=set_value, default=None,
522 use="X11 Authority to use")
524 gopts.var('uuid', val='',
525 fn=set_value, default=None,
526 use="""xenstore UUID (universally unique identifier) to use. One
527 will be randomly generated if this option is not set, just like MAC
528 addresses for virtual network interfaces. This must be a unique
529 value across the entire cluster.""")
531 gopts.var('on_xend_start', val='ignore|start',
532 fn=set_value, default='ignore',
533 use='Action to perform when xend starts')
535 gopts.var('on_xend_stop', val='ignore|shutdown|suspend',
536 fn=set_value, default="ignore",
537 use="""Behaviour when Xend stops:
538 - ignore: Domain continues to run;
539 - shutdown: Domain is shutdown;
540 - suspend: Domain is suspended;
541 """)
543 gopts.var('target', val='TARGET',
544 fn=set_int, default=0,
545 use="Set domain target.")
547 gopts.var('hap', val='HAP',
548 fn=set_int, default=1,
549 use="""Hap status (0=hap is disabled;
550 1=hap is enabled.""")
552 gopts.var('cpuid', val="IN[,SIN]:eax=EAX,ebx=EBX,exc=ECX,edx=EDX",
553 fn=append_value, default=[],
554 use="""Cpuid description.""")
556 gopts.var('cpuid_check', val="IN[,SIN]:eax=EAX,ebx=EBX,exc=ECX,edx=EDX",
557 fn=append_value, default=[],
558 use="""Cpuid check description.""")
560 def err(msg):
561 """Print an error to stderr and exit.
562 """
563 print >>sys.stderr, "Error:", msg
564 sys.exit(1)
567 def warn(msg):
568 """Print a warning to stdout.
569 """
570 print >>sys.stderr, "Warning:", msg
573 def strip(pre, s):
574 """Strip prefix 'pre' if present.
575 """
576 if s.startswith(pre):
577 return s[len(pre):]
578 else:
579 return s
581 def configure_image(vals):
582 """Create the image config.
583 """
584 if not vals.builder:
585 return None
586 config_image = [ vals.builder ]
587 if vals.kernel:
588 config_image.append([ 'kernel', os.path.abspath(vals.kernel) ])
589 if vals.ramdisk:
590 config_image.append([ 'ramdisk', os.path.abspath(vals.ramdisk) ])
591 if vals.loader:
592 config_image.append([ 'loader', os.path.abspath(vals.loader) ])
593 if vals.cmdline_ip:
594 cmdline_ip = strip('ip=', vals.cmdline_ip)
595 config_image.append(['ip', cmdline_ip])
596 if vals.root:
597 cmdline_root = strip('root=', vals.root)
598 config_image.append(['root', cmdline_root])
599 if vals.extra:
600 config_image.append(['args', vals.extra])
602 if vals.builder == 'hvm':
603 configure_hvm(config_image, vals)
605 if vals.vhpt != 0:
606 config_image.append(['vhpt', vals.vhpt])
608 return config_image
610 def configure_disks(config_devs, vals):
611 """Create the config for disks (virtual block devices).
612 """
613 for (uname, dev, mode, backend, protocol) in vals.disk:
614 if uname.startswith('tap:'):
615 cls = 'tap'
616 else:
617 cls = 'vbd'
619 config_vbd = [cls,
620 ['uname', uname],
621 ['dev', dev ],
622 ['mode', mode ] ]
623 if backend:
624 config_vbd.append(['backend', backend])
625 if protocol:
626 config_vbd.append(['protocol', protocol])
627 config_devs.append(['device', config_vbd])
629 def configure_pci(config_devs, vals):
630 """Create the config for pci devices.
631 """
632 config_pci = []
633 for (domain, bus, slot, func) in vals.pci:
634 config_pci.append(['dev', ['domain', domain], ['bus', bus], \
635 ['slot', slot], ['func', func]])
637 if len(config_pci)>0:
638 config_pci.insert(0, 'pci')
639 config_devs.append(['device', config_pci])
641 def configure_ioports(config_devs, vals):
642 """Create the config for legacy i/o ranges.
643 """
644 for (io_from, io_to) in vals.ioports:
645 config_ioports = ['ioports', ['from', io_from], ['to', io_to]]
646 config_devs.append(['device', config_ioports])
648 def configure_irq(config_devs, vals):
649 """Create the config for irqs.
650 """
651 for irq in vals.irq:
652 config_irq = ['irq', ['irq', irq]]
653 config_devs.append(['device', config_irq])
655 def configure_vfbs(config_devs, vals):
656 for f in vals.vfb:
657 d = comma_sep_kv_to_dict(f)
658 config = ['vfb']
659 if not d.has_key("type"):
660 d['type'] = 'sdl'
661 for (k,v) in d.iteritems():
662 if not k in [ 'vnclisten', 'vncunused', 'vncdisplay', 'display',
663 'videoram', 'xauthority', 'type', 'vncpasswd',
664 'opengl' ]:
665 err("configuration option %s unknown to vfbs" % k)
666 config.append([k,v])
667 if not d.has_key("keymap"):
668 if vals.keymap:
669 config.append(['keymap',vals.keymap])
670 if not d.has_key("display") and os.environ.has_key("DISPLAY"):
671 config.append(["display", os.environ['DISPLAY']])
672 if not d.has_key("xauthority"):
673 config.append(["xauthority", get_xauthority()])
674 config_devs.append(['device', ['vkbd']])
675 config_devs.append(['device', config])
677 def configure_security(config, vals):
678 """Create the config for ACM security labels.
679 """
680 access_control = vals.access_control
681 num = len(access_control)
682 if num == 1:
683 d = access_control[0]
684 policy = d.get('policy')
685 label = d.get('label')
686 if policy != security.active_policy:
687 err("Security policy (" + policy + ") incompatible with enforced policy ("
688 + security.active_policy + ")." )
689 config_access_control = ['access_control',
690 ['policy', policy],
691 ['label', label] ]
693 security_label = ['security', [ config_access_control ] ]
694 config.append(security_label)
695 elif num > 1:
696 err("VM config error: Multiple access_control definitions!")
699 def configure_vtpm(config_devs, vals):
700 """Create the config for virtual TPM interfaces.
701 """
702 vtpm = vals.vtpm
703 if len(vtpm) > 0:
704 d = vtpm[0]
705 instance = d.get('instance')
706 if instance == "VTPMD":
707 instance = "0"
708 else:
709 if instance != None:
710 try:
711 if int(instance) == 0:
712 err('VM config error: vTPM instance must not be 0.')
713 except ValueError:
714 err('Vm config error: could not parse instance number.')
715 backend = d.get('backend')
716 typ = d.get('type')
717 config_vtpm = ['vtpm']
718 if instance:
719 config_vtpm.append(['pref_instance', instance])
720 if backend:
721 config_vtpm.append(['backend', backend])
722 if typ:
723 config_vtpm.append(['type', type])
724 config_devs.append(['device', config_vtpm])
727 def configure_vifs(config_devs, vals):
728 """Create the config for virtual network interfaces.
729 """
731 vifs = vals.vif
732 vifs_n = len(vifs)
734 if hasattr(vals, 'nics'):
735 if vals.nics > 0:
736 warn("The nics option is deprecated. Please use an empty vif "
737 "entry instead:\n\n vif = [ '' ]\n")
738 for _ in range(vifs_n, vals.nics):
739 vifs.append('')
740 vifs_n = len(vifs)
741 elif vals.nics == 0:
742 warn("The nics option is deprecated. Please remove it.")
744 for c in vifs:
745 d = comma_sep_kv_to_dict(c)
746 config_vif = ['vif']
748 def f(k):
749 if k not in ['backend', 'bridge', 'ip', 'mac', 'script', 'type',
750 'vifname', 'rate', 'model', 'accel',
751 'policy', 'label']:
752 err('Invalid vif option: ' + k)
754 config_vif.append([k, d[k]])
756 map(f, d.keys())
757 config_devs.append(['device', config_vif])
760 def configure_hvm(config_image, vals):
761 """Create the config for HVM devices.
762 """
763 args = [ 'device_model', 'pae', 'vcpus', 'boot', 'fda', 'fdb', 'timer_mode',
764 'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'soundhw',
765 'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten',
766 'sdl', 'display', 'xauthority', 'rtc_timeoffset', 'monitor',
767 'acpi', 'apic', 'usb', 'usbdevice', 'keymap', 'pci', 'hpet',
768 'guest_os_type', 'hap', 'opengl', 'cpuid', 'cpuid_check']
770 for a in args:
771 if a in vals.__dict__ and vals.__dict__[a] is not None:
772 config_image.append([a, vals.__dict__[a]])
773 if vals.vncpasswd is not None:
774 config_image.append(['vncpasswd', vals.vncpasswd])
777 def make_config(vals):
778 """Create the domain configuration.
779 """
781 config = ['vm']
783 def add_conf(n):
784 if hasattr(vals, n):
785 v = getattr(vals, n)
786 if v:
787 config.append([n, v])
789 map(add_conf, ['name', 'memory', 'maxmem', 'shadow_memory',
790 'restart', 'on_poweroff',
791 'on_reboot', 'on_crash', 'vcpus', 'vcpu_avail', 'features',
792 'on_xend_start', 'on_xend_stop', 'target', 'cpuid',
793 'cpuid_check'])
795 if vals.uuid is not None:
796 config.append(['uuid', vals.uuid])
797 if vals.cpu is not None:
798 config.append(['cpu', vals.cpu])
799 if vals.cpus is not None:
800 config.append(['cpus', vals.cpus])
801 if vals.cpu_cap is not None:
802 config.append(['cpu_cap', vals.cpu_cap])
803 if vals.cpu_weight is not None:
804 config.append(['cpu_weight', vals.cpu_weight])
805 if vals.blkif:
806 config.append(['backend', ['blkif']])
807 if vals.netif:
808 config.append(['backend', ['netif']])
809 if vals.tpmif:
810 config.append(['backend', ['tpmif']])
811 if vals.localtime:
812 config.append(['localtime', vals.localtime])
814 config_image = configure_image(vals)
815 if vals.bootloader:
816 if vals.bootloader == "pygrub":
817 vals.bootloader = osdep.pygrub_path
819 config.append(['bootloader', vals.bootloader])
820 if vals.bootargs:
821 config.append(['bootloader_args', vals.bootargs])
822 else:
823 if vals.console_autoconnect:
824 config.append(['bootloader_args', ''])
825 else:
826 config.append(['bootloader_args', '-q'])
827 config.append(['image', config_image])
829 config_devs = []
830 configure_disks(config_devs, vals)
831 configure_pci(config_devs, vals)
832 configure_ioports(config_devs, vals)
833 configure_irq(config_devs, vals)
834 configure_vifs(config_devs, vals)
835 configure_vtpm(config_devs, vals)
836 configure_vfbs(config_devs, vals)
837 configure_security(config, vals)
838 config += config_devs
840 return config
842 def preprocess_disk(vals):
843 if not vals.disk: return
844 disk = []
845 for v in vals.disk:
846 d = v.split(',')
847 n = len(d)
848 if n == 3:
849 d.append(None)
850 d.append(None)
851 elif n == 4:
852 d.append(None)
853 elif n == 5:
854 pass
855 else:
856 err('Invalid disk specifier: ' + v)
857 disk.append(d)
858 vals.disk = disk
860 def preprocess_cpuid(vals, attr_name):
861 if not vals.cpuid: return
862 cpuid = {}
863 for cpuid_input in getattr(vals, attr_name):
864 input_re = "(0x)?[0-9A-Fa-f]+(,(0x)?[0-9A-Fa-f]+)?"
865 cpuid_match = re.match(r'(?P<input>%s):(?P<regs>.*)' % \
866 input_re, cpuid_input)
867 if cpuid_match != None:
868 res_cpuid = cpuid_match.groupdict()
869 input = res_cpuid['input']
870 regs = res_cpuid['regs'].split(',')
871 cpuid[input]= {} # New input
872 for reg in regs:
873 reg_match = re.match(r"(?P<reg>eax|ebx|ecx|edx)=(?P<val>.*)", reg)
874 if reg_match == None:
875 err("cpuid's syntax is (eax|ebx|ecx|edx)=value")
876 res = reg_match.groupdict()
877 cpuid[input][res['reg']] = res['val'] # new register
878 setattr(vals, attr_name, cpuid)
880 def preprocess_pci(vals):
881 if not vals.pci: return
882 pci = []
883 for pci_dev_str in vals.pci:
884 pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \
885 r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \
886 r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \
887 r"(?P<func>[0-7])$", pci_dev_str)
888 if pci_match!=None:
889 pci_dev_info = pci_match.groupdict('0')
890 try:
891 pci.append( ('0x'+pci_dev_info['domain'], \
892 '0x'+pci_dev_info['bus'], \
893 '0x'+pci_dev_info['slot'], \
894 '0x'+pci_dev_info['func']))
895 except IndexError:
896 err('Error in PCI slot syntax "%s"'%(pci_dev_str))
897 vals.pci = pci
899 def preprocess_ioports(vals):
900 if not vals.ioports: return
901 ioports = []
902 for v in vals.ioports:
903 d = v.split('-')
904 if len(d) < 1 or len(d) > 2:
905 err('Invalid i/o port range specifier: ' + v)
906 if len(d) == 1:
907 d.append(d[0])
908 # Components are in hex: add hex specifier.
909 hexd = ['0x' + x for x in d]
910 ioports.append(hexd)
911 vals.ioports = ioports
913 def preprocess_vtpm(vals):
914 if not vals.vtpm: return
915 vtpms = []
916 for vtpm in vals.vtpm:
917 d = {}
918 a = vtpm.split(',')
919 for b in a:
920 (k, v) = b.strip().split('=', 1)
921 k = k.strip()
922 v = v.strip()
923 if k not in ['backend', 'instance']:
924 err('Invalid vtpm specifier: ' + vtpm)
925 d[k] = v
926 vtpms.append(d)
927 vals.vtpm = vtpms
929 def preprocess_access_control(vals):
930 if not vals.access_control:
931 return
932 access_controls = []
933 num = len(vals.access_control)
934 if num == 1:
935 access_control = (vals.access_control)[0]
936 d = {}
937 a = access_control.split(',')
938 if len(a) > 2:
939 err('Too many elements in access_control specifier: ' + access_control)
940 for b in a:
941 (k, v) = b.strip().split('=', 1)
942 k = k.strip()
943 v = v.strip()
944 if k not in ['policy','label']:
945 err('Invalid access_control specifier: ' + access_control)
946 d[k] = v
947 access_controls.append(d)
948 vals.access_control = access_controls
949 elif num > 1:
950 err('Multiple access_control definitions.')
952 def preprocess_ip(vals):
953 if vals.ip or vals.dhcp != 'off':
954 dummy_nfs_server = '127.0.255.255'
955 ip = (vals.ip
956 + ':' + (vals.nfs_server or dummy_nfs_server)
957 + ':' + vals.gateway
958 + ':' + vals.netmask
959 + ':' + vals.hostname
960 + ':' + vals.interface
961 + ':' + vals.dhcp)
962 else:
963 ip = ''
964 vals.cmdline_ip = ip
966 def preprocess_nfs(vals):
967 if not vals.nfs_root: return
968 if not vals.nfs_server:
969 err('Must set nfs root and nfs server')
970 nfs = 'nfsroot=' + vals.nfs_server + ':' + vals.nfs_root
971 vals.extra = nfs + ' ' + vals.extra
974 def get_host_addr():
975 host = socket.gethostname()
976 addr = socket.gethostbyname(host)
977 return addr
979 VNC_BASE_PORT = 5500
981 def choose_vnc_display():
982 """Try to choose a free vnc display.
983 """
984 def netstat_local_ports():
985 """Run netstat to get a list of the local ports in use.
986 """
987 l = os.popen("netstat -nat").readlines()
988 r = []
989 # Skip 2 lines of header.
990 for x in l[2:]:
991 # Local port is field 3.
992 y = x.split()[3]
993 # Field is addr:port, split off the port.
994 y = y.split(':')[-1]
995 r.append(int(y))
996 return r
998 ports = netstat_local_ports()
999 for d in range(1, 100):
1000 port = VNC_BASE_PORT + d
1001 if port in ports: continue
1002 return d
1003 return None
1004 vncpid = None
1006 def daemonize(prog, args):
1007 """Runs a program as a daemon with the list of arguments. Returns the PID
1008 of the daemonized program, or returns 0 on error.
1009 """
1010 r, w = os.pipe()
1011 pid = os.fork()
1013 if pid == 0:
1014 os.close(r)
1015 w = os.fdopen(w, 'w')
1016 os.setsid()
1017 try:
1018 pid2 = os.fork()
1019 except:
1020 pid2 = None
1021 if pid2 == 0:
1022 os.chdir("/")
1023 for fd in range(0, 256):
1024 try:
1025 os.close(fd)
1026 except:
1027 pass
1028 os.open("/dev/null", os.O_RDWR)
1029 os.dup2(0, 1)
1030 os.dup2(0, 2)
1031 os.execvp(prog, args)
1032 os._exit(1)
1033 else:
1034 w.write(str(pid2 or 0))
1035 w.close()
1036 os._exit(0)
1037 os.close(w)
1038 r = os.fdopen(r)
1039 daemon_pid = int(r.read())
1040 r.close()
1041 os.waitpid(pid, 0)
1042 return daemon_pid
1044 def spawn_vnc(display):
1045 """Spawns a vncviewer that listens on the specified display. On success,
1046 returns the port that the vncviewer is listening on and sets the global
1047 vncpid. On failure, returns 0. Note that vncviewer is daemonized.
1048 """
1049 vncargs = (["vncviewer", "-log", "*:stdout:0",
1050 "-listen", "%d" % (VNC_BASE_PORT + display) ])
1051 global vncpid
1052 vncpid = daemonize("vncviewer", vncargs)
1053 if vncpid == 0:
1054 return 0
1056 return VNC_BASE_PORT + display
1058 def preprocess_vnc(vals):
1059 """If vnc was specified, spawn a vncviewer in listen mode
1060 and pass its address to the domain on the kernel command line.
1061 """
1062 if vals.dryrun: return
1063 if vals.vncviewer:
1064 vnc_display = choose_vnc_display()
1065 if not vnc_display:
1066 warn("No free vnc display")
1067 return
1068 print 'VNC=', vnc_display
1069 vnc_port = spawn_vnc(vnc_display)
1070 if vnc_port > 0:
1071 vnc_host = get_host_addr()
1072 vnc = 'VNC_VIEWER=%s:%d' % (vnc_host, vnc_port)
1073 vals.extra = vnc + ' ' + vals.extra
1075 def preprocess(vals):
1076 preprocess_disk(vals)
1077 preprocess_pci(vals)
1078 preprocess_ioports(vals)
1079 preprocess_ip(vals)
1080 preprocess_nfs(vals)
1081 preprocess_vnc(vals)
1082 preprocess_vtpm(vals)
1083 preprocess_access_control(vals)
1084 preprocess_cpuid(vals, 'cpuid')
1085 preprocess_cpuid(vals, 'cpuid_check')
1088 def comma_sep_kv_to_dict(c):
1089 """Convert comma-separated, equals-separated key-value pairs into a
1090 dictionary.
1091 """
1092 d = {}
1093 c = c.strip()
1094 if len(c) > 0:
1095 a = c.split(',')
1096 for b in a:
1097 if b.find('=') == -1:
1098 err("%s should be a pair, separated by an equals sign." % b)
1099 (k, v) = b.split('=', 1)
1100 k = k.strip()
1101 v = v.strip()
1102 d[k] = v
1103 return d
1106 def make_domain(opts, config):
1107 """Create, build and start a domain.
1109 @param opts: options
1110 @param config: configuration
1111 @return: domain id
1112 @rtype: int
1113 """
1115 try:
1116 dominfo = server.xend.domain.create(config)
1117 except xmlrpclib.Fault, ex:
1118 import signal
1119 if vncpid:
1120 os.kill(vncpid, signal.SIGKILL)
1121 if ex.faultCode == xen.xend.XendClient.ERROR_INVALID_DOMAIN:
1122 err("the domain '%s' does not exist." % ex.faultString)
1123 else:
1124 err("%s" % ex.faultString)
1125 except Exception, ex:
1126 # main.py has good error messages that let the user know what failed.
1127 # unless the error is a create.py specific thing, it should be handled
1128 # at main. The purpose of this general-case 'Exception' handler is to
1129 # clean up create.py specific processes/data but since create.py does
1130 # not know what to do with the error, it should pass it up.
1131 import signal
1132 if vncpid:
1133 os.kill(vncpid, signal.SIGKILL)
1134 raise
1136 dom = sxp.child_value(dominfo, 'name')
1138 try:
1139 server.xend.domain.waitForDevices(dom)
1140 except xmlrpclib.Fault, ex:
1141 server.xend.domain.destroy(dom)
1142 err("%s" % ex.faultString)
1143 except:
1144 server.xend.domain.destroy(dom)
1145 err("Device creation failed for domain %s" % dom)
1147 if not opts.vals.paused:
1148 try:
1149 server.xend.domain.unpause(dom)
1150 except:
1151 server.xend.domain.destroy(dom)
1152 err("Failed to unpause domain %s" % dom)
1153 opts.info("Started domain %s" % (dom))
1154 return int(sxp.child_value(dominfo, 'domid'))
1157 def get_xauthority():
1158 xauth = os.getenv("XAUTHORITY")
1159 if not xauth:
1160 home = os.getenv("HOME")
1161 if not home:
1162 import posix, pwd
1163 home = pwd.getpwuid(posix.getuid())[5]
1164 xauth = home + "/.Xauthority"
1165 return xauth
1168 def parseCommandLine(argv):
1169 gopts.reset()
1170 args = gopts.parse(argv)
1172 if gopts.vals.help or gopts.vals.help_config:
1173 if gopts.vals.help_config:
1174 print gopts.val_usage()
1175 return (None, None)
1177 if not gopts.vals.display:
1178 gopts.vals.display = os.getenv("DISPLAY")
1180 if not gopts.vals.xauthority:
1181 gopts.vals.xauthority = get_xauthority()
1183 gopts.is_xml = False
1185 # Process remaining args as config variables.
1186 for arg in args:
1187 if '=' in arg:
1188 (var, val) = arg.strip().split('=', 1)
1189 gopts.setvar(var.strip(), val.strip())
1190 if gopts.vals.config:
1191 config = gopts.vals.config
1192 else:
1193 try:
1194 gopts.load_defconfig()
1195 preprocess(gopts.vals)
1196 if not gopts.getopt('name') and gopts.getopt('defconfig'):
1197 gopts.setopt('name', os.path.basename(gopts.getopt('defconfig')))
1198 config = make_config(gopts.vals)
1199 except XMLFileError, ex:
1200 XMLFile = ex.getFile()
1201 gopts.is_xml = True
1202 config = ex.getFile()
1204 return (gopts, config)
1206 def help():
1207 return str(gopts)
1209 def main(argv):
1210 is_xml = False
1212 try:
1213 (opts, config) = parseCommandLine(argv)
1214 except StandardError, ex:
1215 err(str(ex))
1217 if not opts:
1218 return
1220 if not opts.is_xml:
1221 if type(config) == str:
1222 try:
1223 config = sxp.parse(file(config))[0]
1224 except IOError, exn:
1225 raise OptionError("Cannot read file %s: %s" % (config, exn[1]))
1227 if serverType == SERVER_XEN_API:
1228 from xen.xm.xenapi_create import sxp2xml
1229 sxp2xml_inst = sxp2xml()
1230 doc = sxp2xml_inst.convert_sxp_to_xml(config, transient=True)
1232 if opts.vals.dryrun and not opts.is_xml:
1233 SXPPrettyPrint.prettyprint(config)
1235 if opts.vals.xmldryrun and serverType == SERVER_XEN_API:
1236 from xml.dom.ext import PrettyPrint as XMLPrettyPrint
1237 XMLPrettyPrint(doc)
1239 if opts.vals.dryrun or opts.vals.xmldryrun:
1240 return
1242 if opts.vals.console_autoconnect:
1243 do_console(sxp.child_value(config, 'name', -1))
1245 if serverType == SERVER_XEN_API:
1246 from xen.xm.xenapi_create import xenapi_create
1247 xenapi_create_inst = xenapi_create()
1248 if opts.is_xml:
1249 vm_refs = xenapi_create_inst.create(filename = config,
1250 skipdtd = opts.vals.skipdtd)
1251 else:
1252 vm_refs = xenapi_create_inst.create(document = doc,
1253 skipdtd = opts.vals.skipdtd)
1255 map(lambda vm_ref: server.xenapi.VM.start(vm_ref, 0), vm_refs)
1256 elif not opts.is_xml:
1257 dom = make_domain(opts, config)
1259 def do_console(domain_name):
1260 cpid = os.fork()
1261 if cpid != 0:
1262 for i in range(10):
1263 # Catch failure of the create process
1264 time.sleep(1)
1265 (p, rv) = os.waitpid(cpid, os.WNOHANG)
1266 if os.WIFEXITED(rv):
1267 if os.WEXITSTATUS(rv) != 0:
1268 sys.exit(os.WEXITSTATUS(rv))
1269 try:
1270 # Acquire the console of the created dom
1271 if serverType == SERVER_XEN_API:
1272 domid = server.xenapi.VM.get_domid(
1273 get_single_vm(domain_name))
1274 else:
1275 dom = server.xend.domain(domain_name)
1276 domid = int(sxp.child_value(dom, 'domid', '-1'))
1277 console.execConsole(domid)
1278 except:
1279 pass
1280 print("Could not start console\n");
1281 sys.exit(0)
1283 if __name__ == '__main__':
1284 main(sys.argv)