ia64/xen-unstable

view tools/python/xen/xm/create.py @ 16739:33dcf04d7715

tools/docs: Fix example and default IP addresses.

In various places in documentation and code, IP addresses are provided
as examples, defaults, or dummy configuration. In general the
specific IP addresses used in Xen are not always appropriate. (For
example, 1.2.3.4 is used in a few places!)

The following addresses should be used:
* For examples and documentation, 192.0.2.0/24. (See RFC3330.)
* For defaults for private networks, a random network from RFC1918.
I have randomly selected 172.30.206.0/24 for this purpose and
documented this in at the only registry I know of,
www.ucam.org/cam-grin. This network should henceforth be used for
default configurations of local bridges, test networks, etc. in
Xen tools.

The following addresses should NOT be used:
* 10.0.*.*, 10.1.*.*, 192.168.0.*, 192.168.1.*, etc. Using these
addresses gives greatly increased likelihood of collision, as
ignorant network administrators and reckless middlebox vendors
often pick networks from the bottom of 10/8 and 192.168/16.
* 169.254.*.*. These are reserved for zeroconf (ad-hoc networking)
and should not be used for Xen private networks, bridges, etc.,
etc. Use of these addresses by Xen scripts causes trouble on hosts
(eg laptops) which find themselves in ad-hoc networking
environments. I think this is not hypothetical (!) since at least
one Linux distribution have specific code to detect this case and
cause Xen startup to fail iff the host already has an external
zeroconf address.
* 1.2.3.4. WTF !?

I have also used 127.0.255.255 in one place where apparently a dummy
address is needed (some Linux kernels won't accept a lack of an NFS
server address). If 127.0.255.255 is mistakenly used it is unlikely
to do any damage to real traffic even if it does escape into the
network at large.

Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jan 17 15:13:40 2008 +0000 (2008-01-17)
parents 38febeb3033f
children cff4c8a1aa28
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('vfb', val="type={vnc,sdl},vncunused=1,vncdisplay=N,vnclisten=ADDR,display=DISPLAY,xauthority=XAUTHORITY,vncpasswd=PASSWORD",
313 fn=append_value, default=[],
314 use="""Make the domain a framebuffer backend.
315 The backend type should be either sdl or vnc.
316 For type=vnc, connect an external vncviewer. The server will listen
317 on ADDR (default 127.0.0.1) on port N+5900. N defaults to the
318 domain id. If vncunused=1, the server will try to find an arbitrary
319 unused port above 5900. vncpasswd overrides the XenD configured
320 default password.
321 For type=sdl, a viewer will be started automatically using the
322 given DISPLAY and XAUTHORITY, which default to the current user's
323 ones.""")
325 gopts.var('vif', val="type=TYPE,mac=MAC,bridge=BRIDGE,ip=IPADDR,script=SCRIPT," + \
326 "backend=DOM,vifname=NAME,rate=RATE,model=MODEL,accel=ACCEL",
327 fn=append_value, default=[],
328 use="""Add a network interface with the given MAC address and bridge.
329 The vif is configured by calling the given configuration script.
330 If type is not specified, default is netfront.
331 If mac is not specified a random MAC address is used.
332 If not specified then the network backend chooses it's own MAC address.
333 If bridge is not specified the first bridge found is used.
334 If script is not specified the default script is used.
335 If backend is not specified the default backend driver domain is used.
336 If vifname is not specified the backend virtual interface will have name vifD.N
337 where D is the domain id and N is the interface id.
338 If rate is not specified the default rate is used.
339 If model is not specified the default model is used.
340 If accel is not specified an accelerator plugin module is not used.
341 This option may be repeated to add more than one vif.
342 Specifying vifs will increase the number of interfaces as needed.""")
344 gopts.var('vtpm', val="instance=INSTANCE,backend=DOM,type=TYPE",
345 fn=append_value, default=[],
346 use="""Add a TPM interface. On the backend side use the given
347 instance as virtual TPM instance. The given number is merely the
348 preferred instance number. The hotplug script will determine
349 which instance number will actually be assigned to the domain.
350 The associtation between virtual machine and the TPM instance
351 number can be found in /etc/xen/vtpm.db. Use the backend in the
352 given domain.
353 The type parameter can be used to select a specific driver type
354 that the VM can use. To prevent a fully virtualized domain (HVM)
355 from being able to access an emulated device model, you may specify
356 'paravirtualized' here.""")
358 gopts.var('access_control', val="policy=POLICY,label=LABEL",
359 fn=append_value, default=[],
360 use="""Add a security label and the security policy reference that defines it.
361 The local ssid reference is calculated when starting/resuming the domain. At
362 this time, the policy is checked against the active policy as well. This way,
363 migrating through save/restore is covered and local labels are automatically
364 created correctly on the system where a domain is started / resumed.""")
366 gopts.var('nics', val="NUM",
367 fn=set_int, default=-1,
368 use="""DEPRECATED. Use empty vif entries instead.
370 Set the number of network interfaces.
371 Use the vif option to define interface parameters, otherwise
372 defaults are used. Specifying vifs will increase the
373 number of interfaces as needed.""")
375 gopts.var('root', val='DEVICE',
376 fn=set_value, default='',
377 use="""Set the root= parameter on the kernel command line.
378 Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""")
380 gopts.var('extra', val="ARGS",
381 fn=set_value, default='',
382 use="Set extra arguments to append to the kernel command line.")
384 gopts.var('ip', val='IPADDR',
385 fn=set_value, default='',
386 use="Set the kernel IP interface address.")
388 gopts.var('gateway', val="IPADDR",
389 fn=set_value, default='',
390 use="Set the kernel IP gateway.")
392 gopts.var('netmask', val="MASK",
393 fn=set_value, default = '',
394 use="Set the kernel IP netmask.")
396 gopts.var('hostname', val="NAME",
397 fn=set_value, default='',
398 use="Set the kernel IP hostname.")
400 gopts.var('interface', val="INTF",
401 fn=set_value, default="eth0",
402 use="Set the kernel IP interface name.")
404 gopts.var('dhcp', val="off|dhcp",
405 fn=set_value, default='off',
406 use="Set the kernel dhcp option.")
408 gopts.var('nfs_server', val="IPADDR",
409 fn=set_value, default=None,
410 use="Set the address of the NFS server for NFS root.")
412 gopts.var('nfs_root', val="PATH",
413 fn=set_value, default=None,
414 use="Set the path of the root NFS directory.")
416 gopts.var('device_model', val='FILE',
417 fn=set_value, default='',
418 use="Path to device model program.")
420 gopts.var('fda', val='FILE',
421 fn=set_value, default='',
422 use="Path to fda")
424 gopts.var('fdb', val='FILE',
425 fn=set_value, default='',
426 use="Path to fdb")
428 gopts.var('serial', val='FILE',
429 fn=set_value, default='',
430 use="Path to serial or pty or vc")
432 gopts.var('monitor', val='no|yes',
433 fn=set_bool, default=0,
434 use="""Should the device model use monitor?""")
436 gopts.var('localtime', val='no|yes',
437 fn=set_bool, default=0,
438 use="Is RTC set to localtime?")
440 gopts.var('keymap', val='FILE',
441 fn=set_value, default='',
442 use="Set keyboard layout used")
444 gopts.var('usb', val='no|yes',
445 fn=set_bool, default=0,
446 use="Emulate USB devices?")
448 gopts.var('usbdevice', val='NAME',
449 fn=set_value, default='',
450 use="Name of USB device to add?")
452 gopts.var('guest_os_type', val='NAME',
453 fn=set_value, default='default',
454 use="Guest OS type running in HVM")
456 gopts.var('stdvga', val='no|yes',
457 fn=set_bool, default=0,
458 use="Use std vga or cirrhus logic graphics")
460 gopts.var('isa', val='no|yes',
461 fn=set_bool, default=0,
462 use="Simulate an ISA only system?")
464 gopts.var('boot', val="a|b|c|d",
465 fn=set_value, default='c',
466 use="Default boot device")
468 gopts.var('nographic', val='no|yes',
469 fn=set_bool, default=0,
470 use="Should device models use graphics?")
472 gopts.var('soundhw', val='audiodev',
473 fn=set_value, default='',
474 use="Should device models enable audio device?")
476 gopts.var('vnc', val='',
477 fn=set_value, default=None,
478 use="""Should the device model use VNC?""")
480 gopts.var('vncdisplay', val='',
481 fn=set_value, default=None,
482 use="""VNC display to use""")
484 gopts.var('vnclisten', val='',
485 fn=set_value, default=None,
486 use="""Address for VNC server to listen on.""")
488 gopts.var('vncunused', val='',
489 fn=set_bool, default=1,
490 use="""Try to find an unused port for the VNC server.
491 Only valid when vnc=1.""")
493 gopts.var('sdl', val='',
494 fn=set_value, default=None,
495 use="""Should the device model use SDL?""")
497 gopts.var('display', val='DISPLAY',
498 fn=set_value, default=None,
499 use="X11 display to use")
501 gopts.var('xauthority', val='XAUTHORITY',
502 fn=set_value, default=None,
503 use="X11 Authority to use")
505 gopts.var('uuid', val='',
506 fn=set_value, default=None,
507 use="""xenstore UUID (universally unique identifier) to use. One
508 will be randomly generated if this option is not set, just like MAC
509 addresses for virtual network interfaces. This must be a unique
510 value across the entire cluster.""")
512 gopts.var('on_xend_start', val='ignore|start',
513 fn=set_value, default='ignore',
514 use='Action to perform when xend starts')
516 gopts.var('on_xend_stop', val='ignore|shutdown|suspend',
517 fn=set_value, default="ignore",
518 use="""Behaviour when Xend stops:
519 - ignore: Domain continues to run;
520 - shutdown: Domain is shutdown;
521 - suspend: Domain is suspended;
522 """)
524 def err(msg):
525 """Print an error to stderr and exit.
526 """
527 print >>sys.stderr, "Error:", msg
528 sys.exit(1)
531 def warn(msg):
532 """Print a warning to stdout.
533 """
534 print >>sys.stderr, "Warning:", msg
537 def strip(pre, s):
538 """Strip prefix 'pre' if present.
539 """
540 if s.startswith(pre):
541 return s[len(pre):]
542 else:
543 return s
545 def configure_image(vals):
546 """Create the image config.
547 """
548 if not vals.builder:
549 return None
550 config_image = [ vals.builder ]
551 if vals.kernel:
552 config_image.append([ 'kernel', os.path.abspath(vals.kernel) ])
553 if vals.ramdisk:
554 config_image.append([ 'ramdisk', os.path.abspath(vals.ramdisk) ])
555 if vals.cmdline_ip:
556 cmdline_ip = strip('ip=', vals.cmdline_ip)
557 config_image.append(['ip', cmdline_ip])
558 if vals.root:
559 cmdline_root = strip('root=', vals.root)
560 config_image.append(['root', cmdline_root])
561 if vals.extra:
562 config_image.append(['args', vals.extra])
564 if vals.builder == 'hvm':
565 configure_hvm(config_image, vals)
567 if vals.vhpt != 0:
568 config_image.append(['vhpt', vals.vhpt])
570 return config_image
572 def configure_disks(config_devs, vals):
573 """Create the config for disks (virtual block devices).
574 """
575 for (uname, dev, mode, backend) in vals.disk:
576 if uname.startswith('tap:'):
577 cls = 'tap'
578 else:
579 cls = 'vbd'
581 config_vbd = [cls,
582 ['uname', uname],
583 ['dev', dev ],
584 ['mode', mode ] ]
585 if backend:
586 config_vbd.append(['backend', backend])
587 config_devs.append(['device', config_vbd])
589 def configure_pci(config_devs, vals):
590 """Create the config for pci devices.
591 """
592 config_pci = []
593 for (domain, bus, slot, func) in vals.pci:
594 config_pci.append(['dev', ['domain', domain], ['bus', bus], \
595 ['slot', slot], ['func', func]])
597 if len(config_pci)>0:
598 config_pci.insert(0, 'pci')
599 config_devs.append(['device', config_pci])
601 def configure_ioports(config_devs, vals):
602 """Create the config for legacy i/o ranges.
603 """
604 for (io_from, io_to) in vals.ioports:
605 config_ioports = ['ioports', ['from', io_from], ['to', io_to]]
606 config_devs.append(['device', config_ioports])
608 def configure_irq(config_devs, vals):
609 """Create the config for irqs.
610 """
611 for irq in vals.irq:
612 config_irq = ['irq', ['irq', irq]]
613 config_devs.append(['device', config_irq])
615 def configure_vfbs(config_devs, vals):
616 for f in vals.vfb:
617 d = comma_sep_kv_to_dict(f)
618 config = ['vfb']
619 if not d.has_key("type"):
620 d['type'] = 'sdl'
621 for (k,v) in d.iteritems():
622 if not k in [ 'vnclisten', 'vncunused', 'vncdisplay', 'display',
623 'xauthority', 'type', 'vncpasswd' ]:
624 err("configuration option %s unknown to vfbs" % k)
625 config.append([k,v])
626 if not d.has_key("keymap"):
627 if vals.keymap:
628 config.append(['keymap',vals.keymap])
629 if not d.has_key("display") and os.environ.has_key("DISPLAY"):
630 config.append(["display", os.environ['DISPLAY']])
631 if not d.has_key("xauthority"):
632 config.append(["xauthority", get_xauthority()])
633 config_devs.append(['device', ['vkbd']])
634 config_devs.append(['device', config])
636 def configure_security(config, vals):
637 """Create the config for ACM security labels.
638 """
639 access_control = vals.access_control
640 num = len(access_control)
641 if num == 1:
642 d = access_control[0]
643 policy = d.get('policy')
644 label = d.get('label')
645 if policy != security.active_policy:
646 err("Security policy (" + policy + ") incompatible with enforced policy ("
647 + security.active_policy + ")." )
648 config_access_control = ['access_control',
649 ['policy', policy],
650 ['label', label] ]
652 security_label = ['security', [ config_access_control ] ]
653 config.append(security_label)
654 elif num > 1:
655 err("VM config error: Multiple access_control definitions!")
658 def configure_vtpm(config_devs, vals):
659 """Create the config for virtual TPM interfaces.
660 """
661 vtpm = vals.vtpm
662 if len(vtpm) > 0:
663 d = vtpm[0]
664 instance = d.get('instance')
665 if instance == "VTPMD":
666 instance = "0"
667 else:
668 if instance != None:
669 try:
670 if int(instance) == 0:
671 err('VM config error: vTPM instance must not be 0.')
672 except ValueError:
673 err('Vm config error: could not parse instance number.')
674 backend = d.get('backend')
675 typ = d.get('type')
676 config_vtpm = ['vtpm']
677 if instance:
678 config_vtpm.append(['pref_instance', instance])
679 if backend:
680 config_vtpm.append(['backend', backend])
681 if typ:
682 config_vtpm.append(['type', type])
683 config_devs.append(['device', config_vtpm])
686 def configure_vifs(config_devs, vals):
687 """Create the config for virtual network interfaces.
688 """
690 vifs = vals.vif
691 vifs_n = len(vifs)
693 if hasattr(vals, 'nics'):
694 if vals.nics > 0:
695 warn("The nics option is deprecated. Please use an empty vif "
696 "entry instead:\n\n vif = [ '' ]\n")
697 for _ in range(vifs_n, vals.nics):
698 vifs.append('')
699 vifs_n = len(vifs)
700 elif vals.nics == 0:
701 warn("The nics option is deprecated. Please remove it.")
703 for c in vifs:
704 d = comma_sep_kv_to_dict(c)
705 config_vif = ['vif']
707 def f(k):
708 if k not in ['backend', 'bridge', 'ip', 'mac', 'script', 'type',
709 'vifname', 'rate', 'model', 'accel',
710 'policy', 'label']:
711 err('Invalid vif option: ' + k)
713 config_vif.append([k, d[k]])
715 map(f, d.keys())
716 config_devs.append(['device', config_vif])
719 def configure_hvm(config_image, vals):
720 """Create the config for HVM devices.
721 """
722 args = [ 'device_model', 'pae', 'vcpus', 'boot', 'fda', 'fdb', 'timer_mode',
723 'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'soundhw',
724 'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten',
725 'sdl', 'display', 'xauthority', 'rtc_timeoffset', 'monitor',
726 'acpi', 'apic', 'usb', 'usbdevice', 'keymap', 'pci',
727 'guest_os_type']
729 for a in args:
730 if a in vals.__dict__ and vals.__dict__[a] is not None:
731 config_image.append([a, vals.__dict__[a]])
732 if vals.vncpasswd is not None:
733 config_image.append(['vncpasswd', vals.vncpasswd])
736 def make_config(vals):
737 """Create the domain configuration.
738 """
740 config = ['vm']
742 def add_conf(n):
743 if hasattr(vals, n):
744 v = getattr(vals, n)
745 if v:
746 config.append([n, v])
748 map(add_conf, ['name', 'memory', 'maxmem', 'shadow_memory',
749 'restart', 'on_poweroff',
750 'on_reboot', 'on_crash', 'vcpus', 'vcpu_avail', 'features',
751 'on_xend_start', 'on_xend_stop'])
753 if vals.uuid is not None:
754 config.append(['uuid', vals.uuid])
755 if vals.cpu is not None:
756 config.append(['cpu', vals.cpu])
757 if vals.cpus is not None:
758 config.append(['cpus', vals.cpus])
759 if vals.cpu_cap is not None:
760 config.append(['cpu_cap', vals.cpu_cap])
761 if vals.cpu_weight is not None:
762 config.append(['cpu_weight', vals.cpu_weight])
763 if vals.blkif:
764 config.append(['backend', ['blkif']])
765 if vals.netif:
766 config.append(['backend', ['netif']])
767 if vals.tpmif:
768 config.append(['backend', ['tpmif']])
769 if vals.localtime:
770 config.append(['localtime', vals.localtime])
772 config_image = configure_image(vals)
773 if vals.bootloader:
774 if vals.bootloader == "pygrub":
775 vals.bootloader = osdep.pygrub_path
777 config.append(['bootloader', vals.bootloader])
778 if vals.bootargs:
779 config.append(['bootloader_args', vals.bootargs])
780 else:
781 if vals.console_autoconnect:
782 config.append(['bootloader_args', ''])
783 else:
784 config.append(['bootloader_args', '-q'])
785 config.append(['image', config_image])
787 config_devs = []
788 configure_disks(config_devs, vals)
789 configure_pci(config_devs, vals)
790 configure_ioports(config_devs, vals)
791 configure_irq(config_devs, vals)
792 configure_vifs(config_devs, vals)
793 configure_vtpm(config_devs, vals)
794 configure_vfbs(config_devs, vals)
795 configure_security(config, vals)
796 config += config_devs
798 return config
800 def preprocess_disk(vals):
801 if not vals.disk: return
802 disk = []
803 for v in vals.disk:
804 d = v.split(',')
805 n = len(d)
806 if n == 3:
807 d.append(None)
808 elif n == 4:
809 pass
810 else:
811 err('Invalid disk specifier: ' + v)
812 disk.append(d)
813 vals.disk = disk
815 def preprocess_pci(vals):
816 if not vals.pci: return
817 pci = []
818 for pci_dev_str in vals.pci:
819 pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \
820 r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \
821 r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \
822 r"(?P<func>[0-9a-fA-F])", pci_dev_str)
823 if pci_match!=None:
824 pci_dev_info = pci_match.groupdict('0')
825 try:
826 pci.append( ('0x'+pci_dev_info['domain'], \
827 '0x'+pci_dev_info['bus'], \
828 '0x'+pci_dev_info['slot'], \
829 '0x'+pci_dev_info['func']))
830 except IndexError:
831 err('Error in PCI slot syntax "%s"'%(pci_dev_str))
832 vals.pci = pci
834 def preprocess_ioports(vals):
835 if not vals.ioports: return
836 ioports = []
837 for v in vals.ioports:
838 d = v.split('-')
839 if len(d) < 1 or len(d) > 2:
840 err('Invalid i/o port range specifier: ' + v)
841 if len(d) == 1:
842 d.append(d[0])
843 # Components are in hex: add hex specifier.
844 hexd = ['0x' + x for x in d]
845 ioports.append(hexd)
846 vals.ioports = ioports
848 def preprocess_vtpm(vals):
849 if not vals.vtpm: return
850 vtpms = []
851 for vtpm in vals.vtpm:
852 d = {}
853 a = vtpm.split(',')
854 for b in a:
855 (k, v) = b.strip().split('=', 1)
856 k = k.strip()
857 v = v.strip()
858 if k not in ['backend', 'instance']:
859 err('Invalid vtpm specifier: ' + vtpm)
860 d[k] = v
861 vtpms.append(d)
862 vals.vtpm = vtpms
864 def preprocess_access_control(vals):
865 if not vals.access_control:
866 return
867 access_controls = []
868 num = len(vals.access_control)
869 if num == 1:
870 access_control = (vals.access_control)[0]
871 d = {}
872 a = access_control.split(',')
873 if len(a) > 2:
874 err('Too many elements in access_control specifier: ' + access_control)
875 for b in a:
876 (k, v) = b.strip().split('=', 1)
877 k = k.strip()
878 v = v.strip()
879 if k not in ['policy','label']:
880 err('Invalid access_control specifier: ' + access_control)
881 d[k] = v
882 access_controls.append(d)
883 vals.access_control = access_controls
884 elif num > 1:
885 err('Multiple access_control definitions.')
887 def preprocess_ip(vals):
888 if vals.ip or vals.dhcp != 'off':
889 dummy_nfs_server = '127.0.255.255'
890 ip = (vals.ip
891 + ':' + (vals.nfs_server or dummy_nfs_server)
892 + ':' + vals.gateway
893 + ':' + vals.netmask
894 + ':' + vals.hostname
895 + ':' + vals.interface
896 + ':' + vals.dhcp)
897 else:
898 ip = ''
899 vals.cmdline_ip = ip
901 def preprocess_nfs(vals):
902 if not vals.nfs_root: return
903 if not vals.nfs_server:
904 err('Must set nfs root and nfs server')
905 nfs = 'nfsroot=' + vals.nfs_server + ':' + vals.nfs_root
906 vals.extra = nfs + ' ' + vals.extra
909 def get_host_addr():
910 host = socket.gethostname()
911 addr = socket.gethostbyname(host)
912 return addr
914 VNC_BASE_PORT = 5500
916 def choose_vnc_display():
917 """Try to choose a free vnc display.
918 """
919 def netstat_local_ports():
920 """Run netstat to get a list of the local ports in use.
921 """
922 l = os.popen("netstat -nat").readlines()
923 r = []
924 # Skip 2 lines of header.
925 for x in l[2:]:
926 # Local port is field 3.
927 y = x.split()[3]
928 # Field is addr:port, split off the port.
929 y = y.split(':')[-1]
930 r.append(int(y))
931 return r
933 ports = netstat_local_ports()
934 for d in range(1, 100):
935 port = VNC_BASE_PORT + d
936 if port in ports: continue
937 return d
938 return None
939 vncpid = None
941 def daemonize(prog, args):
942 """Runs a program as a daemon with the list of arguments. Returns the PID
943 of the daemonized program, or returns 0 on error.
944 """
945 r, w = os.pipe()
946 pid = os.fork()
948 if pid == 0:
949 os.close(r)
950 w = os.fdopen(w, 'w')
951 os.setsid()
952 try:
953 pid2 = os.fork()
954 except:
955 pid2 = None
956 if pid2 == 0:
957 os.chdir("/")
958 for fd in range(0, 256):
959 try:
960 os.close(fd)
961 except:
962 pass
963 os.open("/dev/null", os.O_RDWR)
964 os.dup2(0, 1)
965 os.dup2(0, 2)
966 os.execvp(prog, args)
967 os._exit(1)
968 else:
969 w.write(str(pid2 or 0))
970 w.close()
971 os._exit(0)
972 os.close(w)
973 r = os.fdopen(r)
974 daemon_pid = int(r.read())
975 r.close()
976 os.waitpid(pid, 0)
977 return daemon_pid
979 def spawn_vnc(display):
980 """Spawns a vncviewer that listens on the specified display. On success,
981 returns the port that the vncviewer is listening on and sets the global
982 vncpid. On failure, returns 0. Note that vncviewer is daemonized.
983 """
984 vncargs = (["vncviewer", "-log", "*:stdout:0",
985 "-listen", "%d" % (VNC_BASE_PORT + display) ])
986 global vncpid
987 vncpid = daemonize("vncviewer", vncargs)
988 if vncpid == 0:
989 return 0
991 return VNC_BASE_PORT + display
993 def preprocess_vnc(vals):
994 """If vnc was specified, spawn a vncviewer in listen mode
995 and pass its address to the domain on the kernel command line.
996 """
997 if vals.dryrun: return
998 if vals.vncviewer:
999 vnc_display = choose_vnc_display()
1000 if not vnc_display:
1001 warn("No free vnc display")
1002 return
1003 print 'VNC=', vnc_display
1004 vnc_port = spawn_vnc(vnc_display)
1005 if vnc_port > 0:
1006 vnc_host = get_host_addr()
1007 vnc = 'VNC_VIEWER=%s:%d' % (vnc_host, vnc_port)
1008 vals.extra = vnc + ' ' + vals.extra
1010 def preprocess(vals):
1011 preprocess_disk(vals)
1012 preprocess_pci(vals)
1013 preprocess_ioports(vals)
1014 preprocess_ip(vals)
1015 preprocess_nfs(vals)
1016 preprocess_vnc(vals)
1017 preprocess_vtpm(vals)
1018 preprocess_access_control(vals)
1021 def comma_sep_kv_to_dict(c):
1022 """Convert comma-separated, equals-separated key-value pairs into a
1023 dictionary.
1024 """
1025 d = {}
1026 c = c.strip()
1027 if len(c) > 0:
1028 a = c.split(',')
1029 for b in a:
1030 if b.find('=') == -1:
1031 err("%s should be a pair, separated by an equals sign." % b)
1032 (k, v) = b.split('=', 1)
1033 k = k.strip()
1034 v = v.strip()
1035 d[k] = v
1036 return d
1039 def make_domain(opts, config):
1040 """Create, build and start a domain.
1042 @param opts: options
1043 @param config: configuration
1044 @return: domain id
1045 @rtype: int
1046 """
1048 try:
1049 dominfo = server.xend.domain.create(config)
1050 except xmlrpclib.Fault, ex:
1051 import signal
1052 if vncpid:
1053 os.kill(vncpid, signal.SIGKILL)
1054 if ex.faultCode == xen.xend.XendClient.ERROR_INVALID_DOMAIN:
1055 err("the domain '%s' does not exist." % ex.faultString)
1056 else:
1057 err("%s" % ex.faultString)
1058 except Exception, ex:
1059 # main.py has good error messages that let the user know what failed.
1060 # unless the error is a create.py specific thing, it should be handled
1061 # at main. The purpose of this general-case 'Exception' handler is to
1062 # clean up create.py specific processes/data but since create.py does
1063 # not know what to do with the error, it should pass it up.
1064 import signal
1065 if vncpid:
1066 os.kill(vncpid, signal.SIGKILL)
1067 raise
1069 dom = sxp.child_value(dominfo, 'name')
1071 try:
1072 server.xend.domain.waitForDevices(dom)
1073 except xmlrpclib.Fault, ex:
1074 server.xend.domain.destroy(dom)
1075 err("%s" % ex.faultString)
1076 except:
1077 server.xend.domain.destroy(dom)
1078 err("Device creation failed for domain %s" % dom)
1080 if not opts.vals.paused:
1081 try:
1082 server.xend.domain.unpause(dom)
1083 except:
1084 server.xend.domain.destroy(dom)
1085 err("Failed to unpause domain %s" % dom)
1086 opts.info("Started domain %s" % (dom))
1087 return int(sxp.child_value(dominfo, 'domid'))
1090 def get_xauthority():
1091 xauth = os.getenv("XAUTHORITY")
1092 if not xauth:
1093 home = os.getenv("HOME")
1094 if not home:
1095 import posix, pwd
1096 home = pwd.getpwuid(posix.getuid())[5]
1097 xauth = home + "/.Xauthority"
1098 return xauth
1101 def parseCommandLine(argv):
1102 gopts.reset()
1103 args = gopts.parse(argv)
1105 if gopts.vals.help or gopts.vals.help_config:
1106 if gopts.vals.help_config:
1107 print gopts.val_usage()
1108 return (None, None)
1110 if not gopts.vals.display:
1111 gopts.vals.display = os.getenv("DISPLAY")
1113 if not gopts.vals.xauthority:
1114 gopts.vals.xauthority = get_xauthority()
1116 gopts.is_xml = False
1118 # Process remaining args as config variables.
1119 for arg in args:
1120 if '=' in arg:
1121 (var, val) = arg.strip().split('=', 1)
1122 gopts.setvar(var.strip(), val.strip())
1123 if gopts.vals.config:
1124 config = gopts.vals.config
1125 else:
1126 try:
1127 gopts.load_defconfig()
1128 preprocess(gopts.vals)
1129 if not gopts.getopt('name') and gopts.getopt('defconfig'):
1130 gopts.setopt('name', os.path.basename(gopts.getopt('defconfig')))
1131 config = make_config(gopts.vals)
1132 except XMLFileError, ex:
1133 XMLFile = ex.getFile()
1134 gopts.is_xml = True
1135 config = ex.getFile()
1137 return (gopts, config)
1139 def help():
1140 return str(gopts)
1142 def main(argv):
1143 is_xml = False
1145 try:
1146 (opts, config) = parseCommandLine(argv)
1147 except StandardError, ex:
1148 err(str(ex))
1150 if not opts:
1151 return
1153 if not opts.is_xml:
1154 if type(config) == str:
1155 try:
1156 config = sxp.parse(file(config))[0]
1157 except IOError, exn:
1158 raise OptionError("Cannot read file %s: %s" % (config, exn[1]))
1160 if serverType == SERVER_XEN_API:
1161 from xen.xm.xenapi_create import sxp2xml
1162 sxp2xml_inst = sxp2xml()
1163 doc = sxp2xml_inst.convert_sxp_to_xml(config, transient=True)
1165 if opts.vals.dryrun and not opts.is_xml:
1166 SXPPrettyPrint.prettyprint(config)
1168 if opts.vals.xmldryrun and serverType == SERVER_XEN_API:
1169 from xml.dom.ext import PrettyPrint as XMLPrettyPrint
1170 XMLPrettyPrint(doc)
1172 if opts.vals.dryrun or opts.vals.xmldryrun:
1173 return
1175 if opts.vals.console_autoconnect:
1176 do_console(sxp.child_value(config, 'name', -1))
1178 if serverType == SERVER_XEN_API:
1179 from xen.xm.xenapi_create import xenapi_create
1180 xenapi_create_inst = xenapi_create()
1181 if opts.is_xml:
1182 vm_refs = xenapi_create_inst.create(filename = config,
1183 skipdtd = opts.vals.skipdtd)
1184 else:
1185 vm_refs = xenapi_create_inst.create(document = doc,
1186 skipdtd = opts.vals.skipdtd)
1188 map(lambda vm_ref: server.xenapi.VM.start(vm_ref, 0), vm_refs)
1189 elif not opts.is_xml:
1190 dom = make_domain(opts, config)
1192 def do_console(domain_name):
1193 cpid = os.fork()
1194 if cpid != 0:
1195 for i in range(10):
1196 # Catch failure of the create process
1197 time.sleep(1)
1198 (p, rv) = os.waitpid(cpid, os.WNOHANG)
1199 if os.WIFEXITED(rv):
1200 if os.WEXITSTATUS(rv) != 0:
1201 sys.exit(os.WEXITSTATUS(rv))
1202 try:
1203 # Acquire the console of the created dom
1204 if serverType == SERVER_XEN_API:
1205 domid = server.xenapi.VM.get_domid(
1206 get_single_vm(domain_name))
1207 else:
1208 dom = server.xend.domain(domain_name)
1209 domid = int(sxp.child_value(dom, 'domid', '-1'))
1210 console.execConsole(domid)
1211 except:
1212 pass
1213 print("Could not start console\n");
1214 sys.exit(0)
1216 if __name__ == '__main__':
1217 main(sys.argv)