ia64/xen-unstable

view tools/python/xen/xm/create.py @ 19725:265de5701b82

xm: Don't die when trying to conect the console to short-lived domains

As observed by Mick Joran, if short-lived domain exits cleanly
then os.waitpid() will throw the following exception. This appears
to be because the child process that is used to start the domain
has detached from its parent.

OSError: [Errno 10] No child processes

Cc: Mick Jordan <Mick.Jordan@sun.com>
Signed-off-by: Simon Horman <horms@verge.ent.au>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jun 04 10:46:13 2009 +0100 (2009-06-04)
parents ffcc665158ae
children 50cf07f42fdd
line source
1 #============================================================================UTO
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 import xen.xend.XendClient
33 from xen.xend.XendBootloader import bootloader
34 from xen.xend.XendConstants import *
35 from xen.xend.server.DevConstants import xenbusState
36 from xen.util import blkif
37 from xen.util import vscsi_util
38 import xen.util.xsm.xsm as security
39 from xen.xm.main import serverType, SERVER_XEN_API, get_single_vm
40 from xen.util import utils, auxbin
42 from xen.xm.opts import *
44 from main import server
45 from main import domain_name_to_domid
46 import console
49 gopts = Opts(use="""[options] [vars]
51 Create a domain.
53 Domain creation parameters can be set by command-line switches, from
54 a python configuration script or an SXP config file. See documentation
55 for --defconfig, --config. Configuration variables can be set using
56 VAR=VAL on the command line. For example vmid=3 sets vmid to 3.
58 """)
60 gopts.opt('help', short='h',
61 fn=set_true, default=0,
62 use="Print this help.")
64 gopts.opt('help_config',
65 fn=set_true, default=0,
66 use="Print the available configuration variables (vars) for the "
67 "configuration script.")
69 gopts.opt('quiet', short='q',
70 fn=set_true, default=0,
71 use="Quiet.")
73 gopts.opt('path', val='PATH',
74 fn=set_value, default='.:' + auxbin.xen_configdir(),
75 use="Search path for configuration scripts. "
76 "The value of PATH is a colon-separated directory list.")
78 gopts.opt('defconfig', short='f', val='FILE',
79 fn=set_value, default='xmdefconfig',
80 use="Use the given Python configuration script."
81 "The configuration script is loaded after arguments have been "
82 "processed. Each command-line option sets a configuration "
83 "variable named after its long option name, and these "
84 "variables are placed in the environment of the script before "
85 "it is loaded. Variables for options that may be repeated have "
86 "list values. Other variables can be set using VAR=VAL on the "
87 "command line. "
88 "After the script is loaded, option values that were not set "
89 "on the command line are replaced by the values set in the script.")
91 gopts.default('defconfig')
93 gopts.opt('config', short='F', val='FILE',
94 fn=set_value, default=None,
95 use="Domain configuration to use (SXP).\n"
96 "SXP is the underlying configuration format used by Xen.\n"
97 "SXP configurations can be hand-written or generated from Python "
98 "configuration scripts, using the -n (dryrun) option to print "
99 "the configuration.")
101 gopts.opt('dryrun', short='n',
102 fn=set_true, default=0,
103 use="Dry run - prints the resulting configuration in SXP but "
104 "does not create the domain.")
106 gopts.opt('xmldryrun', short='x',
107 fn=set_true, default=0,
108 use="XML dry run - prints the resulting configuration in XML but "
109 "does not create the domain.")
111 gopts.opt('skipdtd', short='s',
112 fn=set_true, default=0,
113 use="Skip DTD checking - skips checks on XML before creating. "
114 " Experimental. Can decrease create time." )
116 gopts.opt('paused', short='p',
117 fn=set_true, default=0,
118 use='Leave the domain paused after it is created.')
120 gopts.opt('console_autoconnect', short='c',
121 fn=set_true, default=0,
122 use="Connect to the console after the domain is created.")
124 gopts.opt('vncviewer',
125 fn=set_true, default=0,
126 use="Connect to the VNC display after the domain is created.")
128 gopts.opt('vncviewer-autopass',
129 fn=set_true, default=0,
130 use="Pass VNC password to viewer via stdin and -autopass.")
132 gopts.var('vncpasswd', val='NAME',
133 fn=set_value, default=None,
134 use="Password for VNC console on HVM domain.")
136 gopts.var('vncviewer', val='no|yes',
137 fn=set_bool, default=None,
138 use="Spawn a vncviewer listening for a vnc server in the domain.\n"
139 "The address of the vncviewer is passed to the domain on the "
140 "kernel command line using 'VNC_SERVER=<host>:<port>'. The port "
141 "used by vnc is 5500 + DISPLAY. A display value with a free port "
142 "is chosen if possible.\nOnly valid when vnc=1.\nDEPRECATED")
144 gopts.var('vncconsole', val='no|yes',
145 fn=set_bool, default=None,
146 use="Spawn a vncviewer process for the domain's graphical console.\n"
147 "Only valid when vnc=1.")
149 gopts.var('name', val='NAME',
150 fn=set_value, default=None,
151 use="Domain name. Must be unique.")
153 gopts.var('bootloader', val='FILE',
154 fn=set_value, default=None,
155 use="Path to bootloader.")
157 gopts.var('bootargs', val='NAME',
158 fn=set_value, default=None,
159 use="Arguments to pass to boot loader")
161 gopts.var('bootentry', val='NAME',
162 fn=set_value, default=None,
163 use="DEPRECATED. Entry to boot via boot loader. Use bootargs.")
165 gopts.var('kernel', val='FILE',
166 fn=set_value, default=None,
167 use="Path to kernel image.")
169 gopts.var('ramdisk', val='FILE',
170 fn=set_value, default='',
171 use="Path to ramdisk.")
173 gopts.var('loader', val='FILE',
174 fn=set_value, default='',
175 use="Path to HVM firmware.")
177 gopts.var('features', val='FEATURES',
178 fn=set_value, default='',
179 use="Features to enable in guest kernel")
181 gopts.var('builder', val='FUNCTION',
182 fn=set_value, default='linux',
183 use="Function to use to build the domain.")
185 gopts.var('memory', val='MEMORY',
186 fn=set_int, default=128,
187 use="Domain memory in MB.")
189 gopts.var('maxmem', val='MEMORY',
190 fn=set_int, default=None,
191 use="Maximum domain memory in MB.")
193 gopts.var('shadow_memory', val='MEMORY',
194 fn=set_int, default=0,
195 use="Domain shadow memory in MB.")
197 gopts.var('cpu', val='CPU',
198 fn=set_int, default=None,
199 use="CPU to run the VCPU0 on.")
201 gopts.var('cpus', val='CPUS',
202 fn=set_value, default=None,
203 use="CPUS to run the domain on.")
205 gopts.var('rtc_timeoffset', val='RTC_TIMEOFFSET',
206 fn=set_int, default=0,
207 use="Set RTC offset.")
209 gopts.var('pae', val='PAE',
210 fn=set_int, default=1,
211 use="Disable or enable PAE of HVM domain.")
213 gopts.var('hpet', val='HPET',
214 fn=set_int, default=0,
215 use="Enable virtual high-precision event timer.")
217 gopts.var('timer_mode', val='TIMER_MODE',
218 fn=set_int, default=1,
219 use="""Timer mode (0=delay virtual time when ticks are missed;
220 1=virtual time is always wallclock time.""")
222 gopts.var('vpt_align', val='VPT_ALIGN',
223 fn=set_int, default=1,
224 use="Enable aligning all periodic vpt to reduce timer interrupts.")
226 gopts.var('viridian', val='VIRIDIAN',
227 fn=set_int, default=0,
228 use="""Expose Viridian interface to x86 HVM guest?
229 (Default is 0).""")
231 gopts.var('acpi', val='ACPI',
232 fn=set_int, default=1,
233 use="Disable or enable ACPI of HVM domain.")
235 gopts.var('apic', val='APIC',
236 fn=set_int, default=1,
237 use="Disable or enable APIC mode.")
239 gopts.var('vcpus', val='VCPUS',
240 fn=set_int, default=1,
241 use="# of Virtual CPUS in domain.")
243 gopts.var('vcpu_avail', val='VCPUS',
244 fn=set_long, default=None,
245 use="Bitmask for virtual CPUs to make available immediately.")
247 gopts.var('vhpt', val='VHPT',
248 fn=set_int, default=0,
249 use="Log2 of domain VHPT size for IA64.")
251 gopts.var('cpu_cap', val='CAP',
252 fn=set_int, default=None,
253 use="""Set the maximum amount of cpu.
254 CAP is a percentage that fixes the maximum amount of cpu.""")
256 gopts.var('cpu_weight', val='WEIGHT',
257 fn=set_int, default=None,
258 use="""Set the cpu time ratio to be allocated to the domain.""")
260 gopts.var('restart', val='onreboot|always|never',
261 fn=set_value, default=None,
262 use="""Deprecated. Use on_poweroff, on_reboot, and on_crash
263 instead.
265 Whether the domain should be restarted on exit.
266 - onreboot: restart on exit with shutdown code reboot
267 - always: always restart on exit, ignore exit code
268 - never: never restart on exit, ignore exit code""")
270 gopts.var('on_poweroff', val='destroy|restart|preserve|rename-restart',
271 fn=set_value, default=None,
272 use="""Behaviour when a domain exits with reason 'poweroff'.
273 - destroy: the domain is cleaned up as normal;
274 - restart: a new domain is started in place of the old one;
275 - preserve: no clean-up is done until the domain is manually
276 destroyed (using xm destroy, for example);
277 - rename-restart: the old domain is not cleaned up, but is
278 renamed and a new domain started in its place.
279 """)
281 gopts.var('on_reboot', val='destroy|restart|preserve|rename-restart',
282 fn=set_value, default=None,
283 use="""Behaviour when a domain exits with reason 'reboot'.
284 - destroy: the domain is cleaned up as normal;
285 - restart: a new domain is started in place of the old one;
286 - preserve: no clean-up is done until the domain is manually
287 destroyed (using xm destroy, for example);
288 - rename-restart: the old domain is not cleaned up, but is
289 renamed and a new domain started in its place.
290 """)
292 gopts.var('on_crash', val='destroy|restart|preserve|rename-restart|coredump-destroy|coredump-restart',
293 fn=set_value, default=None,
294 use="""Behaviour when a domain exits with reason 'crash'.
295 - destroy: the domain is cleaned up as normal;
296 - restart: a new domain is started in place of the old one;
297 - preserve: no clean-up is done until the domain is manually
298 destroyed (using xm destroy, for example);
299 - rename-restart: the old domain is not cleaned up, but is
300 renamed and a new domain started in its place.
301 - coredump-destroy: dump the domain's core, followed by destroy
302 - coredump-restart: dump the domain's core, followed by restart
303 """)
305 gopts.var('blkif', val='no|yes',
306 fn=set_bool, default=0,
307 use="Make the domain a block device backend.")
309 gopts.var('netif', val='no|yes',
310 fn=set_bool, default=0,
311 use="Make the domain a network interface backend.")
313 gopts.var('tpmif', val='no|yes',
314 fn=append_value, default=0,
315 use="Make the domain a TPM interface backend.")
317 gopts.var('disk', val='phy:DEV,VDEV,MODE[,DOM]',
318 fn=append_value, default=[],
319 use="""Add a disk device to a domain. The physical device is DEV,
320 which is exported to the domain as VDEV. The disk is read-only if MODE
321 is 'r', read-write if MODE is 'w'. If DOM is specified it defines the
322 backend driver domain to use for the disk.
323 The option may be repeated to add more than one disk.""")
325 gopts.var('pci', val='BUS:DEV.FUNC[@VSLOT][,msitranslate=0|1][,power_mgmt=0|1]',
326 fn=append_value, default=[],
327 use="""Add a PCI device to a domain, using given params (in hex).
328 For example 'pci=c0:02.1'.
329 If VSLOT is supplied the device will be inserted into that
330 virtual slot in the guest, else a free slot is selected.
331 If msitranslate is set, MSI-INTx translation is enabled if possible.
332 Guest that doesn't support MSI will get IO-APIC type IRQs
333 translated from physical MSI, HVM only. Default is 1.
334 The option may be repeated to add more than one pci device.
335 If power_mgmt is set, the guest OS will be able to program the power
336 states D0-D3hot of the device, HVM only. Default=0.""")
338 gopts.var('vscsi', val='PDEV,VDEV[,DOM]',
339 fn=append_value, default=[],
340 use="""Add a SCSI device to a domain. The physical device is PDEV,
341 which is exported to the domain as VDEV(X:X:X:X).""")
343 gopts.var('ioports', val='FROM[-TO]',
344 fn=append_value, default=[],
345 use="""Add a legacy I/O range to a domain, using given params (in hex).
346 For example 'ioports=02f8-02ff'.
347 The option may be repeated to add more than one i/o range.""")
349 gopts.var('irq', val='IRQ',
350 fn=append_value, default=[],
351 use="""Add an IRQ (interrupt line) to a domain.
352 For example 'irq=7'.
353 This option may be repeated to add more than one IRQ.""")
355 gopts.var('vfb', val="vnc=1,sdl=1,vncunused=1,vncdisplay=N,vnclisten=ADDR,display=DISPLAY,xauthority=XAUTHORITY,vncpasswd=PASSWORD,opengl=1,keymap=FILE",
356 fn=append_value, default=[],
357 use="""Make the domain a framebuffer backend.
358 Both sdl=1 and vnc=1 can be enabled at the same time.
359 For vnc=1, connect an external vncviewer. The server will listen
360 on ADDR (default 127.0.0.1) on port N+5900. N defaults to the
361 domain id. If vncunused=1, the server will try to find an arbitrary
362 unused port above 5900. vncpasswd overrides the XenD configured
363 default password.
364 For sdl=1, a viewer will be started automatically using the
365 given DISPLAY and XAUTHORITY, which default to the current user's
366 ones. OpenGL will be used by default unless opengl is set to 0.
367 keymap overrides the XendD configured default layout file.""")
369 gopts.var('vif', val="type=TYPE,mac=MAC,bridge=BRIDGE,ip=IPADDR,script=SCRIPT," + \
370 "backend=DOM,vifname=NAME,rate=RATE,model=MODEL,accel=ACCEL",
371 fn=append_value, default=[],
372 use="""Add a network interface with the given MAC address and bridge.
373 The vif is configured by calling the given configuration script.
374 If type is not specified, default is netfront.
375 If mac is not specified a random MAC address is used.
376 If not specified then the network backend chooses it's own MAC address.
377 If bridge is not specified the first bridge found is used.
378 If script is not specified the default script is used.
379 If backend is not specified the default backend driver domain is used.
380 If vifname is not specified the backend virtual interface will have name vifD.N
381 where D is the domain id and N is the interface id.
382 If rate is not specified the default rate is used.
383 If model is not specified the default model is used.
384 If accel is not specified an accelerator plugin module is not used.
385 This option may be repeated to add more than one vif.
386 Specifying vifs will increase the number of interfaces as needed.""")
388 gopts.var('vtpm', val="instance=INSTANCE,backend=DOM,type=TYPE",
389 fn=append_value, default=[],
390 use="""Add a TPM interface. On the backend side use the given
391 instance as virtual TPM instance. The given number is merely the
392 preferred instance number. The hotplug script will determine
393 which instance number will actually be assigned to the domain.
394 The associtation between virtual machine and the TPM instance
395 number can be found in /etc/xen/vtpm.db. Use the backend in the
396 given domain.
397 The type parameter can be used to select a specific driver type
398 that the VM can use. To prevent a fully virtualized domain (HVM)
399 from being able to access an emulated device model, you may specify
400 'paravirtualized' here.""")
402 gopts.var('access_control', val="policy=POLICY,label=LABEL",
403 fn=append_value, default=[],
404 use="""Add a security label and the security policy reference that defines it.
405 The local ssid reference is calculated when starting/resuming the domain. At
406 this time, the policy is checked against the active policy as well. This way,
407 migrating through save/restore is covered and local labels are automatically
408 created correctly on the system where a domain is started / resumed.""")
410 gopts.var('nics', val="NUM",
411 fn=set_int, default=-1,
412 use="""DEPRECATED. Use empty vif entries instead.
414 Set the number of network interfaces.
415 Use the vif option to define interface parameters, otherwise
416 defaults are used. Specifying vifs will increase the
417 number of interfaces as needed.""")
419 gopts.var('root', val='DEVICE',
420 fn=set_value, default='',
421 use="""Set the root= parameter on the kernel command line.
422 Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""")
424 gopts.var('extra', val="ARGS",
425 fn=set_value, default='',
426 use="Set extra arguments to append to the kernel command line.")
428 gopts.var('ip', val='IPADDR',
429 fn=set_value, default='',
430 use="Set the kernel IP interface address.")
432 gopts.var('gateway', val="IPADDR",
433 fn=set_value, default='',
434 use="Set the kernel IP gateway.")
436 gopts.var('netmask', val="MASK",
437 fn=set_value, default = '',
438 use="Set the kernel IP netmask.")
440 gopts.var('hostname', val="NAME",
441 fn=set_value, default='',
442 use="Set the kernel IP hostname.")
444 gopts.var('interface', val="INTF",
445 fn=set_value, default="eth0",
446 use="Set the kernel IP interface name.")
448 gopts.var('dhcp', val="off|dhcp",
449 fn=set_value, default='off',
450 use="Set the kernel dhcp option.")
452 gopts.var('nfs_server', val="IPADDR",
453 fn=set_value, default=None,
454 use="Set the address of the NFS server for NFS root.")
456 gopts.var('nfs_root', val="PATH",
457 fn=set_value, default=None,
458 use="Set the path of the root NFS directory.")
460 gopts.var('device_model', val='FILE',
461 fn=set_value, default=None,
462 use="Path to device model program.")
464 gopts.var('fda', val='FILE',
465 fn=set_value, default='',
466 use="Path to fda")
468 gopts.var('fdb', val='FILE',
469 fn=set_value, default='',
470 use="Path to fdb")
472 gopts.var('serial', val='FILE',
473 fn=set_value, default='',
474 use="Path to serial or pty or vc")
476 gopts.var('monitor', val='no|yes',
477 fn=set_bool, default=0,
478 use="""Should the device model use monitor?""")
480 gopts.var('localtime', val='no|yes',
481 fn=set_bool, default=0,
482 use="Is RTC set to localtime?")
484 gopts.var('keymap', val='FILE',
485 fn=set_value, default='',
486 use="Set keyboard layout used")
488 gopts.var('usb', val='no|yes',
489 fn=set_bool, default=0,
490 use="Emulate USB devices?")
492 gopts.var('usbdevice', val='NAME',
493 fn=set_value, default='',
494 use="Name of USB device to add?")
496 gopts.var('guest_os_type', val='NAME',
497 fn=set_value, default='default',
498 use="Guest OS type running in HVM")
500 gopts.var('stdvga', val='no|yes',
501 fn=set_bool, default=0,
502 use="Use std vga or cirrhus logic graphics")
504 gopts.var('isa', val='no|yes',
505 fn=set_bool, default=0,
506 use="Simulate an ISA only system?")
508 gopts.var('boot', val="a|b|c|d",
509 fn=set_value, default='c',
510 use="Default boot device")
512 gopts.var('nographic', val='no|yes',
513 fn=set_bool, default=0,
514 use="Should device models use graphics?")
516 gopts.var('soundhw', val='audiodev',
517 fn=set_value, default='',
518 use="Should device models enable audio device?")
520 gopts.var('vnc', val='',
521 fn=set_value, default=None,
522 use="""Should the device model use VNC?""")
524 gopts.var('vncdisplay', val='',
525 fn=set_value, default=None,
526 use="""VNC display to use""")
528 gopts.var('vnclisten', val='',
529 fn=set_value, default=None,
530 use="""Address for VNC server to listen on.""")
532 gopts.var('vncunused', val='',
533 fn=set_bool, default=1,
534 use="""Try to find an unused port for the VNC server.
535 Only valid when vnc=1.""")
537 gopts.var('videoram', val='MEMORY',
538 fn=set_int, default=4,
539 use="""Maximum amount of videoram a guest can allocate
540 for frame buffer.""")
542 gopts.var('sdl', val='',
543 fn=set_value, default=None,
544 use="""Should the device model use SDL?""")
546 gopts.var('opengl', val='',
547 fn=set_value, default=None,
548 use="""Enable\Disable OpenGL""")
550 gopts.var('display', val='DISPLAY',
551 fn=set_value, default=None,
552 use="X11 display to use")
554 gopts.var('xauthority', val='XAUTHORITY',
555 fn=set_value, default=None,
556 use="X11 Authority to use")
558 gopts.var('uuid', val='',
559 fn=set_value, default=None,
560 use="""xenstore UUID (universally unique identifier) to use. One
561 will be randomly generated if this option is not set, just like MAC
562 addresses for virtual network interfaces. This must be a unique
563 value across the entire cluster.""")
565 gopts.var('on_xend_start', val='ignore|start',
566 fn=set_value, default='ignore',
567 use='Action to perform when xend starts')
569 gopts.var('on_xend_stop', val='ignore|shutdown|suspend',
570 fn=set_value, default="ignore",
571 use="""Behaviour when Xend stops:
572 - ignore: Domain continues to run;
573 - shutdown: Domain is shutdown;
574 - suspend: Domain is suspended;
575 """)
577 gopts.var('target', val='TARGET',
578 fn=set_int, default=0,
579 use="Set domain target.")
581 gopts.var('hap', val='HAP',
582 fn=set_int, default=1,
583 use="""Hap status (0=hap is disabled;
584 1=hap is enabled.""")
586 gopts.var('s3_integrity', val='TBOOT_MEMORY_PROTECT',
587 fn=set_int, default=1,
588 use="""Should domain memory integrity be verified during S3?
589 (0=protection is disabled; 1=protection is enabled.""")
591 gopts.var('cpuid', val="IN[,SIN]:eax=EAX,ebx=EBX,ecx=ECX,edx=EDX",
592 fn=append_value, default=[],
593 use="""Cpuid description.""")
595 gopts.var('cpuid_check', val="IN[,SIN]:eax=EAX,ebx=EBX,ecx=ECX,edx=EDX",
596 fn=append_value, default=[],
597 use="""Cpuid check description.""")
599 gopts.var('machine_address_size', val='BITS',
600 fn=set_int, default=None,
601 use="""Maximum machine address size""")
603 gopts.var('suppress_spurious_page_faults', val='yes|no',
604 fn=set_bool, default=None,
605 use="""Do not inject spurious page faults into this guest""")
607 gopts.var('pci_msitranslate', val='TRANSLATE',
608 fn=set_int, default=1,
609 use="""Global PCI MSI-INTx translation flag (0=disable;
610 1=enable.""")
612 gopts.var('pci_power_mgmt', val='POWERMGMT',
613 fn=set_int, default=0,
614 use="""Global PCI Power Management flag (0=disable;1=enable).""")
616 gopts.var('xen_platform_pci', val='0|1',
617 fn=set_int, default=1,
618 use="Is xen_platform_pci used?")
620 gopts.var('superpages', val='0|1',
621 fn=set_int, default=0,
622 use="Create domain with superpages")
624 def err(msg):
625 """Print an error to stderr and exit.
626 """
627 print >>sys.stderr, "Error:", msg
628 sys.exit(1)
631 def warn(msg):
632 """Print a warning to stdout.
633 """
634 print >>sys.stderr, "Warning:", msg
637 def strip(pre, s):
638 """Strip prefix 'pre' if present.
639 """
640 if s.startswith(pre):
641 return s[len(pre):]
642 else:
643 return s
645 def configure_image(vals):
646 """Create the image config.
647 """
648 if not vals.builder:
649 return None
650 config_image = [ vals.builder ]
651 if vals.kernel:
652 config_image.append([ 'kernel', os.path.abspath(vals.kernel) ])
653 if vals.ramdisk:
654 config_image.append([ 'ramdisk', os.path.abspath(vals.ramdisk) ])
655 if vals.loader:
656 config_image.append([ 'loader', os.path.abspath(vals.loader) ])
657 if vals.cmdline_ip:
658 cmdline_ip = strip('ip=', vals.cmdline_ip)
659 config_image.append(['ip', cmdline_ip])
660 if vals.root:
661 cmdline_root = strip('root=', vals.root)
662 config_image.append(['root', cmdline_root])
663 if vals.videoram:
664 config_image.append(['videoram', vals.videoram])
665 if vals.extra:
666 config_image.append(['args', vals.extra])
667 if vals.superpages:
668 config_image.append(['superpages', vals.superpages])
670 if vals.builder == 'hvm':
671 configure_hvm(config_image, vals)
673 if vals.vhpt != 0:
674 config_image.append(['vhpt', vals.vhpt])
676 if vals.machine_address_size:
677 config_image.append(['machine_address_size', vals.machine_address_size])
679 if vals.suppress_spurious_page_faults:
680 config_image.append(['suppress_spurious_page_faults', vals.suppress_spurious_page_faults])
682 return config_image
684 def configure_disks(config_devs, vals):
685 """Create the config for disks (virtual block devices).
686 """
687 for (uname, dev, mode, backend, protocol) in vals.disk:
688 if uname.startswith('tap:'):
689 cls = 'tap'
690 else:
691 cls = 'vbd'
693 config_vbd = [cls,
694 ['uname', uname],
695 ['dev', dev ],
696 ['mode', mode ] ]
697 if backend:
698 config_vbd.append(['backend', backend])
699 if protocol:
700 config_vbd.append(['protocol', protocol])
701 config_devs.append(['device', config_vbd])
703 def configure_pci(config_devs, vals):
704 """Create the config for pci devices.
705 """
706 config_pci = []
707 for (domain, bus, slot, func, vslot, opts) in vals.pci:
708 config_pci_opts = []
709 d = comma_sep_kv_to_dict(opts)
711 def f(k):
712 if k not in ['msitranslate', 'power_mgmt']:
713 err('Invalid pci option: ' + k)
715 config_pci_opts.append([k, d[k]])
717 config_pci_bdf = ['dev', ['domain', domain], ['bus', bus], \
718 ['slot', slot], ['func', func],
719 ['vslot', vslot]]
720 map(f, d.keys())
721 if len(config_pci_opts)>0:
722 config_pci_bdf.append(['opts', config_pci_opts])
724 config_pci.append(config_pci_bdf)
726 if len(config_pci)>0:
727 config_pci.insert(0, 'pci')
728 config_devs.append(['device', config_pci])
730 def configure_vscsis(config_devs, vals):
731 """Create the config for vscsis (virtual scsi devices).
732 """
734 def get_devid(hctl):
735 return int(hctl.split(':')[0])
737 if len(vals.vscsi) == 0:
738 return 0
740 config_scsi = {}
741 pHCTL_list = []
742 vHCTL_list = []
744 scsi_devices = vscsi_util.vscsi_get_scsidevices()
745 for (p_dev, v_dev, backend) in vals.vscsi:
746 (p_hctl, devname) = \
747 vscsi_util.vscsi_get_hctl_and_devname_by(p_dev, scsi_devices)
749 if p_hctl == None:
750 raise ValueError('Cannot find device "%s"' % p_dev)
752 feature_host = 0
753 if v_dev == 'host':
754 if serverType == SERVER_XEN_API:
755 # TODO
756 raise ValueError("SCSI devices assignment by HBA is not implemeted")
757 feature_host = 1
758 scsi_info = []
759 devid = get_devid(p_hctl)
760 for (pHCTL, devname, _, _) in scsi_devices:
761 if get_devid(pHCTL) == devid:
762 scsi_info.append([devid, pHCTL, devname, pHCTL])
763 else:
764 scsi_info = [[get_devid(v_dev), p_hctl, devname, v_dev]]
766 devid_key = scsi_info[0][0]
767 try:
768 config = config_scsi[devid_key]
769 except KeyError:
770 config = {'feature-host': feature_host, 'backend': backend, 'devs': []}
772 devs = config['devs']
773 for (devid, pHCTL, devname, vHCTL) in scsi_info:
774 if pHCTL in pHCTL_list:
775 raise ValueError('The physical device "%s" is already defined' % pHCTL)
776 if vHCTL in vHCTL_list:
777 raise ValueError('The virtual device "%s" is already defined' % vHCTL)
778 pHCTL_list.append(pHCTL)
779 vHCTL_list.append(vHCTL)
780 devs.append(['dev', \
781 ['state', xenbusState['Initialising']], \
782 ['devid', devid], \
783 ['p-dev', pHCTL], \
784 ['p-devname', devname], \
785 ['v-dev', vHCTL] ])
787 if config['feature-host'] != feature_host:
788 raise ValueError('The physical device "%s" cannot define '
789 'because mode is different' % scsi_info[0][1])
790 if config['backend'] != backend:
791 raise ValueError('The physical device "%s" cannot define '
792 'because backend is different' % scsi_info[0][1])
794 config['devs'] = devs
795 config_scsi[devid_key] = config
797 for config in config_scsi.values():
798 device = ['vscsi', ['feature-host', config['feature-host']]]
799 for dev in config['devs']:
800 device.append(dev)
801 if config['backend']:
802 device.append(['backend', config['backend']])
803 config_devs.append(['device', device])
805 def configure_ioports(config_devs, vals):
806 """Create the config for legacy i/o ranges.
807 """
808 for (io_from, io_to) in vals.ioports:
809 config_ioports = ['ioports', ['from', io_from], ['to', io_to]]
810 config_devs.append(['device', config_ioports])
812 def configure_irq(config_devs, vals):
813 """Create the config for irqs.
814 """
815 for irq in vals.irq:
816 config_irq = ['irq', ['irq', irq]]
817 config_devs.append(['device', config_irq])
819 def configure_vfbs(config_devs, vals):
820 for f in vals.vfb:
821 d = comma_sep_kv_to_dict(f)
822 config = ['vfb']
823 #handle the legacy case
824 if d.has_key("type"):
825 d[d['type']] = '1'
826 del d['type']
827 for (k,v) in d.iteritems():
828 if not k in [ 'vnclisten', 'vncunused', 'vncdisplay', 'display',
829 'videoram', 'xauthority', 'sdl', 'vnc', 'vncpasswd',
830 'opengl', 'keymap' ]:
831 err("configuration option %s unknown to vfbs" % k)
832 config.append([k,v])
833 if not d.has_key("keymap"):
834 if vals.keymap:
835 config.append(['keymap',vals.keymap])
836 if not d.has_key("display") and os.environ.has_key("DISPLAY"):
837 config.append(["display", os.environ['DISPLAY']])
838 if not d.has_key("xauthority"):
839 config.append(["xauthority", get_xauthority()])
840 config_devs.append(['device', ['vkbd']])
841 config_devs.append(['device', config])
843 def configure_security(config, vals):
844 """Create the config for ACM security labels.
845 """
846 access_control = vals.access_control
847 num = len(access_control)
848 if num == 1:
849 d = access_control[0]
850 policy = d.get('policy')
851 label = d.get('label')
852 if policy != security.active_policy:
853 err("Security policy (" + policy + ") incompatible with enforced policy ("
854 + security.active_policy + ")." )
855 config_access_control = ['access_control',
856 ['policy', policy],
857 ['label', label] ]
859 security_label = ['security', [ config_access_control ] ]
860 config.append(security_label)
861 elif num > 1:
862 err("VM config error: Multiple access_control definitions!")
864 def configure_mem_prot(config_image, vals):
865 """Create the config for S3 memory integrity verification under tboot.
866 """
867 config_image.append(['s3_integrity', vals.s3_integrity])
869 def configure_vtpm(config_devs, vals):
870 """Create the config for virtual TPM interfaces.
871 """
872 vtpm = vals.vtpm
873 if len(vtpm) > 0:
874 d = vtpm[0]
875 instance = d.get('instance')
876 if instance == "VTPMD":
877 instance = "0"
878 else:
879 if instance != None:
880 try:
881 if int(instance) == 0:
882 err('VM config error: vTPM instance must not be 0.')
883 except ValueError:
884 err('Vm config error: could not parse instance number.')
885 backend = d.get('backend')
886 typ = d.get('type')
887 config_vtpm = ['vtpm']
888 if instance:
889 config_vtpm.append(['pref_instance', instance])
890 if backend:
891 config_vtpm.append(['backend', backend])
892 if typ:
893 config_vtpm.append(['type', type])
894 config_devs.append(['device', config_vtpm])
897 def configure_vifs(config_devs, vals):
898 """Create the config for virtual network interfaces.
899 """
901 vifs = vals.vif
902 vifs_n = len(vifs)
904 if hasattr(vals, 'nics'):
905 if vals.nics > 0:
906 warn("The nics option is deprecated. Please use an empty vif "
907 "entry instead:\n\n vif = [ '' ]\n")
908 for _ in range(vifs_n, vals.nics):
909 vifs.append('')
910 vifs_n = len(vifs)
911 elif vals.nics == 0:
912 warn("The nics option is deprecated. Please remove it.")
914 for c in vifs:
915 d = comma_sep_kv_to_dict(c)
916 config_vif = ['vif']
918 def f(k):
919 if k not in ['backend', 'bridge', 'ip', 'mac', 'script', 'type',
920 'vifname', 'rate', 'model', 'accel',
921 'policy', 'label']:
922 err('Invalid vif option: ' + k)
924 config_vif.append([k, d[k]])
926 map(f, d.keys())
927 config_devs.append(['device', config_vif])
930 def configure_hvm(config_image, vals):
931 """Create the config for HVM devices.
932 """
933 args = [ 'device_model', 'pae', 'vcpus', 'boot', 'fda', 'fdb', 'timer_mode',
934 'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'soundhw',
935 'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten',
936 'sdl', 'display', 'xauthority', 'rtc_timeoffset', 'monitor',
937 'acpi', 'apic', 'usb', 'usbdevice', 'keymap', 'pci', 'hpet',
938 'guest_os_type', 'hap', 'opengl', 'cpuid', 'cpuid_check',
939 'viridian', 'xen_extended_power_mgmt', 'pci_msitranslate',
940 'vpt_align', 'pci_power_mgmt', 'xen_platform_pci' ]
942 for a in args:
943 if a in vals.__dict__ and vals.__dict__[a] is not None:
944 config_image.append([a, vals.__dict__[a]])
945 if vals.vncpasswd is not None:
946 config_image.append(['vncpasswd', vals.vncpasswd])
949 def make_config(vals):
950 """Create the domain configuration.
951 """
953 config = ['vm']
955 def add_conf(n):
956 if hasattr(vals, n):
957 v = getattr(vals, n)
958 if v:
959 config.append([n, v])
961 map(add_conf, ['name', 'memory', 'maxmem', 'shadow_memory',
962 'restart', 'on_poweroff',
963 'on_reboot', 'on_crash', 'vcpus', 'vcpu_avail', 'features',
964 'on_xend_start', 'on_xend_stop', 'target', 'cpuid',
965 'cpuid_check', 'machine_address_size', 'suppress_spurious_page_faults'])
967 if vals.uuid is not None:
968 config.append(['uuid', vals.uuid])
969 if vals.cpu is not None:
970 config.append(['cpu', vals.cpu])
971 if vals.cpus is not None:
972 config.append(['cpus', vals.cpus])
973 if vals.cpu_cap is not None:
974 config.append(['cpu_cap', vals.cpu_cap])
975 if vals.cpu_weight is not None:
976 config.append(['cpu_weight', vals.cpu_weight])
977 if vals.blkif:
978 config.append(['backend', ['blkif']])
979 if vals.netif:
980 config.append(['backend', ['netif']])
981 if vals.tpmif:
982 config.append(['backend', ['tpmif']])
983 if vals.localtime:
984 config.append(['localtime', vals.localtime])
986 config_image = configure_image(vals)
987 if vals.bootloader:
988 if vals.bootloader == "pygrub":
989 vals.bootloader = auxbin.pathTo(vals.bootloader)
991 config.append(['bootloader', vals.bootloader])
992 if vals.bootargs:
993 config.append(['bootloader_args', vals.bootargs])
994 else:
995 if vals.console_autoconnect:
996 config.append(['bootloader_args', ''])
997 else:
998 config.append(['bootloader_args', '-q'])
999 config.append(['image', config_image])
1000 configure_mem_prot(config, vals);
1002 config_devs = []
1003 configure_disks(config_devs, vals)
1004 configure_pci(config_devs, vals)
1005 configure_vscsis(config_devs, vals)
1006 configure_ioports(config_devs, vals)
1007 configure_irq(config_devs, vals)
1008 configure_vifs(config_devs, vals)
1009 configure_vtpm(config_devs, vals)
1010 configure_vfbs(config_devs, vals)
1011 configure_security(config, vals)
1012 config += config_devs
1014 return config
1016 def preprocess_disk(vals):
1017 if not vals.disk: return
1018 disk = []
1019 for v in vals.disk:
1020 d = v.split(',')
1021 n = len(d)
1022 if n == 3:
1023 d.append(None)
1024 d.append(None)
1025 elif n == 4:
1026 d.append(None)
1027 elif n == 5:
1028 pass
1029 else:
1030 err('Invalid disk specifier: ' + v)
1031 disk.append(d)
1032 vals.disk = disk
1034 def preprocess_cpuid(vals, attr_name):
1035 if not vals.cpuid: return
1036 cpuid = {}
1037 for cpuid_input in getattr(vals, attr_name):
1038 input_re = "(0x)?[0-9A-Fa-f]+(,(0x)?[0-9A-Fa-f]+)?"
1039 cpuid_match = re.match(r'(?P<input>%s):(?P<regs>.*)' % \
1040 input_re, cpuid_input)
1041 if cpuid_match != None:
1042 res_cpuid = cpuid_match.groupdict()
1043 input = res_cpuid['input']
1044 regs = res_cpuid['regs'].split(',')
1045 cpuid[input]= {} # New input
1046 for reg in regs:
1047 reg_match = re.match(r"(?P<reg>eax|ebx|ecx|edx)=(?P<val>.*)", reg)
1048 if reg_match == None:
1049 err("cpuid's syntax is (eax|ebx|ecx|edx)=value")
1050 res = reg_match.groupdict()
1051 if (res['val'][:2] != '0x' and len(res['val']) != 32):
1052 err("cpuid: We should specify all the bits " \
1053 "of the register %s for input %s\n"
1054 % (res['reg'], input) )
1055 cpuid[input][res['reg']] = res['val'] # new register
1056 setattr(vals, attr_name, cpuid)
1058 def preprocess_pci(vals):
1059 if not vals.pci: return
1060 pci = []
1061 for pci_dev_str in vals.pci:
1062 pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \
1063 r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \
1064 r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \
1065 r"(?P<func>[0-7])" + \
1066 r"(@(?P<vslot>[01]?[0-9a-fA-F]))?" + \
1067 r"(,(?P<opts>.*))?$", \
1068 pci_dev_str)
1069 if pci_match!=None:
1070 pci_dev_info = pci_match.groupdict('')
1071 if pci_dev_info['domain']=='':
1072 pci_dev_info['domain']='0'
1073 if pci_dev_info['vslot']=='':
1074 pci_dev_info['vslot']="%02x" % AUTO_PHP_SLOT
1075 try:
1076 pci.append( ('0x'+pci_dev_info['domain'], \
1077 '0x'+pci_dev_info['bus'], \
1078 '0x'+pci_dev_info['slot'], \
1079 '0x'+pci_dev_info['func'], \
1080 '0x'+pci_dev_info['vslot'], \
1081 pci_dev_info['opts']))
1082 except IndexError:
1083 err('Error in PCI slot syntax "%s"'%(pci_dev_str))
1084 vals.pci = pci
1086 def preprocess_vscsi(vals):
1087 if not vals.vscsi: return
1088 scsi = []
1089 for scsi_str in vals.vscsi:
1090 d = [tmp.strip() for tmp in scsi_str.split(',')]
1091 n = len(d)
1092 if n == 2:
1093 tmp = d[1].split(':')
1094 if d[1] != 'host' and len(tmp) != 4:
1095 err('vscsi syntax error "%s"' % d[1])
1096 else:
1097 d.append(None)
1098 elif n == 3:
1099 pass
1100 else:
1101 err('vscsi syntax error "%s"' % scsi_str)
1102 scsi.append(d)
1103 vals.vscsi = scsi
1105 def preprocess_ioports(vals):
1106 if not vals.ioports: return
1107 ioports = []
1108 for v in vals.ioports:
1109 d = v.split('-')
1110 if len(d) < 1 or len(d) > 2:
1111 err('Invalid i/o port range specifier: ' + v)
1112 if len(d) == 1:
1113 d.append(d[0])
1114 # Components are in hex: add hex specifier.
1115 hexd = ['0x' + x for x in d]
1116 ioports.append(hexd)
1117 vals.ioports = ioports
1119 def preprocess_irq(vals):
1120 if not vals.irq: return
1121 irq = []
1122 for v in vals.irq:
1123 d = repr(v)
1124 irq.append(d)
1125 vals.irq = irq
1127 def preprocess_vtpm(vals):
1128 if not vals.vtpm: return
1129 vtpms = []
1130 for vtpm in vals.vtpm:
1131 d = {}
1132 a = vtpm.split(',')
1133 for b in a:
1134 (k, v) = b.strip().split('=', 1)
1135 k = k.strip()
1136 v = v.strip()
1137 if k not in ['backend', 'instance']:
1138 err('Invalid vtpm specifier: ' + vtpm)
1139 d[k] = v
1140 vtpms.append(d)
1141 vals.vtpm = vtpms
1143 def preprocess_access_control(vals):
1144 if not vals.access_control:
1145 return
1146 access_controls = []
1147 num = len(vals.access_control)
1148 if num == 1:
1149 access_control = (vals.access_control)[0]
1150 d = {}
1151 a = access_control.split(',')
1152 if len(a) > 2:
1153 err('Too many elements in access_control specifier: ' + access_control)
1154 for b in a:
1155 (k, v) = b.strip().split('=', 1)
1156 k = k.strip()
1157 v = v.strip()
1158 if k not in ['policy','label']:
1159 err('Invalid access_control specifier: ' + access_control)
1160 d[k] = v
1161 access_controls.append(d)
1162 vals.access_control = access_controls
1163 elif num > 1:
1164 err('Multiple access_control definitions.')
1166 def preprocess_ip(vals):
1167 if vals.ip or vals.dhcp != 'off':
1168 dummy_nfs_server = '127.0.255.255'
1169 ip = (vals.ip
1170 + ':' + (vals.nfs_server or dummy_nfs_server)
1171 + ':' + vals.gateway
1172 + ':' + vals.netmask
1173 + ':' + vals.hostname
1174 + ':' + vals.interface
1175 + ':' + vals.dhcp)
1176 else:
1177 ip = ''
1178 vals.cmdline_ip = ip
1180 def preprocess_nfs(vals):
1181 if not vals.nfs_root: return
1182 if not vals.nfs_server:
1183 err('Must set nfs root and nfs server')
1184 nfs = 'nfsroot=' + vals.nfs_server + ':' + vals.nfs_root
1185 vals.extra = nfs + ' ' + vals.extra
1188 def get_host_addr():
1189 host = socket.gethostname()
1190 addr = socket.gethostbyname(host)
1191 return addr
1193 VNC_BASE_PORT = 5500
1195 def choose_vnc_display():
1196 """Try to choose a free vnc display.
1197 """
1198 def netstat_local_ports():
1199 """Run netstat to get a list of the local ports in use.
1200 """
1201 l = os.popen("netstat -nat").readlines()
1202 r = []
1203 # Skip 2 lines of header.
1204 for x in l[2:]:
1205 # Local port is field 3.
1206 y = x.split()[3]
1207 # Field is addr:port, split off the port.
1208 y = y.split(':')[-1]
1209 r.append(int(y))
1210 return r
1212 ports = netstat_local_ports()
1213 for d in range(1, 100):
1214 port = VNC_BASE_PORT + d
1215 if port in ports: continue
1216 return d
1217 return None
1219 def preprocess(vals):
1220 preprocess_disk(vals)
1221 preprocess_pci(vals)
1222 preprocess_vscsi(vals)
1223 preprocess_ioports(vals)
1224 preprocess_ip(vals)
1225 preprocess_irq(vals)
1226 preprocess_nfs(vals)
1227 preprocess_vtpm(vals)
1228 preprocess_access_control(vals)
1229 preprocess_cpuid(vals, 'cpuid')
1230 preprocess_cpuid(vals, 'cpuid_check')
1233 def comma_sep_kv_to_dict(c):
1234 """Convert comma-separated, equals-separated key-value pairs into a
1235 dictionary.
1236 """
1237 d = {}
1238 c = c.strip()
1239 if len(c) > 0:
1240 a = c.split(',')
1241 for b in a:
1242 if b.find('=') == -1:
1243 err("%s should be a pair, separated by an equals sign." % b)
1244 (k, v) = b.split('=', 1)
1245 k = k.strip()
1246 v = v.strip()
1247 d[k] = v
1248 return d
1251 def make_domain(opts, config):
1252 """Create, build and start a domain.
1254 @param opts: options
1255 @param config: configuration
1256 @return: domain id
1257 @rtype: int
1258 """
1260 try:
1261 dominfo = server.xend.domain.create(config)
1262 except xmlrpclib.Fault, ex:
1263 if ex.faultCode == xen.xend.XendClient.ERROR_INVALID_DOMAIN:
1264 err("the domain '%s' does not exist." % ex.faultString)
1265 else:
1266 err("%s" % ex.faultString)
1268 dom = sxp.child_value(dominfo, 'name')
1270 try:
1271 server.xend.domain.waitForDevices(dom)
1272 except xmlrpclib.Fault, ex:
1273 server.xend.domain.destroy(dom)
1274 err("%s" % ex.faultString)
1275 except:
1276 server.xend.domain.destroy(dom)
1277 err("Device creation failed for domain %s" % dom)
1279 if not opts.vals.paused:
1280 try:
1281 server.xend.domain.unpause(dom)
1282 except:
1283 server.xend.domain.destroy(dom)
1284 err("Failed to unpause domain %s" % dom)
1285 domid = int(sxp.child_value(dominfo, 'domid'))
1286 opts.info("Started domain %s (id=%d)" % (dom, domid))
1287 return domid
1290 def get_xauthority():
1291 xauth = os.getenv("XAUTHORITY")
1292 if not xauth:
1293 home = os.getenv("HOME")
1294 if not home:
1295 import posix, pwd
1296 home = pwd.getpwuid(posix.getuid())[5]
1297 xauth = home + "/.Xauthority"
1298 return xauth
1301 def parseCommandLine(argv):
1302 gopts.reset()
1303 args = gopts.parse(argv)
1305 if gopts.vals.help or gopts.vals.help_config:
1306 if gopts.vals.help_config:
1307 print gopts.val_usage()
1308 return (None, None)
1310 if not gopts.vals.display:
1311 gopts.vals.display = os.getenv("DISPLAY")
1313 if not gopts.vals.xauthority:
1314 gopts.vals.xauthority = get_xauthority()
1316 gopts.is_xml = False
1318 # Process remaining args as config variables.
1319 for arg in args:
1320 if '=' in arg:
1321 (var, val) = arg.strip().split('=', 1)
1322 gopts.setvar(var.strip(), val.strip())
1323 if gopts.vals.config:
1324 config = gopts.vals.config
1325 else:
1326 try:
1327 gopts.load_defconfig()
1328 preprocess(gopts.vals)
1329 if not gopts.getopt('name') and gopts.getopt('defconfig'):
1330 gopts.setopt('name', os.path.basename(gopts.getopt('defconfig')))
1331 config = make_config(gopts.vals)
1332 except XMLFileError, ex:
1333 XMLFile = ex.getFile()
1334 gopts.is_xml = True
1335 config = ex.getFile()
1337 return (gopts, config)
1339 def help():
1340 return str(gopts)
1342 def main(argv):
1343 is_xml = False
1345 try:
1346 (opts, config) = parseCommandLine(argv)
1347 except StandardError, ex:
1348 err(str(ex))
1350 if not opts:
1351 return
1353 if not opts.is_xml:
1354 if type(config) == str:
1355 try:
1356 config = sxp.parse(file(config))[0]
1357 except IOError, exn:
1358 raise OptionError("Cannot read file %s: %s" % (config, exn[1]))
1360 if serverType == SERVER_XEN_API:
1361 from xen.xm.xenapi_create import sxp2xml
1362 sxp2xml_inst = sxp2xml()
1363 doc = sxp2xml_inst.convert_sxp_to_xml(config, transient=True)
1365 if opts.vals.dryrun and not opts.is_xml:
1366 SXPPrettyPrint.prettyprint(config)
1368 if opts.vals.xmldryrun and serverType == SERVER_XEN_API:
1369 from xml.dom.ext import PrettyPrint as XMLPrettyPrint
1370 XMLPrettyPrint(doc)
1372 if opts.vals.dryrun or opts.vals.xmldryrun:
1373 return
1375 if opts.vals.console_autoconnect:
1376 do_console(sxp.child_value(config, 'name', -1))
1378 if serverType == SERVER_XEN_API:
1379 from xen.xm.xenapi_create import xenapi_create
1380 xenapi_create_inst = xenapi_create()
1381 if opts.is_xml:
1382 vm_refs = xenapi_create_inst.create(filename = config,
1383 skipdtd = opts.vals.skipdtd)
1384 else:
1385 vm_refs = xenapi_create_inst.create(document = doc,
1386 skipdtd = opts.vals.skipdtd)
1388 map(lambda vm_ref: server.xenapi.VM.start(vm_ref, 0), vm_refs)
1389 elif not opts.is_xml:
1390 dom = make_domain(opts, config)
1392 if opts.vals.vncconsole:
1393 domid = domain_name_to_domid(sxp.child_value(config, 'name', -1))
1394 vncviewer_autopass = getattr(opts.vals,'vncviewer-autopass', False)
1395 console.runVncViewer(domid, vncviewer_autopass, True)
1397 def do_console(domain_name):
1398 cpid = os.fork()
1399 if cpid != 0:
1400 for i in range(10):
1401 # Catch failure of the create process
1402 time.sleep(1)
1403 try:
1404 (p, rv) = os.waitpid(cpid, os.WNOHANG)
1405 except OSError:
1406 # Domain has started cleanly and then exiting,
1407 # the child process used to do this has detached
1408 print("Domain has already finished");
1409 break
1410 (p, rv) = os.waitpid(cpid, os.WNOHANG)
1411 if os.WIFEXITED(rv):
1412 if os.WEXITSTATUS(rv) != 0:
1413 sys.exit(os.WEXITSTATUS(rv))
1414 try:
1415 domid = domain_name_to_domid(domain_name)
1416 console.execConsole(domid)
1417 except:
1418 pass
1419 print("Could not start console\n");
1420 sys.exit(0)
1422 if __name__ == '__main__':
1423 main(sys.argv)