ia64/xen-unstable

view tools/python/xen/xm/create.py @ 19813:b55070edb185

tools: don't require hardcoded firmware path in guest config file

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