ia64/xen-unstable

view tools/python/xen/xm/create.py @ 18289:841b8f64a493

xm: fix trivial typo. s/ciredump-restore/coredump-restart/

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Aug 07 09:05:31 2008 +0100 (2008-08-07)
parents 21dd1fdb73d8
children b5912430e66c
line source
1 #============================================================================
2 # This library is free software; you can redistribute it and/or
3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
4 # License as published by the Free Software Foundation.
5 #
6 # This library is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 # Lesser General Public License for more details.
10 #
11 # You should have received a copy of the GNU Lesser General Public
12 # License along with this library; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 #============================================================================
15 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
16 # Copyright (C) 2005 Nguyen Anh Quynh <aquynh@gmail.com>
17 # Copyright (C) 2005-2006 XenSource Ltd
18 #============================================================================
20 """Domain creation.
21 """
22 import os
23 import os.path
24 import sys
25 import socket
26 import re
27 import time
28 import xmlrpclib
30 from xen.xend import sxp
31 from xen.xend import PrettyPrint as SXPPrettyPrint
32 from xen.xend import osdep
33 import xen.xend.XendClient
34 from xen.xend.XendBootloader import bootloader
35 from xen.util import blkif
36 from xen.util import vscsi_util
37 import xen.util.xsm.xsm as security
38 from xen.xm.main import serverType, SERVER_XEN_API, get_single_vm
39 from xen.util import utils
41 from xen.xm.opts import *
43 from main import server
44 from main import domain_name_to_domid
45 import console
48 gopts = Opts(use="""[options] [vars]
50 Create a domain.
52 Domain creation parameters can be set by command-line switches, from
53 a python configuration script or an SXP config file. See documentation
54 for --defconfig, --config. Configuration variables can be set using
55 VAR=VAL on the command line. For example vmid=3 sets vmid to 3.
57 """)
59 gopts.opt('help', short='h',
60 fn=set_true, default=0,
61 use="Print this help.")
63 gopts.opt('help_config',
64 fn=set_true, default=0,
65 use="Print the available configuration variables (vars) for the "
66 "configuration script.")
68 gopts.opt('quiet', short='q',
69 fn=set_true, default=0,
70 use="Quiet.")
72 gopts.opt('path', val='PATH',
73 fn=set_value, default='.:/etc/xen',
74 use="Search path for configuration scripts. "
75 "The value of PATH is a colon-separated directory list.")
77 gopts.opt('defconfig', short='f', val='FILE',
78 fn=set_value, default='xmdefconfig',
79 use="Use the given Python configuration script."
80 "The configuration script is loaded after arguments have been "
81 "processed. Each command-line option sets a configuration "
82 "variable named after its long option name, and these "
83 "variables are placed in the environment of the script before "
84 "it is loaded. Variables for options that may be repeated have "
85 "list values. Other variables can be set using VAR=VAL on the "
86 "command line. "
87 "After the script is loaded, option values that were not set "
88 "on the command line are replaced by the values set in the script.")
90 gopts.default('defconfig')
92 gopts.opt('config', short='F', val='FILE',
93 fn=set_value, default=None,
94 use="Domain configuration to use (SXP).\n"
95 "SXP is the underlying configuration format used by Xen.\n"
96 "SXP configurations can be hand-written or generated from Python "
97 "configuration scripts, using the -n (dryrun) option to print "
98 "the configuration.")
100 gopts.opt('dryrun', short='n',
101 fn=set_true, default=0,
102 use="Dry run - prints the resulting configuration in SXP but "
103 "does not create the domain.")
105 gopts.opt('xmldryrun', short='x',
106 fn=set_true, default=0,
107 use="XML dry run - prints the resulting configuration in XML but "
108 "does not create the domain.")
110 gopts.opt('skipdtd', short='s',
111 fn=set_true, default=0,
112 use="Skip DTD checking - skips checks on XML before creating. "
113 " Experimental. Can decrease create time." )
115 gopts.opt('paused', short='p',
116 fn=set_true, default=0,
117 use='Leave the domain paused after it is created.')
119 gopts.opt('console_autoconnect', short='c',
120 fn=set_true, default=0,
121 use="Connect to the console after the domain is created.")
123 gopts.opt('vncviewer',
124 fn=set_true, default=0,
125 use="Connect to the VNC display after the domain is created.")
127 gopts.opt('vncviewer-autopass',
128 fn=set_true, default=0,
129 use="Pass VNC password to viewer via stdin and -autopass.")
131 gopts.var('vncpasswd', val='NAME',
132 fn=set_value, default=None,
133 use="Password for VNC console on HVM domain.")
135 gopts.var('vncviewer', val='no|yes',
136 fn=set_bool, default=None,
137 use="Spawn a vncviewer listening for a vnc server in the domain.\n"
138 "The address of the vncviewer is passed to the domain on the "
139 "kernel command line using 'VNC_SERVER=<host>:<port>'. The port "
140 "used by vnc is 5500 + DISPLAY. A display value with a free port "
141 "is chosen if possible.\nOnly valid when vnc=1.\nDEPRECATED")
143 gopts.var('vncconsole', val='no|yes',
144 fn=set_bool, default=None,
145 use="Spawn a vncviewer process for the domain's graphical console.\n"
146 "Only valid when vnc=1.")
148 gopts.var('name', val='NAME',
149 fn=set_value, default=None,
150 use="Domain name. Must be unique.")
152 gopts.var('bootloader', val='FILE',
153 fn=set_value, default=None,
154 use="Path to bootloader.")
156 gopts.var('bootargs', val='NAME',
157 fn=set_value, default=None,
158 use="Arguments to pass to boot loader")
160 gopts.var('bootentry', val='NAME',
161 fn=set_value, default=None,
162 use="DEPRECATED. Entry to boot via boot loader. Use bootargs.")
164 gopts.var('kernel', val='FILE',
165 fn=set_value, default=None,
166 use="Path to kernel image.")
168 gopts.var('ramdisk', val='FILE',
169 fn=set_value, default='',
170 use="Path to ramdisk.")
172 gopts.var('loader', val='FILE',
173 fn=set_value, default='',
174 use="Path to HVM firmware.")
176 gopts.var('features', val='FEATURES',
177 fn=set_value, default='',
178 use="Features to enable in guest kernel")
180 gopts.var('builder', val='FUNCTION',
181 fn=set_value, default='linux',
182 use="Function to use to build the domain.")
184 gopts.var('memory', val='MEMORY',
185 fn=set_int, default=128,
186 use="Domain memory in MB.")
188 gopts.var('maxmem', val='MEMORY',
189 fn=set_int, default=None,
190 use="Maximum domain memory in MB.")
192 gopts.var('shadow_memory', val='MEMORY',
193 fn=set_int, default=0,
194 use="Domain shadow memory in MB.")
196 gopts.var('cpu', val='CPU',
197 fn=set_int, default=None,
198 use="CPU to run the VCPU0 on.")
200 gopts.var('cpus', val='CPUS',
201 fn=set_value, default=None,
202 use="CPUS to run the domain on.")
204 gopts.var('rtc_timeoffset', val='RTC_TIMEOFFSET',
205 fn=set_value, default="0",
206 use="Set RTC offset.")
208 gopts.var('pae', val='PAE',
209 fn=set_int, default=1,
210 use="Disable or enable PAE of HVM domain.")
212 gopts.var('hpet', val='HPET',
213 fn=set_int, default=0,
214 use="Enable virtual high-precision event timer.")
216 gopts.var('timer_mode', val='TIMER_MODE',
217 fn=set_int, default=0,
218 use="""Timer mode (0=delay virtual time when ticks are missed;
219 1=virtual time is always wallclock time.""")
221 gopts.var('acpi', val='ACPI',
222 fn=set_int, default=1,
223 use="Disable or enable ACPI of HVM domain.")
225 gopts.var('apic', val='APIC',
226 fn=set_int, default=1,
227 use="Disable or enable APIC mode.")
229 gopts.var('vcpus', val='VCPUS',
230 fn=set_int, default=1,
231 use="# of Virtual CPUS in domain.")
233 gopts.var('vcpu_avail', val='VCPUS',
234 fn=set_long, default=None,
235 use="Bitmask for virtual CPUs to make available immediately.")
237 gopts.var('vhpt', val='VHPT',
238 fn=set_int, default=0,
239 use="Log2 of domain VHPT size for IA64.")
241 gopts.var('cpu_cap', val='CAP',
242 fn=set_int, default=None,
243 use="""Set the maximum amount of cpu.
244 CAP is a percentage that fixes the maximum amount of cpu.""")
246 gopts.var('cpu_weight', val='WEIGHT',
247 fn=set_int, default=None,
248 use="""Set the cpu time ratio to be allocated to the domain.""")
250 gopts.var('restart', val='onreboot|always|never',
251 fn=set_value, default=None,
252 use="""Deprecated. Use on_poweroff, on_reboot, and on_crash
253 instead.
255 Whether the domain should be restarted on exit.
256 - onreboot: restart on exit with shutdown code reboot
257 - always: always restart on exit, ignore exit code
258 - never: never restart on exit, ignore exit code""")
260 gopts.var('on_poweroff', val='destroy|restart|preserve|rename-restart',
261 fn=set_value, default=None,
262 use="""Behaviour when a domain exits with reason 'poweroff'.
263 - destroy: the domain is cleaned up as normal;
264 - restart: a new domain is started in place of the old one;
265 - preserve: no clean-up is done until the domain is manually
266 destroyed (using xm destroy, for example);
267 - rename-restart: the old domain is not cleaned up, but is
268 renamed and a new domain started in its place.
269 """)
271 gopts.var('on_reboot', val='destroy|restart|preserve|rename-restart',
272 fn=set_value, default=None,
273 use="""Behaviour when a domain exits with reason 'reboot'.
274 - destroy: the domain is cleaned up as normal;
275 - restart: a new domain is started in place of the old one;
276 - preserve: no clean-up is done until the domain is manually
277 destroyed (using xm destroy, for example);
278 - rename-restart: the old domain is not cleaned up, but is
279 renamed and a new domain started in its place.
280 """)
282 gopts.var('on_crash', val='destroy|restart|preserve|rename-restart|coredump-destroy|coredump-restart',
283 fn=set_value, default=None,
284 use="""Behaviour when a domain exits with reason 'crash'.
285 - destroy: the domain is cleaned up as normal;
286 - restart: a new domain is started in place of the old one;
287 - preserve: no clean-up is done until the domain is manually
288 destroyed (using xm destroy, for example);
289 - rename-restart: the old domain is not cleaned up, but is
290 renamed and a new domain started in its place.
291 - coredump-destroy: dump the domain's core, followed by destroy
292 - coredump-restart: dump the domain's core, followed by restart
293 """)
295 gopts.var('blkif', val='no|yes',
296 fn=set_bool, default=0,
297 use="Make the domain a block device backend.")
299 gopts.var('netif', val='no|yes',
300 fn=set_bool, default=0,
301 use="Make the domain a network interface backend.")
303 gopts.var('tpmif', val='no|yes',
304 fn=append_value, default=0,
305 use="Make the domain a TPM interface backend.")
307 gopts.var('disk', val='phy:DEV,VDEV,MODE[,DOM]',
308 fn=append_value, default=[],
309 use="""Add a disk device to a domain. The physical device is DEV,
310 which is exported to the domain as VDEV. The disk is read-only if MODE
311 is 'r', read-write if MODE is 'w'. If DOM is specified it defines the
312 backend driver domain to use for the disk.
313 The option may be repeated to add more than one disk.""")
315 gopts.var('pci', val='BUS:DEV.FUNC',
316 fn=append_value, default=[],
317 use="""Add a PCI device to a domain, using given params (in hex).
318 For example 'pci=c0:02.1'.
319 The option may be repeated to add more than one pci device.""")
321 gopts.var('vscsi', val='PDEV,VDEV[,DOM]',
322 fn=append_value, default=[],
323 use="""Add a SCSI device to a domain. The physical device is PDEV,
324 which is exported to the domain as VDEV(X:X:X:X).""")
326 gopts.var('ioports', val='FROM[-TO]',
327 fn=append_value, default=[],
328 use="""Add a legacy I/O range to a domain, using given params (in hex).
329 For example 'ioports=02f8-02ff'.
330 The option may be repeated to add more than one i/o range.""")
332 gopts.var('irq', val='IRQ',
333 fn=append_value, default=[],
334 use="""Add an IRQ (interrupt line) to a domain.
335 For example 'irq=7'.
336 This option may be repeated to add more than one IRQ.""")
338 gopts.var('vfb', val="type={vnc,sdl},vncunused=1,vncdisplay=N,vnclisten=ADDR,display=DISPLAY,xauthority=XAUTHORITY,vncpasswd=PASSWORD,opengl=1,keymap=FILE",
339 fn=append_value, default=[],
340 use="""Make the domain a framebuffer backend.
341 The backend type should be either sdl or vnc.
342 For type=vnc, connect an external vncviewer. The server will listen
343 on ADDR (default 127.0.0.1) on port N+5900. N defaults to the
344 domain id. If vncunused=1, the server will try to find an arbitrary
345 unused port above 5900. vncpasswd overrides the XenD configured
346 default password.
347 For type=sdl, a viewer will be started automatically using the
348 given DISPLAY and XAUTHORITY, which default to the current user's
349 ones. OpenGL will be used by default unless opengl is set to 0.
350 keymap overrides the XendD configured default layout file.""")
352 gopts.var('vif', val="type=TYPE,mac=MAC,bridge=BRIDGE,ip=IPADDR,script=SCRIPT," + \
353 "backend=DOM,vifname=NAME,rate=RATE,model=MODEL,accel=ACCEL",
354 fn=append_value, default=[],
355 use="""Add a network interface with the given MAC address and bridge.
356 The vif is configured by calling the given configuration script.
357 If type is not specified, default is netfront.
358 If mac is not specified a random MAC address is used.
359 If not specified then the network backend chooses it's own MAC address.
360 If bridge is not specified the first bridge found is used.
361 If script is not specified the default script is used.
362 If backend is not specified the default backend driver domain is used.
363 If vifname is not specified the backend virtual interface will have name vifD.N
364 where D is the domain id and N is the interface id.
365 If rate is not specified the default rate is used.
366 If model is not specified the default model is used.
367 If accel is not specified an accelerator plugin module is not used.
368 This option may be repeated to add more than one vif.
369 Specifying vifs will increase the number of interfaces as needed.""")
371 gopts.var('vtpm', val="instance=INSTANCE,backend=DOM,type=TYPE",
372 fn=append_value, default=[],
373 use="""Add a TPM interface. On the backend side use the given
374 instance as virtual TPM instance. The given number is merely the
375 preferred instance number. The hotplug script will determine
376 which instance number will actually be assigned to the domain.
377 The associtation between virtual machine and the TPM instance
378 number can be found in /etc/xen/vtpm.db. Use the backend in the
379 given domain.
380 The type parameter can be used to select a specific driver type
381 that the VM can use. To prevent a fully virtualized domain (HVM)
382 from being able to access an emulated device model, you may specify
383 'paravirtualized' here.""")
385 gopts.var('access_control', val="policy=POLICY,label=LABEL",
386 fn=append_value, default=[],
387 use="""Add a security label and the security policy reference that defines it.
388 The local ssid reference is calculated when starting/resuming the domain. At
389 this time, the policy is checked against the active policy as well. This way,
390 migrating through save/restore is covered and local labels are automatically
391 created correctly on the system where a domain is started / resumed.""")
393 gopts.var('nics', val="NUM",
394 fn=set_int, default=-1,
395 use="""DEPRECATED. Use empty vif entries instead.
397 Set the number of network interfaces.
398 Use the vif option to define interface parameters, otherwise
399 defaults are used. Specifying vifs will increase the
400 number of interfaces as needed.""")
402 gopts.var('root', val='DEVICE',
403 fn=set_value, default='',
404 use="""Set the root= parameter on the kernel command line.
405 Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""")
407 gopts.var('extra', val="ARGS",
408 fn=set_value, default='',
409 use="Set extra arguments to append to the kernel command line.")
411 gopts.var('ip', val='IPADDR',
412 fn=set_value, default='',
413 use="Set the kernel IP interface address.")
415 gopts.var('gateway', val="IPADDR",
416 fn=set_value, default='',
417 use="Set the kernel IP gateway.")
419 gopts.var('netmask', val="MASK",
420 fn=set_value, default = '',
421 use="Set the kernel IP netmask.")
423 gopts.var('hostname', val="NAME",
424 fn=set_value, default='',
425 use="Set the kernel IP hostname.")
427 gopts.var('interface', val="INTF",
428 fn=set_value, default="eth0",
429 use="Set the kernel IP interface name.")
431 gopts.var('dhcp', val="off|dhcp",
432 fn=set_value, default='off',
433 use="Set the kernel dhcp option.")
435 gopts.var('nfs_server', val="IPADDR",
436 fn=set_value, default=None,
437 use="Set the address of the NFS server for NFS root.")
439 gopts.var('nfs_root', val="PATH",
440 fn=set_value, default=None,
441 use="Set the path of the root NFS directory.")
443 gopts.var('device_model', val='FILE',
444 fn=set_value, default=None,
445 use="Path to device model program.")
447 gopts.var('fda', val='FILE',
448 fn=set_value, default='',
449 use="Path to fda")
451 gopts.var('fdb', val='FILE',
452 fn=set_value, default='',
453 use="Path to fdb")
455 gopts.var('serial', val='FILE',
456 fn=set_value, default='',
457 use="Path to serial or pty or vc")
459 gopts.var('monitor', val='no|yes',
460 fn=set_bool, default=0,
461 use="""Should the device model use monitor?""")
463 gopts.var('localtime', val='no|yes',
464 fn=set_bool, default=0,
465 use="Is RTC set to localtime?")
467 gopts.var('keymap', val='FILE',
468 fn=set_value, default='',
469 use="Set keyboard layout used")
471 gopts.var('usb', val='no|yes',
472 fn=set_bool, default=0,
473 use="Emulate USB devices?")
475 gopts.var('usbdevice', val='NAME',
476 fn=set_value, default='',
477 use="Name of USB device to add?")
479 gopts.var('guest_os_type', val='NAME',
480 fn=set_value, default='default',
481 use="Guest OS type running in HVM")
483 gopts.var('stdvga', val='no|yes',
484 fn=set_bool, default=0,
485 use="Use std vga or cirrhus logic graphics")
487 gopts.var('isa', val='no|yes',
488 fn=set_bool, default=0,
489 use="Simulate an ISA only system?")
491 gopts.var('boot', val="a|b|c|d",
492 fn=set_value, default='c',
493 use="Default boot device")
495 gopts.var('nographic', val='no|yes',
496 fn=set_bool, default=0,
497 use="Should device models use graphics?")
499 gopts.var('soundhw', val='audiodev',
500 fn=set_value, default='',
501 use="Should device models enable audio device?")
503 gopts.var('vnc', val='',
504 fn=set_value, default=None,
505 use="""Should the device model use VNC?""")
507 gopts.var('vncdisplay', val='',
508 fn=set_value, default=None,
509 use="""VNC display to use""")
511 gopts.var('vnclisten', val='',
512 fn=set_value, default=None,
513 use="""Address for VNC server to listen on.""")
515 gopts.var('vncunused', val='',
516 fn=set_bool, default=1,
517 use="""Try to find an unused port for the VNC server.
518 Only valid when vnc=1.""")
520 gopts.var('videoram', val='',
521 fn=set_value, default=None,
522 use="""Maximum amount of videoram PV guest can allocate
523 for frame buffer.""")
525 gopts.var('sdl', val='',
526 fn=set_value, default=None,
527 use="""Should the device model use SDL?""")
529 gopts.var('opengl', val='',
530 fn=set_value, default=None,
531 use="""Enable\Disable OpenGL""")
533 gopts.var('display', val='DISPLAY',
534 fn=set_value, default=None,
535 use="X11 display to use")
537 gopts.var('xauthority', val='XAUTHORITY',
538 fn=set_value, default=None,
539 use="X11 Authority to use")
541 gopts.var('uuid', val='',
542 fn=set_value, default=None,
543 use="""xenstore UUID (universally unique identifier) to use. One
544 will be randomly generated if this option is not set, just like MAC
545 addresses for virtual network interfaces. This must be a unique
546 value across the entire cluster.""")
548 gopts.var('on_xend_start', val='ignore|start',
549 fn=set_value, default='ignore',
550 use='Action to perform when xend starts')
552 gopts.var('on_xend_stop', val='ignore|shutdown|suspend',
553 fn=set_value, default="ignore",
554 use="""Behaviour when Xend stops:
555 - ignore: Domain continues to run;
556 - shutdown: Domain is shutdown;
557 - suspend: Domain is suspended;
558 """)
560 gopts.var('target', val='TARGET',
561 fn=set_int, default=0,
562 use="Set domain target.")
564 gopts.var('hap', val='HAP',
565 fn=set_int, default=1,
566 use="""Hap status (0=hap is disabled;
567 1=hap is enabled.""")
569 gopts.var('cpuid', val="IN[,SIN]:eax=EAX,ebx=EBX,exc=ECX,edx=EDX",
570 fn=append_value, default=[],
571 use="""Cpuid description.""")
573 gopts.var('cpuid_check', val="IN[,SIN]:eax=EAX,ebx=EBX,exc=ECX,edx=EDX",
574 fn=append_value, default=[],
575 use="""Cpuid check description.""")
577 gopts.var('machine_address_size', val='BITS',
578 fn=set_int, default=None,
579 use="""Maximum machine address size""")
581 def err(msg):
582 """Print an error to stderr and exit.
583 """
584 print >>sys.stderr, "Error:", msg
585 sys.exit(1)
588 def warn(msg):
589 """Print a warning to stdout.
590 """
591 print >>sys.stderr, "Warning:", msg
594 def strip(pre, s):
595 """Strip prefix 'pre' if present.
596 """
597 if s.startswith(pre):
598 return s[len(pre):]
599 else:
600 return s
602 def configure_image(vals):
603 """Create the image config.
604 """
605 if not vals.builder:
606 return None
607 config_image = [ vals.builder ]
608 if vals.kernel:
609 config_image.append([ 'kernel', os.path.abspath(vals.kernel) ])
610 if vals.ramdisk:
611 config_image.append([ 'ramdisk', os.path.abspath(vals.ramdisk) ])
612 if vals.loader:
613 config_image.append([ 'loader', os.path.abspath(vals.loader) ])
614 if vals.cmdline_ip:
615 cmdline_ip = strip('ip=', vals.cmdline_ip)
616 config_image.append(['ip', cmdline_ip])
617 if vals.root:
618 cmdline_root = strip('root=', vals.root)
619 config_image.append(['root', cmdline_root])
620 if vals.extra:
621 config_image.append(['args', vals.extra])
623 if vals.builder == 'hvm':
624 configure_hvm(config_image, vals)
626 if vals.vhpt != 0:
627 config_image.append(['vhpt', vals.vhpt])
629 if vals.machine_address_size:
630 config_image.append(['machine_address_size', vals.machine_address_size])
632 return config_image
634 def configure_disks(config_devs, vals):
635 """Create the config for disks (virtual block devices).
636 """
637 for (uname, dev, mode, backend, protocol) in vals.disk:
638 if uname.startswith('tap:'):
639 cls = 'tap'
640 else:
641 cls = 'vbd'
643 config_vbd = [cls,
644 ['uname', uname],
645 ['dev', dev ],
646 ['mode', mode ] ]
647 if backend:
648 config_vbd.append(['backend', backend])
649 if protocol:
650 config_vbd.append(['protocol', protocol])
651 config_devs.append(['device', config_vbd])
653 def configure_pci(config_devs, vals):
654 """Create the config for pci devices.
655 """
656 config_pci = []
657 for (domain, bus, slot, func) in vals.pci:
658 config_pci.append(['dev', ['domain', domain], ['bus', bus], \
659 ['slot', slot], ['func', func]])
661 if len(config_pci)>0:
662 config_pci.insert(0, 'pci')
663 config_devs.append(['device', config_pci])
665 def vscsi_convert_sxp_to_dict(dev_sxp):
666 dev_dict = {}
667 for opt_val in dev_sxp[1:]:
668 try:
669 opt, val = opt_val
670 dev_dict[opt] = val
671 except TypeError:
672 pass
673 return dev_dict
675 def vscsi_lookup_devid(devlist, req_devid):
676 if len(devlist) == 0:
677 return 0
678 else:
679 for devid, backend in devlist:
680 if devid == req_devid:
681 return 1
682 return 0
684 def configure_vscsis(config_devs, vals):
685 """Create the config for vscsis (virtual scsi devices).
686 """
687 devidlist = []
688 config_scsi = []
689 if len(vals.vscsi) == 0:
690 return 0
692 scsi_devices = vscsi_util.vscsi_get_scsidevices()
693 for (p_dev, v_dev, backend) in vals.vscsi:
694 tmp = p_dev.split(':')
695 if len(tmp) == 4:
696 (p_hctl, block) = vscsi_util._vscsi_hctl_block(p_dev, scsi_devices)
697 else:
698 (p_hctl, block) = vscsi_util._vscsi_block_scsiid_to_hctl(p_dev, scsi_devices)
700 if p_hctl == None:
701 raise ValueError("Cannot find device \"%s\"" % p_dev)
703 for config in config_scsi:
704 dev = vscsi_convert_sxp_to_dict(config)
705 if dev['v-dev'] == v_dev:
706 raise ValueError('The virtual device "%s" is already defined' % v_dev)
708 v_hctl = v_dev.split(':')
709 devid = int(v_hctl[0])
710 config_scsi.append(['dev', \
711 ['state', 'Initialising'], \
712 ['devid', devid], \
713 ['p-dev', p_hctl], \
714 ['p-devname', block], \
715 ['v-dev', v_dev] ])
717 if vscsi_lookup_devid(devidlist, devid) == 0:
718 devidlist.append([devid, backend])
720 for devid, backend in devidlist:
721 tmp = []
722 for config in config_scsi:
723 dev = vscsi_convert_sxp_to_dict(config)
724 if dev['devid'] == devid:
725 tmp.append(config)
727 tmp.insert(0, 'vscsi')
728 if backend:
729 tmp.append(['backend', backend])
730 config_devs.append(['device', tmp])
732 def configure_ioports(config_devs, vals):
733 """Create the config for legacy i/o ranges.
734 """
735 for (io_from, io_to) in vals.ioports:
736 config_ioports = ['ioports', ['from', io_from], ['to', io_to]]
737 config_devs.append(['device', config_ioports])
739 def configure_irq(config_devs, vals):
740 """Create the config for irqs.
741 """
742 for irq in vals.irq:
743 config_irq = ['irq', ['irq', irq]]
744 config_devs.append(['device', config_irq])
746 def configure_vfbs(config_devs, vals):
747 for f in vals.vfb:
748 d = comma_sep_kv_to_dict(f)
749 config = ['vfb']
750 if not d.has_key("type"):
751 d['type'] = 'sdl'
752 for (k,v) in d.iteritems():
753 if not k in [ 'vnclisten', 'vncunused', 'vncdisplay', 'display',
754 'videoram', 'xauthority', 'type', 'vncpasswd',
755 'opengl', 'keymap' ]:
756 err("configuration option %s unknown to vfbs" % k)
757 config.append([k,v])
758 if not d.has_key("keymap"):
759 if vals.keymap:
760 config.append(['keymap',vals.keymap])
761 if not d.has_key("display") and os.environ.has_key("DISPLAY"):
762 config.append(["display", os.environ['DISPLAY']])
763 if not d.has_key("xauthority"):
764 config.append(["xauthority", get_xauthority()])
765 config_devs.append(['device', ['vkbd']])
766 config_devs.append(['device', config])
768 def configure_security(config, vals):
769 """Create the config for ACM security labels.
770 """
771 access_control = vals.access_control
772 num = len(access_control)
773 if num == 1:
774 d = access_control[0]
775 policy = d.get('policy')
776 label = d.get('label')
777 if policy != security.active_policy:
778 err("Security policy (" + policy + ") incompatible with enforced policy ("
779 + security.active_policy + ")." )
780 config_access_control = ['access_control',
781 ['policy', policy],
782 ['label', label] ]
784 security_label = ['security', [ config_access_control ] ]
785 config.append(security_label)
786 elif num > 1:
787 err("VM config error: Multiple access_control definitions!")
790 def configure_vtpm(config_devs, vals):
791 """Create the config for virtual TPM interfaces.
792 """
793 vtpm = vals.vtpm
794 if len(vtpm) > 0:
795 d = vtpm[0]
796 instance = d.get('instance')
797 if instance == "VTPMD":
798 instance = "0"
799 else:
800 if instance != None:
801 try:
802 if int(instance) == 0:
803 err('VM config error: vTPM instance must not be 0.')
804 except ValueError:
805 err('Vm config error: could not parse instance number.')
806 backend = d.get('backend')
807 typ = d.get('type')
808 config_vtpm = ['vtpm']
809 if instance:
810 config_vtpm.append(['pref_instance', instance])
811 if backend:
812 config_vtpm.append(['backend', backend])
813 if typ:
814 config_vtpm.append(['type', type])
815 config_devs.append(['device', config_vtpm])
818 def configure_vifs(config_devs, vals):
819 """Create the config for virtual network interfaces.
820 """
822 vifs = vals.vif
823 vifs_n = len(vifs)
825 if hasattr(vals, 'nics'):
826 if vals.nics > 0:
827 warn("The nics option is deprecated. Please use an empty vif "
828 "entry instead:\n\n vif = [ '' ]\n")
829 for _ in range(vifs_n, vals.nics):
830 vifs.append('')
831 vifs_n = len(vifs)
832 elif vals.nics == 0:
833 warn("The nics option is deprecated. Please remove it.")
835 for c in vifs:
836 d = comma_sep_kv_to_dict(c)
837 config_vif = ['vif']
839 def f(k):
840 if k not in ['backend', 'bridge', 'ip', 'mac', 'script', 'type',
841 'vifname', 'rate', 'model', 'accel',
842 'policy', 'label']:
843 err('Invalid vif option: ' + k)
845 config_vif.append([k, d[k]])
847 map(f, d.keys())
848 config_devs.append(['device', config_vif])
851 def configure_hvm(config_image, vals):
852 """Create the config for HVM devices.
853 """
854 args = [ 'device_model', 'pae', 'vcpus', 'boot', 'fda', 'fdb', 'timer_mode',
855 'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'soundhw',
856 'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten',
857 'sdl', 'display', 'xauthority', 'rtc_timeoffset', 'monitor',
858 'acpi', 'apic', 'usb', 'usbdevice', 'keymap', 'pci', 'hpet',
859 'guest_os_type', 'hap', 'opengl', 'cpuid', 'cpuid_check']
861 for a in args:
862 if a in vals.__dict__ and vals.__dict__[a] is not None:
863 config_image.append([a, vals.__dict__[a]])
864 if vals.vncpasswd is not None:
865 config_image.append(['vncpasswd', vals.vncpasswd])
868 def make_config(vals):
869 """Create the domain configuration.
870 """
872 config = ['vm']
874 def add_conf(n):
875 if hasattr(vals, n):
876 v = getattr(vals, n)
877 if v:
878 config.append([n, v])
880 map(add_conf, ['name', 'memory', 'maxmem', 'shadow_memory',
881 'restart', 'on_poweroff',
882 'on_reboot', 'on_crash', 'vcpus', 'vcpu_avail', 'features',
883 'on_xend_start', 'on_xend_stop', 'target', 'cpuid',
884 'cpuid_check', 'machine_address_size'])
886 if vals.uuid is not None:
887 config.append(['uuid', vals.uuid])
888 if vals.cpu is not None:
889 config.append(['cpu', vals.cpu])
890 if vals.cpus is not None:
891 config.append(['cpus', vals.cpus])
892 if vals.cpu_cap is not None:
893 config.append(['cpu_cap', vals.cpu_cap])
894 if vals.cpu_weight is not None:
895 config.append(['cpu_weight', vals.cpu_weight])
896 if vals.blkif:
897 config.append(['backend', ['blkif']])
898 if vals.netif:
899 config.append(['backend', ['netif']])
900 if vals.tpmif:
901 config.append(['backend', ['tpmif']])
902 if vals.localtime:
903 config.append(['localtime', vals.localtime])
905 config_image = configure_image(vals)
906 if vals.bootloader:
907 if vals.bootloader == "pygrub":
908 vals.bootloader = osdep.pygrub_path
910 config.append(['bootloader', vals.bootloader])
911 if vals.bootargs:
912 config.append(['bootloader_args', vals.bootargs])
913 else:
914 if vals.console_autoconnect:
915 config.append(['bootloader_args', ''])
916 else:
917 config.append(['bootloader_args', '-q'])
918 config.append(['image', config_image])
920 config_devs = []
921 configure_disks(config_devs, vals)
922 configure_pci(config_devs, vals)
923 configure_vscsis(config_devs, vals)
924 configure_ioports(config_devs, vals)
925 configure_irq(config_devs, vals)
926 configure_vifs(config_devs, vals)
927 configure_vtpm(config_devs, vals)
928 configure_vfbs(config_devs, vals)
929 configure_security(config, vals)
930 config += config_devs
932 return config
934 def preprocess_disk(vals):
935 if not vals.disk: return
936 disk = []
937 for v in vals.disk:
938 d = v.split(',')
939 n = len(d)
940 if n == 3:
941 d.append(None)
942 d.append(None)
943 elif n == 4:
944 d.append(None)
945 elif n == 5:
946 pass
947 else:
948 err('Invalid disk specifier: ' + v)
949 disk.append(d)
950 vals.disk = disk
952 def preprocess_cpuid(vals, attr_name):
953 if not vals.cpuid: return
954 cpuid = {}
955 for cpuid_input in getattr(vals, attr_name):
956 input_re = "(0x)?[0-9A-Fa-f]+(,(0x)?[0-9A-Fa-f]+)?"
957 cpuid_match = re.match(r'(?P<input>%s):(?P<regs>.*)' % \
958 input_re, cpuid_input)
959 if cpuid_match != None:
960 res_cpuid = cpuid_match.groupdict()
961 input = res_cpuid['input']
962 regs = res_cpuid['regs'].split(',')
963 cpuid[input]= {} # New input
964 for reg in regs:
965 reg_match = re.match(r"(?P<reg>eax|ebx|ecx|edx)=(?P<val>.*)", reg)
966 if reg_match == None:
967 err("cpuid's syntax is (eax|ebx|ecx|edx)=value")
968 res = reg_match.groupdict()
969 if (res['val'][:2] != '0x' and len(res['val']) != 32):
970 err("cpuid: We should specify all the bits " \
971 "of the register %s for input %s\n"
972 % (res['reg'], input) )
973 cpuid[input][res['reg']] = res['val'] # new register
974 setattr(vals, attr_name, cpuid)
976 def preprocess_pci(vals):
977 if not vals.pci: return
978 pci = []
979 for pci_dev_str in vals.pci:
980 pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \
981 r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \
982 r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \
983 r"(?P<func>[0-7])$", pci_dev_str)
984 if pci_match!=None:
985 pci_dev_info = pci_match.groupdict('0')
986 try:
987 pci.append( ('0x'+pci_dev_info['domain'], \
988 '0x'+pci_dev_info['bus'], \
989 '0x'+pci_dev_info['slot'], \
990 '0x'+pci_dev_info['func']))
991 except IndexError:
992 err('Error in PCI slot syntax "%s"'%(pci_dev_str))
993 vals.pci = pci
995 def preprocess_vscsi(vals):
996 if not vals.vscsi: return
997 scsi = []
998 for scsi_str in vals.vscsi:
999 d = scsi_str.split(',')
1000 n = len(d)
1001 if n == 2:
1002 tmp = d[1].split(':')
1003 if len(tmp) != 4:
1004 err('vscsi syntax error "%s"' % d[1])
1005 else:
1006 d.append(None)
1007 elif n == 3:
1008 pass
1009 else:
1010 err('vscsi syntax error "%s"' % scsi_str)
1011 scsi.append(d)
1012 vals.vscsi = scsi
1014 def preprocess_ioports(vals):
1015 if not vals.ioports: return
1016 ioports = []
1017 for v in vals.ioports:
1018 d = v.split('-')
1019 if len(d) < 1 or len(d) > 2:
1020 err('Invalid i/o port range specifier: ' + v)
1021 if len(d) == 1:
1022 d.append(d[0])
1023 # Components are in hex: add hex specifier.
1024 hexd = ['0x' + x for x in d]
1025 ioports.append(hexd)
1026 vals.ioports = ioports
1028 def preprocess_vtpm(vals):
1029 if not vals.vtpm: return
1030 vtpms = []
1031 for vtpm in vals.vtpm:
1032 d = {}
1033 a = vtpm.split(',')
1034 for b in a:
1035 (k, v) = b.strip().split('=', 1)
1036 k = k.strip()
1037 v = v.strip()
1038 if k not in ['backend', 'instance']:
1039 err('Invalid vtpm specifier: ' + vtpm)
1040 d[k] = v
1041 vtpms.append(d)
1042 vals.vtpm = vtpms
1044 def preprocess_access_control(vals):
1045 if not vals.access_control:
1046 return
1047 access_controls = []
1048 num = len(vals.access_control)
1049 if num == 1:
1050 access_control = (vals.access_control)[0]
1051 d = {}
1052 a = access_control.split(',')
1053 if len(a) > 2:
1054 err('Too many elements in access_control specifier: ' + access_control)
1055 for b in a:
1056 (k, v) = b.strip().split('=', 1)
1057 k = k.strip()
1058 v = v.strip()
1059 if k not in ['policy','label']:
1060 err('Invalid access_control specifier: ' + access_control)
1061 d[k] = v
1062 access_controls.append(d)
1063 vals.access_control = access_controls
1064 elif num > 1:
1065 err('Multiple access_control definitions.')
1067 def preprocess_ip(vals):
1068 if vals.ip or vals.dhcp != 'off':
1069 dummy_nfs_server = '127.0.255.255'
1070 ip = (vals.ip
1071 + ':' + (vals.nfs_server or dummy_nfs_server)
1072 + ':' + vals.gateway
1073 + ':' + vals.netmask
1074 + ':' + vals.hostname
1075 + ':' + vals.interface
1076 + ':' + vals.dhcp)
1077 else:
1078 ip = ''
1079 vals.cmdline_ip = ip
1081 def preprocess_nfs(vals):
1082 if not vals.nfs_root: return
1083 if not vals.nfs_server:
1084 err('Must set nfs root and nfs server')
1085 nfs = 'nfsroot=' + vals.nfs_server + ':' + vals.nfs_root
1086 vals.extra = nfs + ' ' + vals.extra
1089 def get_host_addr():
1090 host = socket.gethostname()
1091 addr = socket.gethostbyname(host)
1092 return addr
1094 VNC_BASE_PORT = 5500
1096 def choose_vnc_display():
1097 """Try to choose a free vnc display.
1098 """
1099 def netstat_local_ports():
1100 """Run netstat to get a list of the local ports in use.
1101 """
1102 l = os.popen("netstat -nat").readlines()
1103 r = []
1104 # Skip 2 lines of header.
1105 for x in l[2:]:
1106 # Local port is field 3.
1107 y = x.split()[3]
1108 # Field is addr:port, split off the port.
1109 y = y.split(':')[-1]
1110 r.append(int(y))
1111 return r
1113 ports = netstat_local_ports()
1114 for d in range(1, 100):
1115 port = VNC_BASE_PORT + d
1116 if port in ports: continue
1117 return d
1118 return None
1119 vncpid = None
1121 def spawn_vnc(display):
1122 """Spawns a vncviewer that listens on the specified display. On success,
1123 returns the port that the vncviewer is listening on and sets the global
1124 vncpid. On failure, returns 0. Note that vncviewer is daemonized.
1125 """
1126 vncargs = (["vncviewer", "-log", "*:stdout:0",
1127 "-listen", "%d" % (VNC_BASE_PORT + display) ])
1128 global vncpid
1129 vncpid = utils.daemonize("vncviewer", vncargs)
1130 if vncpid == 0:
1131 return 0
1133 return VNC_BASE_PORT + display
1135 def preprocess_vnc(vals):
1136 """If vnc was specified, spawn a vncviewer in listen mode
1137 and pass its address to the domain on the kernel command line.
1138 """
1139 if vals.dryrun: return
1140 if vals.vncviewer:
1141 vnc_display = choose_vnc_display()
1142 if not vnc_display:
1143 warn("No free vnc display")
1144 return
1145 print 'VNC=', vnc_display
1146 vnc_port = spawn_vnc(vnc_display)
1147 if vnc_port > 0:
1148 vnc_host = get_host_addr()
1149 vnc = 'VNC_VIEWER=%s:%d' % (vnc_host, vnc_port)
1150 vals.extra = vnc + ' ' + vals.extra
1152 def preprocess(vals):
1153 preprocess_disk(vals)
1154 preprocess_pci(vals)
1155 preprocess_vscsi(vals)
1156 preprocess_ioports(vals)
1157 preprocess_ip(vals)
1158 preprocess_nfs(vals)
1159 preprocess_vnc(vals)
1160 preprocess_vtpm(vals)
1161 preprocess_access_control(vals)
1162 preprocess_cpuid(vals, 'cpuid')
1163 preprocess_cpuid(vals, 'cpuid_check')
1166 def comma_sep_kv_to_dict(c):
1167 """Convert comma-separated, equals-separated key-value pairs into a
1168 dictionary.
1169 """
1170 d = {}
1171 c = c.strip()
1172 if len(c) > 0:
1173 a = c.split(',')
1174 for b in a:
1175 if b.find('=') == -1:
1176 err("%s should be a pair, separated by an equals sign." % b)
1177 (k, v) = b.split('=', 1)
1178 k = k.strip()
1179 v = v.strip()
1180 d[k] = v
1181 return d
1184 def make_domain(opts, config):
1185 """Create, build and start a domain.
1187 @param opts: options
1188 @param config: configuration
1189 @return: domain id
1190 @rtype: int
1191 """
1193 try:
1194 dominfo = server.xend.domain.create(config)
1195 except xmlrpclib.Fault, ex:
1196 import signal
1197 if vncpid:
1198 os.kill(vncpid, signal.SIGKILL)
1199 if ex.faultCode == xen.xend.XendClient.ERROR_INVALID_DOMAIN:
1200 err("the domain '%s' does not exist." % ex.faultString)
1201 else:
1202 err("%s" % ex.faultString)
1203 except Exception, ex:
1204 # main.py has good error messages that let the user know what failed.
1205 # unless the error is a create.py specific thing, it should be handled
1206 # at main. The purpose of this general-case 'Exception' handler is to
1207 # clean up create.py specific processes/data but since create.py does
1208 # not know what to do with the error, it should pass it up.
1209 import signal
1210 if vncpid:
1211 os.kill(vncpid, signal.SIGKILL)
1212 raise
1214 dom = sxp.child_value(dominfo, 'name')
1216 try:
1217 server.xend.domain.waitForDevices(dom)
1218 except xmlrpclib.Fault, ex:
1219 server.xend.domain.destroy(dom)
1220 err("%s" % ex.faultString)
1221 except:
1222 server.xend.domain.destroy(dom)
1223 err("Device creation failed for domain %s" % dom)
1225 if not opts.vals.paused:
1226 try:
1227 server.xend.domain.unpause(dom)
1228 except:
1229 server.xend.domain.destroy(dom)
1230 err("Failed to unpause domain %s" % dom)
1231 opts.info("Started domain %s" % (dom))
1232 return int(sxp.child_value(dominfo, 'domid'))
1235 def get_xauthority():
1236 xauth = os.getenv("XAUTHORITY")
1237 if not xauth:
1238 home = os.getenv("HOME")
1239 if not home:
1240 import posix, pwd
1241 home = pwd.getpwuid(posix.getuid())[5]
1242 xauth = home + "/.Xauthority"
1243 return xauth
1246 def parseCommandLine(argv):
1247 gopts.reset()
1248 args = gopts.parse(argv)
1250 if gopts.vals.help or gopts.vals.help_config:
1251 if gopts.vals.help_config:
1252 print gopts.val_usage()
1253 return (None, None)
1255 if not gopts.vals.display:
1256 gopts.vals.display = os.getenv("DISPLAY")
1258 if not gopts.vals.xauthority:
1259 gopts.vals.xauthority = get_xauthority()
1261 gopts.is_xml = False
1263 # Process remaining args as config variables.
1264 for arg in args:
1265 if '=' in arg:
1266 (var, val) = arg.strip().split('=', 1)
1267 gopts.setvar(var.strip(), val.strip())
1268 if gopts.vals.config:
1269 config = gopts.vals.config
1270 else:
1271 try:
1272 gopts.load_defconfig()
1273 preprocess(gopts.vals)
1274 if not gopts.getopt('name') and gopts.getopt('defconfig'):
1275 gopts.setopt('name', os.path.basename(gopts.getopt('defconfig')))
1276 config = make_config(gopts.vals)
1277 except XMLFileError, ex:
1278 XMLFile = ex.getFile()
1279 gopts.is_xml = True
1280 config = ex.getFile()
1282 return (gopts, config)
1284 def help():
1285 return str(gopts)
1287 def main(argv):
1288 is_xml = False
1290 try:
1291 (opts, config) = parseCommandLine(argv)
1292 except StandardError, ex:
1293 err(str(ex))
1295 if not opts:
1296 return
1298 if not opts.is_xml:
1299 if type(config) == str:
1300 try:
1301 config = sxp.parse(file(config))[0]
1302 except IOError, exn:
1303 raise OptionError("Cannot read file %s: %s" % (config, exn[1]))
1305 if serverType == SERVER_XEN_API:
1306 from xen.xm.xenapi_create import sxp2xml
1307 sxp2xml_inst = sxp2xml()
1308 doc = sxp2xml_inst.convert_sxp_to_xml(config, transient=True)
1310 if opts.vals.dryrun and not opts.is_xml:
1311 SXPPrettyPrint.prettyprint(config)
1313 if opts.vals.xmldryrun and serverType == SERVER_XEN_API:
1314 from xml.dom.ext import PrettyPrint as XMLPrettyPrint
1315 XMLPrettyPrint(doc)
1317 if opts.vals.dryrun or opts.vals.xmldryrun:
1318 return
1320 if opts.vals.console_autoconnect:
1321 do_console(sxp.child_value(config, 'name', -1))
1323 if serverType == SERVER_XEN_API:
1324 from xen.xm.xenapi_create import xenapi_create
1325 xenapi_create_inst = xenapi_create()
1326 if opts.is_xml:
1327 vm_refs = xenapi_create_inst.create(filename = config,
1328 skipdtd = opts.vals.skipdtd)
1329 else:
1330 vm_refs = xenapi_create_inst.create(document = doc,
1331 skipdtd = opts.vals.skipdtd)
1333 map(lambda vm_ref: server.xenapi.VM.start(vm_ref, 0), vm_refs)
1334 elif not opts.is_xml:
1335 dom = make_domain(opts, config)
1337 if opts.vals.vncviewer:
1338 domid = domain_name_to_domid(sxp.child_value(config, 'name', -1))
1339 vncviewer_autopass = getattr(opts.vals,'vncviewer-autopass', False)
1340 console.runVncViewer(domid, vncviewer_autopass, True)
1342 def do_console(domain_name):
1343 cpid = os.fork()
1344 if cpid != 0:
1345 for i in range(10):
1346 # Catch failure of the create process
1347 time.sleep(1)
1348 (p, rv) = os.waitpid(cpid, os.WNOHANG)
1349 if os.WIFEXITED(rv):
1350 if os.WEXITSTATUS(rv) != 0:
1351 sys.exit(os.WEXITSTATUS(rv))
1352 try:
1353 domid = domain_name_to_domid(domain_name)
1354 console.execConsole(domid)
1355 except:
1356 pass
1357 print("Could not start console\n");
1358 sys.exit(0)
1360 if __name__ == '__main__':
1361 main(sys.argv)