ia64/xen-unstable

view tools/python/xen/xm/create.py @ 16525:eb4aa1a07e21

Fix help message of on_xend_stop
Signed-off-by: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Dec 05 09:57:32 2007 +0000 (2007-12-05)
parents 5255eac35270
children 38febeb3033f
line source
1 #============================================================================
2 # This library is free software; you can redistribute it and/or
3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
4 # License as published by the Free Software Foundation.
5 #
6 # This library is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 # Lesser General Public License for more details.
10 #
11 # You should have received a copy of the GNU Lesser General Public
12 # License along with this library; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 #============================================================================
15 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
16 # Copyright (C) 2005 Nguyen Anh Quynh <aquynh@gmail.com>
17 # Copyright (C) 2005-2006 XenSource Ltd
18 #============================================================================
20 """Domain creation.
21 """
22 import os
23 import os.path
24 import sys
25 import socket
26 import re
27 import time
28 import xmlrpclib
30 from xen.xend import sxp
31 from xen.xend import PrettyPrint as SXPPrettyPrint
32 from xen.xend import osdep
33 import xen.xend.XendClient
34 from xen.xend.XendBootloader import bootloader
35 from xen.util import blkif
36 import xen.util.xsm.xsm as security
37 from xen.xm.main import serverType, SERVER_XEN_API, get_single_vm
39 from xen.xm.opts import *
41 from main import server
42 import console
45 gopts = Opts(use="""[options] [vars]
47 Create a domain.
49 Domain creation parameters can be set by command-line switches, from
50 a python configuration script or an SXP config file. See documentation
51 for --defconfig, --config. Configuration variables can be set using
52 VAR=VAL on the command line. For example vmid=3 sets vmid to 3.
54 """)
56 gopts.opt('help', short='h',
57 fn=set_true, default=0,
58 use="Print this help.")
60 gopts.opt('help_config',
61 fn=set_true, default=0,
62 use="Print the available configuration variables (vars) for the "
63 "configuration script.")
65 gopts.opt('quiet', short='q',
66 fn=set_true, default=0,
67 use="Quiet.")
69 gopts.opt('path', val='PATH',
70 fn=set_value, default='.:/etc/xen',
71 use="Search path for configuration scripts. "
72 "The value of PATH is a colon-separated directory list.")
74 gopts.opt('defconfig', short='f', val='FILE',
75 fn=set_value, default='xmdefconfig',
76 use="Use the given Python configuration script."
77 "The configuration script is loaded after arguments have been "
78 "processed. Each command-line option sets a configuration "
79 "variable named after its long option name, and these "
80 "variables are placed in the environment of the script before "
81 "it is loaded. Variables for options that may be repeated have "
82 "list values. Other variables can be set using VAR=VAL on the "
83 "command line. "
84 "After the script is loaded, option values that were not set "
85 "on the command line are replaced by the values set in the script.")
87 gopts.default('defconfig')
89 gopts.opt('config', short='F', val='FILE',
90 fn=set_value, default=None,
91 use="Domain configuration to use (SXP).\n"
92 "SXP is the underlying configuration format used by Xen.\n"
93 "SXP configurations can be hand-written or generated from Python "
94 "configuration scripts, using the -n (dryrun) option to print "
95 "the configuration.")
97 gopts.opt('dryrun', short='n',
98 fn=set_true, default=0,
99 use="Dry run - prints the resulting configuration in SXP but "
100 "does not create the domain.")
102 gopts.opt('xmldryrun', short='x',
103 fn=set_true, default=0,
104 use="XML dry run - prints the resulting configuration in XML but "
105 "does not create the domain.")
107 gopts.opt('skipdtd', short='s',
108 fn=set_true, default=0,
109 use="Skip DTD checking - skips checks on XML before creating. "
110 " Experimental. Can decrease create time." )
112 gopts.opt('paused', short='p',
113 fn=set_true, default=0,
114 use='Leave the domain paused after it is created.')
116 gopts.opt('console_autoconnect', short='c',
117 fn=set_true, default=0,
118 use="Connect to the console after the domain is created.")
120 gopts.var('vncpasswd', val='NAME',
121 fn=set_value, default=None,
122 use="Password for VNC console on HVM domain.")
124 gopts.var('vncviewer', val='no|yes',
125 fn=set_bool, default=None,
126 use="Spawn a vncviewer listening for a vnc server in the domain.\n"
127 "The address of the vncviewer is passed to the domain on the "
128 "kernel command line using 'VNC_SERVER=<host>:<port>'. The port "
129 "used by vnc is 5500 + DISPLAY. A display value with a free port "
130 "is chosen if possible.\nOnly valid when vnc=1.")
132 gopts.var('vncconsole', val='no|yes',
133 fn=set_bool, default=None,
134 use="Spawn a vncviewer process for the domain's graphical console.\n"
135 "Only valid when vnc=1.")
137 gopts.var('name', val='NAME',
138 fn=set_value, default=None,
139 use="Domain name. Must be unique.")
141 gopts.var('bootloader', val='FILE',
142 fn=set_value, default=None,
143 use="Path to bootloader.")
145 gopts.var('bootargs', val='NAME',
146 fn=set_value, default=None,
147 use="Arguments to pass to boot loader")
149 gopts.var('bootentry', val='NAME',
150 fn=set_value, default=None,
151 use="DEPRECATED. Entry to boot via boot loader. Use bootargs.")
153 gopts.var('kernel', val='FILE',
154 fn=set_value, default=None,
155 use="Path to kernel image.")
157 gopts.var('ramdisk', val='FILE',
158 fn=set_value, default='',
159 use="Path to ramdisk.")
161 gopts.var('features', val='FEATURES',
162 fn=set_value, default='',
163 use="Features to enable in guest kernel")
165 gopts.var('builder', val='FUNCTION',
166 fn=set_value, default='linux',
167 use="Function to use to build the domain.")
169 gopts.var('memory', val='MEMORY',
170 fn=set_int, default=128,
171 use="Domain memory in MB.")
173 gopts.var('maxmem', val='MEMORY',
174 fn=set_int, default=None,
175 use="Maximum domain memory in MB.")
177 gopts.var('shadow_memory', val='MEMORY',
178 fn=set_int, default=0,
179 use="Domain shadow memory in MB.")
181 gopts.var('cpu', val='CPU',
182 fn=set_int, default=None,
183 use="CPU to run the VCPU0 on.")
185 gopts.var('cpus', val='CPUS',
186 fn=set_value, default=None,
187 use="CPUS to run the domain on.")
189 gopts.var('rtc_timeoffset', val='RTC_TIMEOFFSET',
190 fn=set_value, default="0",
191 use="Set RTC offset.")
193 gopts.var('pae', val='PAE',
194 fn=set_int, default=1,
195 use="Disable or enable PAE of HVM domain.")
197 gopts.var('timer_mode', val='TIMER_MODE',
198 fn=set_int, default=0,
199 use="""Timer mode (0=delay virtual time when ticks are missed;
200 1=virtual time is always wallclock time.""")
202 gopts.var('acpi', val='ACPI',
203 fn=set_int, default=1,
204 use="Disable or enable ACPI of HVM domain.")
206 gopts.var('apic', val='APIC',
207 fn=set_int, default=1,
208 use="Disable or enable APIC mode.")
210 gopts.var('vcpus', val='VCPUS',
211 fn=set_int, default=1,
212 use="# of Virtual CPUS in domain.")
214 gopts.var('vcpu_avail', val='VCPUS',
215 fn=set_long, default=None,
216 use="Bitmask for virtual CPUs to make available immediately.")
218 gopts.var('vhpt', val='VHPT',
219 fn=set_int, default=0,
220 use="Log2 of domain VHPT size for IA64.")
222 gopts.var('cpu_cap', val='CAP',
223 fn=set_int, default=None,
224 use="""Set the maximum amount of cpu.
225 CAP is a percentage that fixes the maximum amount of cpu.""")
227 gopts.var('cpu_weight', val='WEIGHT',
228 fn=set_int, default=None,
229 use="""Set the cpu time ratio to be allocated to the domain.""")
231 gopts.var('restart', val='onreboot|always|never',
232 fn=set_value, default=None,
233 use="""Deprecated. Use on_poweroff, on_reboot, and on_crash
234 instead.
236 Whether the domain should be restarted on exit.
237 - onreboot: restart on exit with shutdown code reboot
238 - always: always restart on exit, ignore exit code
239 - never: never restart on exit, ignore exit code""")
241 gopts.var('on_poweroff', val='destroy|restart|preserve|rename-restart',
242 fn=set_value, default=None,
243 use="""Behaviour when a domain exits with reason 'poweroff'.
244 - destroy: the domain is cleaned up as normal;
245 - restart: a new domain is started in place of the old one;
246 - preserve: no clean-up is done until the domain is manually
247 destroyed (using xm destroy, for example);
248 - rename-restart: the old domain is not cleaned up, but is
249 renamed and a new domain started in its place.
250 """)
252 gopts.var('on_reboot', val='destroy|restart|preserve|rename-restart',
253 fn=set_value, default=None,
254 use="""Behaviour when a domain exits with reason 'reboot'.
255 - destroy: the domain is cleaned up as normal;
256 - restart: a new domain is started in place of the old one;
257 - preserve: no clean-up is done until the domain is manually
258 destroyed (using xm destroy, for example);
259 - rename-restart: the old domain is not cleaned up, but is
260 renamed and a new domain started in its place.
261 """)
263 gopts.var('on_crash', val='destroy|restart|preserve|rename-restart',
264 fn=set_value, default=None,
265 use="""Behaviour when a domain exits with reason 'crash'.
266 - destroy: the domain is cleaned up as normal;
267 - restart: a new domain is started in place of the old one;
268 - preserve: no clean-up is done until the domain is manually
269 destroyed (using xm destroy, for example);
270 - rename-restart: the old domain is not cleaned up, but is
271 renamed and a new domain started in its place.
272 """)
274 gopts.var('blkif', val='no|yes',
275 fn=set_bool, default=0,
276 use="Make the domain a block device backend.")
278 gopts.var('netif', val='no|yes',
279 fn=set_bool, default=0,
280 use="Make the domain a network interface backend.")
282 gopts.var('tpmif', val='no|yes',
283 fn=append_value, default=0,
284 use="Make the domain a TPM interface backend.")
286 gopts.var('disk', val='phy:DEV,VDEV,MODE[,DOM]',
287 fn=append_value, default=[],
288 use="""Add a disk device to a domain. The physical device is DEV,
289 which is exported to the domain as VDEV. The disk is read-only if MODE
290 is 'r', read-write if MODE is 'w'. If DOM is specified it defines the
291 backend driver domain to use for the disk.
292 The option may be repeated to add more than one disk.""")
294 gopts.var('pci', val='BUS:DEV.FUNC',
295 fn=append_value, default=[],
296 use="""Add a PCI device to a domain, using given params (in hex).
297 For example 'pci=c0:02.1a'.
298 The option may be repeated to add more than one pci device.""")
300 gopts.var('ioports', val='FROM[-TO]',
301 fn=append_value, default=[],
302 use="""Add a legacy I/O range to a domain, using given params (in hex).
303 For example 'ioports=02f8-02ff'.
304 The option may be repeated to add more than one i/o range.""")
306 gopts.var('irq', val='IRQ',
307 fn=append_value, default=[],
308 use="""Add an IRQ (interrupt line) to a domain.
309 For example 'irq=7'.
310 This option may be repeated to add more than one IRQ.""")
312 gopts.var('usbport', val='PATH',
313 fn=append_value, default=[],
314 use="""Add a physical USB port to a domain, as specified by the path
315 to that port. This option may be repeated to add more than one port.""")
317 gopts.var('vfb', val="type={vnc,sdl},vncunused=1,vncdisplay=N,vnclisten=ADDR,display=DISPLAY,xauthority=XAUTHORITY,vncpasswd=PASSWORD",
318 fn=append_value, default=[],
319 use="""Make the domain a framebuffer backend.
320 The backend type should be either sdl or vnc.
321 For type=vnc, connect an external vncviewer. The server will listen
322 on ADDR (default 127.0.0.1) on port N+5900. N defaults to the
323 domain id. If vncunused=1, the server will try to find an arbitrary
324 unused port above 5900. vncpasswd overrides the XenD configured
325 default password.
326 For type=sdl, a viewer will be started automatically using the
327 given DISPLAY and XAUTHORITY, which default to the current user's
328 ones.""")
330 gopts.var('vif', val="type=TYPE,mac=MAC,bridge=BRIDGE,ip=IPADDR,script=SCRIPT," + \
331 "backend=DOM,vifname=NAME,rate=RATE,model=MODEL,accel=ACCEL",
332 fn=append_value, default=[],
333 use="""Add a network interface with the given MAC address and bridge.
334 The vif is configured by calling the given configuration script.
335 If type is not specified, default is netfront.
336 If mac is not specified a random MAC address is used.
337 If not specified then the network backend chooses it's own MAC address.
338 If bridge is not specified the first bridge found is used.
339 If script is not specified the default script is used.
340 If backend is not specified the default backend driver domain is used.
341 If vifname is not specified the backend virtual interface will have name vifD.N
342 where D is the domain id and N is the interface id.
343 If rate is not specified the default rate is used.
344 If model is not specified the default model is used.
345 If accel is not specified an accelerator plugin module is not used.
346 This option may be repeated to add more than one vif.
347 Specifying vifs will increase the number of interfaces as needed.""")
349 gopts.var('vtpm', val="instance=INSTANCE,backend=DOM,type=TYPE",
350 fn=append_value, default=[],
351 use="""Add a TPM interface. On the backend side use the given
352 instance as virtual TPM instance. The given number is merely the
353 preferred instance number. The hotplug script will determine
354 which instance number will actually be assigned to the domain.
355 The associtation between virtual machine and the TPM instance
356 number can be found in /etc/xen/vtpm.db. Use the backend in the
357 given domain.
358 The type parameter can be used to select a specific driver type
359 that the VM can use. To prevent a fully virtualized domain (HVM)
360 from being able to access an emulated device model, you may specify
361 'paravirtualized' here.""")
363 gopts.var('access_control', val="policy=POLICY,label=LABEL",
364 fn=append_value, default=[],
365 use="""Add a security label and the security policy reference that defines it.
366 The local ssid reference is calculated when starting/resuming the domain. At
367 this time, the policy is checked against the active policy as well. This way,
368 migrating through save/restore is covered and local labels are automatically
369 created correctly on the system where a domain is started / resumed.""")
371 gopts.var('nics', val="NUM",
372 fn=set_int, default=-1,
373 use="""DEPRECATED. Use empty vif entries instead.
375 Set the number of network interfaces.
376 Use the vif option to define interface parameters, otherwise
377 defaults are used. Specifying vifs will increase the
378 number of interfaces as needed.""")
380 gopts.var('root', val='DEVICE',
381 fn=set_value, default='',
382 use="""Set the root= parameter on the kernel command line.
383 Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""")
385 gopts.var('extra', val="ARGS",
386 fn=set_value, default='',
387 use="Set extra arguments to append to the kernel command line.")
389 gopts.var('ip', val='IPADDR',
390 fn=set_value, default='',
391 use="Set the kernel IP interface address.")
393 gopts.var('gateway', val="IPADDR",
394 fn=set_value, default='',
395 use="Set the kernel IP gateway.")
397 gopts.var('netmask', val="MASK",
398 fn=set_value, default = '',
399 use="Set the kernel IP netmask.")
401 gopts.var('hostname', val="NAME",
402 fn=set_value, default='',
403 use="Set the kernel IP hostname.")
405 gopts.var('interface', val="INTF",
406 fn=set_value, default="eth0",
407 use="Set the kernel IP interface name.")
409 gopts.var('dhcp', val="off|dhcp",
410 fn=set_value, default='off',
411 use="Set the kernel dhcp option.")
413 gopts.var('nfs_server', val="IPADDR",
414 fn=set_value, default=None,
415 use="Set the address of the NFS server for NFS root.")
417 gopts.var('nfs_root', val="PATH",
418 fn=set_value, default=None,
419 use="Set the path of the root NFS directory.")
421 gopts.var('device_model', val='FILE',
422 fn=set_value, default='',
423 use="Path to device model program.")
425 gopts.var('fda', val='FILE',
426 fn=set_value, default='',
427 use="Path to fda")
429 gopts.var('fdb', val='FILE',
430 fn=set_value, default='',
431 use="Path to fdb")
433 gopts.var('serial', val='FILE',
434 fn=set_value, default='',
435 use="Path to serial or pty or vc")
437 gopts.var('monitor', val='no|yes',
438 fn=set_bool, default=0,
439 use="""Should the device model use monitor?""")
441 gopts.var('localtime', val='no|yes',
442 fn=set_bool, default=0,
443 use="Is RTC set to localtime?")
445 gopts.var('keymap', val='FILE',
446 fn=set_value, default='',
447 use="Set keyboard layout used")
449 gopts.var('usb', val='no|yes',
450 fn=set_bool, default=0,
451 use="Emulate USB devices?")
453 gopts.var('usbdevice', val='NAME',
454 fn=set_value, default='',
455 use="Name of USB device to add?")
457 gopts.var('guest_os_type', val='NAME',
458 fn=set_value, default='default',
459 use="Guest OS type running in HVM")
461 gopts.var('stdvga', val='no|yes',
462 fn=set_bool, default=0,
463 use="Use std vga or cirrhus logic graphics")
465 gopts.var('isa', val='no|yes',
466 fn=set_bool, default=0,
467 use="Simulate an ISA only system?")
469 gopts.var('boot', val="a|b|c|d",
470 fn=set_value, default='c',
471 use="Default boot device")
473 gopts.var('nographic', val='no|yes',
474 fn=set_bool, default=0,
475 use="Should device models use graphics?")
477 gopts.var('soundhw', val='audiodev',
478 fn=set_value, default='',
479 use="Should device models enable audio device?")
481 gopts.var('vnc', val='',
482 fn=set_value, default=None,
483 use="""Should the device model use VNC?""")
485 gopts.var('vncdisplay', val='',
486 fn=set_value, default=None,
487 use="""VNC display to use""")
489 gopts.var('vnclisten', val='',
490 fn=set_value, default=None,
491 use="""Address for VNC server to listen on.""")
493 gopts.var('vncunused', val='',
494 fn=set_bool, default=1,
495 use="""Try to find an unused port for the VNC server.
496 Only valid when vnc=1.""")
498 gopts.var('sdl', val='',
499 fn=set_value, default=None,
500 use="""Should the device model use SDL?""")
502 gopts.var('display', val='DISPLAY',
503 fn=set_value, default=None,
504 use="X11 display to use")
506 gopts.var('xauthority', val='XAUTHORITY',
507 fn=set_value, default=None,
508 use="X11 Authority to use")
510 gopts.var('uuid', val='',
511 fn=set_value, default=None,
512 use="""xenstore UUID (universally unique identifier) to use. One
513 will be randomly generated if this option is not set, just like MAC
514 addresses for virtual network interfaces. This must be a unique
515 value across the entire cluster.""")
517 gopts.var('on_xend_start', val='ignore|start',
518 fn=set_value, default='ignore',
519 use='Action to perform when xend starts')
521 gopts.var('on_xend_stop', val='ignore|shutdown|suspend',
522 fn=set_value, default="ignore",
523 use="""Behaviour when Xend stops:
524 - ignore: Domain continues to run;
525 - shutdown: Domain is shutdown;
526 - suspend: Domain is suspended;
527 """)
529 def err(msg):
530 """Print an error to stderr and exit.
531 """
532 print >>sys.stderr, "Error:", msg
533 sys.exit(1)
536 def warn(msg):
537 """Print a warning to stdout.
538 """
539 print >>sys.stderr, "Warning:", msg
542 def strip(pre, s):
543 """Strip prefix 'pre' if present.
544 """
545 if s.startswith(pre):
546 return s[len(pre):]
547 else:
548 return s
550 def configure_image(vals):
551 """Create the image config.
552 """
553 if not vals.builder:
554 return None
555 config_image = [ vals.builder ]
556 if vals.kernel:
557 config_image.append([ 'kernel', os.path.abspath(vals.kernel) ])
558 if vals.ramdisk:
559 config_image.append([ 'ramdisk', os.path.abspath(vals.ramdisk) ])
560 if vals.cmdline_ip:
561 cmdline_ip = strip('ip=', vals.cmdline_ip)
562 config_image.append(['ip', cmdline_ip])
563 if vals.root:
564 cmdline_root = strip('root=', vals.root)
565 config_image.append(['root', cmdline_root])
566 if vals.extra:
567 config_image.append(['args', vals.extra])
569 if vals.builder == 'hvm':
570 configure_hvm(config_image, vals)
572 if vals.vhpt != 0:
573 config_image.append(['vhpt', vals.vhpt])
575 return config_image
577 def configure_disks(config_devs, vals):
578 """Create the config for disks (virtual block devices).
579 """
580 for (uname, dev, mode, backend) in vals.disk:
581 if uname.startswith('tap:'):
582 cls = 'tap'
583 else:
584 cls = 'vbd'
586 config_vbd = [cls,
587 ['uname', uname],
588 ['dev', dev ],
589 ['mode', mode ] ]
590 if backend:
591 config_vbd.append(['backend', backend])
592 config_devs.append(['device', config_vbd])
594 def configure_pci(config_devs, vals):
595 """Create the config for pci devices.
596 """
597 config_pci = []
598 for (domain, bus, slot, func) in vals.pci:
599 config_pci.append(['dev', ['domain', domain], ['bus', bus], \
600 ['slot', slot], ['func', func]])
602 if len(config_pci)>0:
603 config_pci.insert(0, 'pci')
604 config_devs.append(['device', config_pci])
606 def configure_ioports(config_devs, vals):
607 """Create the config for legacy i/o ranges.
608 """
609 for (io_from, io_to) in vals.ioports:
610 config_ioports = ['ioports', ['from', io_from], ['to', io_to]]
611 config_devs.append(['device', config_ioports])
613 def configure_irq(config_devs, vals):
614 """Create the config for irqs.
615 """
616 for irq in vals.irq:
617 config_irq = ['irq', ['irq', irq]]
618 config_devs.append(['device', config_irq])
620 def configure_usb(config_devs, vals):
621 for path in vals.usbport:
622 config_usb = ['usbport', ['path', path]]
623 config_devs.append(['device', config_usb])
625 def configure_vfbs(config_devs, vals):
626 for f in vals.vfb:
627 d = comma_sep_kv_to_dict(f)
628 config = ['vfb']
629 if not d.has_key("type"):
630 d['type'] = 'sdl'
631 for (k,v) in d.iteritems():
632 if not k in [ 'vnclisten', 'vncunused', 'vncdisplay', 'display',
633 'xauthority', 'type', 'vncpasswd' ]:
634 err("configuration option %s unknown to vfbs" % k)
635 config.append([k,v])
636 if not d.has_key("keymap"):
637 if vals.keymap:
638 config.append(['keymap',vals.keymap])
639 if not d.has_key("display") and os.environ.has_key("DISPLAY"):
640 config.append(["display", os.environ['DISPLAY']])
641 if not d.has_key("xauthority"):
642 config.append(["xauthority", get_xauthority()])
643 config_devs.append(['device', ['vkbd']])
644 config_devs.append(['device', config])
646 def configure_security(config, vals):
647 """Create the config for ACM security labels.
648 """
649 access_control = vals.access_control
650 num = len(access_control)
651 if num == 1:
652 d = access_control[0]
653 policy = d.get('policy')
654 label = d.get('label')
655 if policy != security.active_policy:
656 err("Security policy (" + policy + ") incompatible with enforced policy ("
657 + security.active_policy + ")." )
658 config_access_control = ['access_control',
659 ['policy', policy],
660 ['label', label] ]
662 security_label = ['security', [ config_access_control ] ]
663 config.append(security_label)
664 elif num > 1:
665 err("VM config error: Multiple access_control definitions!")
668 def configure_vtpm(config_devs, vals):
669 """Create the config for virtual TPM interfaces.
670 """
671 vtpm = vals.vtpm
672 if len(vtpm) > 0:
673 d = vtpm[0]
674 instance = d.get('instance')
675 if instance == "VTPMD":
676 instance = "0"
677 else:
678 if instance != None:
679 try:
680 if int(instance) == 0:
681 err('VM config error: vTPM instance must not be 0.')
682 except ValueError:
683 err('Vm config error: could not parse instance number.')
684 backend = d.get('backend')
685 typ = d.get('type')
686 config_vtpm = ['vtpm']
687 if instance:
688 config_vtpm.append(['pref_instance', instance])
689 if backend:
690 config_vtpm.append(['backend', backend])
691 if typ:
692 config_vtpm.append(['type', type])
693 config_devs.append(['device', config_vtpm])
696 def configure_vifs(config_devs, vals):
697 """Create the config for virtual network interfaces.
698 """
700 vifs = vals.vif
701 vifs_n = len(vifs)
703 if hasattr(vals, 'nics'):
704 if vals.nics > 0:
705 warn("The nics option is deprecated. Please use an empty vif "
706 "entry instead:\n\n vif = [ '' ]\n")
707 for _ in range(vifs_n, vals.nics):
708 vifs.append('')
709 vifs_n = len(vifs)
710 elif vals.nics == 0:
711 warn("The nics option is deprecated. Please remove it.")
713 for c in vifs:
714 d = comma_sep_kv_to_dict(c)
715 config_vif = ['vif']
717 def f(k):
718 if k not in ['backend', 'bridge', 'ip', 'mac', 'script', 'type',
719 'vifname', 'rate', 'model', 'accel',
720 'policy', 'label']:
721 err('Invalid vif option: ' + k)
723 config_vif.append([k, d[k]])
725 map(f, d.keys())
726 config_devs.append(['device', config_vif])
729 def configure_hvm(config_image, vals):
730 """Create the config for HVM devices.
731 """
732 args = [ 'device_model', 'pae', 'vcpus', 'boot', 'fda', 'fdb', 'timer_mode',
733 'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'soundhw',
734 'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten',
735 'sdl', 'display', 'xauthority', 'rtc_timeoffset', 'monitor',
736 'acpi', 'apic', 'usb', 'usbdevice', 'keymap', 'pci',
737 'guest_os_type']
739 for a in args:
740 if a in vals.__dict__ and vals.__dict__[a] is not None:
741 config_image.append([a, vals.__dict__[a]])
742 if vals.vncpasswd is not None:
743 config_image.append(['vncpasswd', vals.vncpasswd])
746 def make_config(vals):
747 """Create the domain configuration.
748 """
750 config = ['vm']
752 def add_conf(n):
753 if hasattr(vals, n):
754 v = getattr(vals, n)
755 if v:
756 config.append([n, v])
758 map(add_conf, ['name', 'memory', 'maxmem', 'shadow_memory',
759 'restart', 'on_poweroff',
760 'on_reboot', 'on_crash', 'vcpus', 'vcpu_avail', 'features',
761 'on_xend_start', 'on_xend_stop'])
763 if vals.uuid is not None:
764 config.append(['uuid', vals.uuid])
765 if vals.cpu is not None:
766 config.append(['cpu', vals.cpu])
767 if vals.cpus is not None:
768 config.append(['cpus', vals.cpus])
769 if vals.cpu_cap is not None:
770 config.append(['cpu_cap', vals.cpu_cap])
771 if vals.cpu_weight is not None:
772 config.append(['cpu_weight', vals.cpu_weight])
773 if vals.blkif:
774 config.append(['backend', ['blkif']])
775 if vals.netif:
776 config.append(['backend', ['netif']])
777 if vals.tpmif:
778 config.append(['backend', ['tpmif']])
779 if vals.localtime:
780 config.append(['localtime', vals.localtime])
782 config_image = configure_image(vals)
783 if vals.bootloader:
784 if vals.bootloader == "pygrub":
785 vals.bootloader = osdep.pygrub_path
787 config.append(['bootloader', vals.bootloader])
788 if vals.bootargs:
789 config.append(['bootloader_args', vals.bootargs])
790 else:
791 if vals.console_autoconnect:
792 config.append(['bootloader_args', ''])
793 else:
794 config.append(['bootloader_args', '-q'])
795 config.append(['image', config_image])
797 config_devs = []
798 configure_disks(config_devs, vals)
799 configure_pci(config_devs, vals)
800 configure_ioports(config_devs, vals)
801 configure_irq(config_devs, vals)
802 configure_vifs(config_devs, vals)
803 configure_usb(config_devs, vals)
804 configure_vtpm(config_devs, vals)
805 configure_vfbs(config_devs, vals)
806 configure_security(config, vals)
807 config += config_devs
809 return config
811 def preprocess_disk(vals):
812 if not vals.disk: return
813 disk = []
814 for v in vals.disk:
815 d = v.split(',')
816 n = len(d)
817 if n == 3:
818 d.append(None)
819 elif n == 4:
820 pass
821 else:
822 err('Invalid disk specifier: ' + v)
823 disk.append(d)
824 vals.disk = disk
826 def preprocess_pci(vals):
827 if not vals.pci: return
828 pci = []
829 for pci_dev_str in vals.pci:
830 pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \
831 r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \
832 r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \
833 r"(?P<func>[0-9a-fA-F])", pci_dev_str)
834 if pci_match!=None:
835 pci_dev_info = pci_match.groupdict('0')
836 try:
837 pci.append( ('0x'+pci_dev_info['domain'], \
838 '0x'+pci_dev_info['bus'], \
839 '0x'+pci_dev_info['slot'], \
840 '0x'+pci_dev_info['func']))
841 except IndexError:
842 err('Error in PCI slot syntax "%s"'%(pci_dev_str))
843 vals.pci = pci
845 def preprocess_ioports(vals):
846 if not vals.ioports: return
847 ioports = []
848 for v in vals.ioports:
849 d = v.split('-')
850 if len(d) < 1 or len(d) > 2:
851 err('Invalid i/o port range specifier: ' + v)
852 if len(d) == 1:
853 d.append(d[0])
854 # Components are in hex: add hex specifier.
855 hexd = ['0x' + x for x in d]
856 ioports.append(hexd)
857 vals.ioports = ioports
859 def preprocess_vtpm(vals):
860 if not vals.vtpm: return
861 vtpms = []
862 for vtpm in vals.vtpm:
863 d = {}
864 a = vtpm.split(',')
865 for b in a:
866 (k, v) = b.strip().split('=', 1)
867 k = k.strip()
868 v = v.strip()
869 if k not in ['backend', 'instance']:
870 err('Invalid vtpm specifier: ' + vtpm)
871 d[k] = v
872 vtpms.append(d)
873 vals.vtpm = vtpms
875 def preprocess_access_control(vals):
876 if not vals.access_control:
877 return
878 access_controls = []
879 num = len(vals.access_control)
880 if num == 1:
881 access_control = (vals.access_control)[0]
882 d = {}
883 a = access_control.split(',')
884 if len(a) > 2:
885 err('Too many elements in access_control specifier: ' + access_control)
886 for b in a:
887 (k, v) = b.strip().split('=', 1)
888 k = k.strip()
889 v = v.strip()
890 if k not in ['policy','label']:
891 err('Invalid access_control specifier: ' + access_control)
892 d[k] = v
893 access_controls.append(d)
894 vals.access_control = access_controls
895 elif num > 1:
896 err('Multiple access_control definitions.')
898 def preprocess_ip(vals):
899 if vals.ip or vals.dhcp != 'off':
900 dummy_nfs_server = '1.2.3.4'
901 ip = (vals.ip
902 + ':' + (vals.nfs_server or dummy_nfs_server)
903 + ':' + vals.gateway
904 + ':' + vals.netmask
905 + ':' + vals.hostname
906 + ':' + vals.interface
907 + ':' + vals.dhcp)
908 else:
909 ip = ''
910 vals.cmdline_ip = ip
912 def preprocess_nfs(vals):
913 if not vals.nfs_root: return
914 if not vals.nfs_server:
915 err('Must set nfs root and nfs server')
916 nfs = 'nfsroot=' + vals.nfs_server + ':' + vals.nfs_root
917 vals.extra = nfs + ' ' + vals.extra
920 def get_host_addr():
921 host = socket.gethostname()
922 addr = socket.gethostbyname(host)
923 return addr
925 VNC_BASE_PORT = 5500
927 def choose_vnc_display():
928 """Try to choose a free vnc display.
929 """
930 def netstat_local_ports():
931 """Run netstat to get a list of the local ports in use.
932 """
933 l = os.popen("netstat -nat").readlines()
934 r = []
935 # Skip 2 lines of header.
936 for x in l[2:]:
937 # Local port is field 3.
938 y = x.split()[3]
939 # Field is addr:port, split off the port.
940 y = y.split(':')[-1]
941 r.append(int(y))
942 return r
944 ports = netstat_local_ports()
945 for d in range(1, 100):
946 port = VNC_BASE_PORT + d
947 if port in ports: continue
948 return d
949 return None
950 vncpid = None
952 def daemonize(prog, args):
953 """Runs a program as a daemon with the list of arguments. Returns the PID
954 of the daemonized program, or returns 0 on error.
955 """
956 r, w = os.pipe()
957 pid = os.fork()
959 if pid == 0:
960 os.close(r)
961 w = os.fdopen(w, 'w')
962 os.setsid()
963 try:
964 pid2 = os.fork()
965 except:
966 pid2 = None
967 if pid2 == 0:
968 os.chdir("/")
969 for fd in range(0, 256):
970 try:
971 os.close(fd)
972 except:
973 pass
974 os.open("/dev/null", os.O_RDWR)
975 os.dup2(0, 1)
976 os.dup2(0, 2)
977 os.execvp(prog, args)
978 os._exit(1)
979 else:
980 w.write(str(pid2 or 0))
981 w.close()
982 os._exit(0)
983 os.close(w)
984 r = os.fdopen(r)
985 daemon_pid = int(r.read())
986 r.close()
987 os.waitpid(pid, 0)
988 return daemon_pid
990 def spawn_vnc(display):
991 """Spawns a vncviewer that listens on the specified display. On success,
992 returns the port that the vncviewer is listening on and sets the global
993 vncpid. On failure, returns 0. Note that vncviewer is daemonized.
994 """
995 vncargs = (["vncviewer", "-log", "*:stdout:0",
996 "-listen", "%d" % (VNC_BASE_PORT + display) ])
997 global vncpid
998 vncpid = daemonize("vncviewer", vncargs)
999 if vncpid == 0:
1000 return 0
1002 return VNC_BASE_PORT + display
1004 def preprocess_vnc(vals):
1005 """If vnc was specified, spawn a vncviewer in listen mode
1006 and pass its address to the domain on the kernel command line.
1007 """
1008 if vals.dryrun: return
1009 if vals.vncviewer:
1010 vnc_display = choose_vnc_display()
1011 if not vnc_display:
1012 warn("No free vnc display")
1013 return
1014 print 'VNC=', vnc_display
1015 vnc_port = spawn_vnc(vnc_display)
1016 if vnc_port > 0:
1017 vnc_host = get_host_addr()
1018 vnc = 'VNC_VIEWER=%s:%d' % (vnc_host, vnc_port)
1019 vals.extra = vnc + ' ' + vals.extra
1021 def preprocess(vals):
1022 preprocess_disk(vals)
1023 preprocess_pci(vals)
1024 preprocess_ioports(vals)
1025 preprocess_ip(vals)
1026 preprocess_nfs(vals)
1027 preprocess_vnc(vals)
1028 preprocess_vtpm(vals)
1029 preprocess_access_control(vals)
1032 def comma_sep_kv_to_dict(c):
1033 """Convert comma-separated, equals-separated key-value pairs into a
1034 dictionary.
1035 """
1036 d = {}
1037 c = c.strip()
1038 if len(c) > 0:
1039 a = c.split(',')
1040 for b in a:
1041 if b.find('=') == -1:
1042 err("%s should be a pair, separated by an equals sign." % b)
1043 (k, v) = b.split('=', 1)
1044 k = k.strip()
1045 v = v.strip()
1046 d[k] = v
1047 return d
1050 def make_domain(opts, config):
1051 """Create, build and start a domain.
1053 @param opts: options
1054 @param config: configuration
1055 @return: domain id
1056 @rtype: int
1057 """
1059 try:
1060 dominfo = server.xend.domain.create(config)
1061 except xmlrpclib.Fault, ex:
1062 import signal
1063 if vncpid:
1064 os.kill(vncpid, signal.SIGKILL)
1065 if ex.faultCode == xen.xend.XendClient.ERROR_INVALID_DOMAIN:
1066 err("the domain '%s' does not exist." % ex.faultString)
1067 else:
1068 err("%s" % ex.faultString)
1069 except Exception, ex:
1070 # main.py has good error messages that let the user know what failed.
1071 # unless the error is a create.py specific thing, it should be handled
1072 # at main. The purpose of this general-case 'Exception' handler is to
1073 # clean up create.py specific processes/data but since create.py does
1074 # not know what to do with the error, it should pass it up.
1075 import signal
1076 if vncpid:
1077 os.kill(vncpid, signal.SIGKILL)
1078 raise
1080 dom = sxp.child_value(dominfo, 'name')
1082 try:
1083 server.xend.domain.waitForDevices(dom)
1084 except xmlrpclib.Fault, ex:
1085 server.xend.domain.destroy(dom)
1086 err("%s" % ex.faultString)
1087 except:
1088 server.xend.domain.destroy(dom)
1089 err("Device creation failed for domain %s" % dom)
1091 if not opts.vals.paused:
1092 try:
1093 server.xend.domain.unpause(dom)
1094 except:
1095 server.xend.domain.destroy(dom)
1096 err("Failed to unpause domain %s" % dom)
1097 opts.info("Started domain %s" % (dom))
1098 return int(sxp.child_value(dominfo, 'domid'))
1101 def get_xauthority():
1102 xauth = os.getenv("XAUTHORITY")
1103 if not xauth:
1104 home = os.getenv("HOME")
1105 if not home:
1106 import posix, pwd
1107 home = pwd.getpwuid(posix.getuid())[5]
1108 xauth = home + "/.Xauthority"
1109 return xauth
1112 def parseCommandLine(argv):
1113 gopts.reset()
1114 args = gopts.parse(argv)
1116 if gopts.vals.help or gopts.vals.help_config:
1117 if gopts.vals.help_config:
1118 print gopts.val_usage()
1119 return (None, None)
1121 if not gopts.vals.display:
1122 gopts.vals.display = os.getenv("DISPLAY")
1124 if not gopts.vals.xauthority:
1125 gopts.vals.xauthority = get_xauthority()
1127 gopts.is_xml = False
1129 # Process remaining args as config variables.
1130 for arg in args:
1131 if '=' in arg:
1132 (var, val) = arg.strip().split('=', 1)
1133 gopts.setvar(var.strip(), val.strip())
1134 if gopts.vals.config:
1135 config = gopts.vals.config
1136 else:
1137 try:
1138 gopts.load_defconfig()
1139 preprocess(gopts.vals)
1140 if not gopts.getopt('name') and gopts.getopt('defconfig'):
1141 gopts.setopt('name', os.path.basename(gopts.getopt('defconfig')))
1142 config = make_config(gopts.vals)
1143 except XMLFileError, ex:
1144 XMLFile = ex.getFile()
1145 gopts.is_xml = True
1146 config = ex.getFile()
1148 return (gopts, config)
1150 def help():
1151 return str(gopts)
1153 def main(argv):
1154 is_xml = False
1156 try:
1157 (opts, config) = parseCommandLine(argv)
1158 except StandardError, ex:
1159 err(str(ex))
1161 if not opts:
1162 return
1164 if not opts.is_xml:
1165 if type(config) == str:
1166 try:
1167 config = sxp.parse(file(config))[0]
1168 except IOError, exn:
1169 raise OptionError("Cannot read file %s: %s" % (config, exn[1]))
1171 if serverType == SERVER_XEN_API:
1172 from xen.xm.xenapi_create import sxp2xml
1173 sxp2xml_inst = sxp2xml()
1174 doc = sxp2xml_inst.convert_sxp_to_xml(config, transient=True)
1176 if opts.vals.dryrun and not opts.is_xml:
1177 SXPPrettyPrint.prettyprint(config)
1179 if opts.vals.xmldryrun and serverType == SERVER_XEN_API:
1180 from xml.dom.ext import PrettyPrint as XMLPrettyPrint
1181 XMLPrettyPrint(doc)
1183 if opts.vals.dryrun or opts.vals.xmldryrun:
1184 return
1186 if opts.vals.console_autoconnect:
1187 do_console(sxp.child_value(config, 'name', -1))
1189 if serverType == SERVER_XEN_API:
1190 from xen.xm.xenapi_create import xenapi_create
1191 xenapi_create_inst = xenapi_create()
1192 if opts.is_xml:
1193 vm_refs = xenapi_create_inst.create(filename = config,
1194 skipdtd = opts.vals.skipdtd)
1195 else:
1196 vm_refs = xenapi_create_inst.create(document = doc,
1197 skipdtd = opts.vals.skipdtd)
1199 map(lambda vm_ref: server.xenapi.VM.start(vm_ref, 0), vm_refs)
1200 elif not opts.is_xml:
1201 dom = make_domain(opts, config)
1203 def do_console(domain_name):
1204 cpid = os.fork()
1205 if cpid != 0:
1206 for i in range(10):
1207 # Catch failure of the create process
1208 time.sleep(1)
1209 (p, rv) = os.waitpid(cpid, os.WNOHANG)
1210 if os.WIFEXITED(rv):
1211 if os.WEXITSTATUS(rv) != 0:
1212 sys.exit(os.WEXITSTATUS(rv))
1213 try:
1214 # Acquire the console of the created dom
1215 if serverType == SERVER_XEN_API:
1216 domid = server.xenapi.VM.get_domid(
1217 get_single_vm(domain_name))
1218 else:
1219 dom = server.xend.domain(domain_name)
1220 domid = int(sxp.child_value(dom, 'domid', '-1'))
1221 console.execConsole(domid)
1222 except:
1223 pass
1224 print("Could not start console\n");
1225 sys.exit(0)
1227 if __name__ == '__main__':
1228 main(sys.argv)