ia64/xen-unstable

view tools/python/xen/xm/create.py @ 8669:2cb434a12bba

Treat xenstore UUID for domU's like MAC addresses for virtual network
interfaces -- can be set by user in domU configuration, but is
generated randomly by default.

Signed-off-by: Andrew D. Ball <aball@us.ibm.com>
author emellor@leeni.uk.xensource.com
date Thu Jan 26 00:10:03 2006 +0100 (2006-01-26)
parents 412995d28a07
children f1b361b05bf3
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 XenSource Ltd
18 #============================================================================
20 """Domain creation.
21 """
22 import os
23 import os.path
24 import string
25 import sys
26 import socket
27 import commands
28 import time
30 import xen.lowlevel.xc
32 from xen.xend import sxp
33 from xen.xend import PrettyPrint
34 from xen.xend.XendClient import server, XendError
35 from xen.xend.XendBootloader import bootloader
36 from xen.util import blkif
38 from xen.xm.opts import *
40 import console
43 gopts = Opts(use="""[options] [vars]
45 Create a domain.
47 Domain creation parameters can be set by command-line switches, from
48 a python configuration script or an SXP config file. See documentation
49 for --defconfig, --config. Configuration variables can be set using
50 VAR=VAL on the command line. For example vmid=3 sets vmid to 3.
52 """)
54 gopts.opt('help', short='h',
55 fn=set_true, default=0,
56 use="Print this help.")
58 gopts.opt('help_config',
59 fn=set_true, default=0,
60 use="Print help for the configuration script.")
62 gopts.opt('quiet', short='q',
63 fn=set_true, default=0,
64 use="Quiet.")
66 gopts.opt('path', val='PATH',
67 fn=set_value, default='.:/etc/xen',
68 use="""Search path for configuration scripts.
69 The value of PATH is a colon-separated directory list.""")
71 gopts.opt('defconfig', short='f', val='FILE',
72 fn=set_value, default='xmdefconfig',
73 use="""Use the given Python configuration script.
74 The configuration script is loaded after arguments have been processed.
75 Each command-line option sets a configuration variable named after
76 its long option name, and these variables are placed in the
77 environment of the script before it is loaded.
78 Variables for options that may be repeated have list values.
79 Other variables can be set using VAR=VAL on the command line.
81 After the script is loaded, option values that were not set on the
82 command line are replaced by the values set in the script.""")
84 gopts.default('defconfig')
86 gopts.opt('config', short='F', val='FILE',
87 fn=set_value, default=None,
88 use="""Domain configuration to use (SXP).
89 SXP is the underlying configuration format used by Xen.
90 SXP configurations can be hand-written or generated from Python configuration
91 scripts, using the -n (dryrun) option to print the configuration.""")
93 gopts.opt('load', short='L', val='FILE',
94 fn=set_value, default=None,
95 use='Domain saved state to load.')
97 gopts.opt('dryrun', short='n',
98 fn=set_true, default=0,
99 use="""Dry run - print the configuration but don't create the domain.
100 Loads the configuration script, creates the SXP configuration and prints it.""")
102 gopts.opt('paused', short='p',
103 fn=set_true, default=0,
104 use='Leave the domain paused after it is created.')
106 gopts.opt('console_autoconnect', short='c',
107 fn=set_true, default=0,
108 use="Connect to the console after the domain is created.")
110 gopts.var('vncviewer', val='no|yes',
111 fn=set_bool, default=None,
112 use="""Spawn a vncviewer listening for a vnc server in the domain.
113 The address of the vncviewer is passed to the domain on the kernel command
114 line using 'VNC_SERVER=<host>:<port>'. The port used by vnc is 5500 + DISPLAY.
115 A display value with a free port is chosen if possible.
116 Only valid when vnc=1.
117 """)
119 gopts.var('name', val='NAME',
120 fn=set_value, default=None,
121 use="Domain name. Must be unique.")
123 gopts.var('bootloader', val='FILE',
124 fn=set_value, default=None,
125 use="Path to bootloader.")
127 gopts.var('bootentry', val='NAME',
128 fn=set_value, default=None,
129 use="Entry to boot via boot loader")
131 gopts.var('kernel', val='FILE',
132 fn=set_value, default=None,
133 use="Path to kernel image.")
135 gopts.var('ramdisk', val='FILE',
136 fn=set_value, default='',
137 use="Path to ramdisk.")
139 gopts.var('builder', val='FUNCTION',
140 fn=set_value, default='linux',
141 use="Function to use to build the domain.")
143 gopts.var('memory', val='MEMORY',
144 fn=set_int, default=128,
145 use="Domain memory in MB.")
147 gopts.var('ssidref', val='SSIDREF',
148 fn=set_u32, default=0,
149 use="Security Identifier.")
151 gopts.var('maxmem', val='MEMORY',
152 fn=set_int, default=None,
153 use="Maximum domain memory in MB.")
155 gopts.var('cpu', val='CPU',
156 fn=set_int, default=None,
157 use="CPU to run the VCPU0 on.")
159 gopts.var('cpus', val='CPUS',
160 fn=set_int, default=None,
161 use="CPUS to run the domain on.")
163 gopts.var('acpi', val='ACPI',
164 fn=set_int, default=0,
165 use="Disable or enable ACPI of VMX domain.")
167 gopts.var('apic', val='APIC',
168 fn=set_int, default=0,
169 use="Disable or enable APIC of VMX domain.")
171 gopts.var('vcpus', val='VCPUS',
172 fn=set_int, default=1,
173 use="# of Virtual CPUS in domain.")
175 gopts.var('cpu_weight', val='WEIGHT',
176 fn=set_float, default=None,
177 use="""Set the new domain's cpu weight.
178 WEIGHT is a float that controls the domain's share of the cpu.""")
180 gopts.var('restart', val='onreboot|always|never',
181 fn=set_value, default=None,
182 use="""Deprecated. Use on_poweroff, on_reboot, and on_crash
183 instead.
185 Whether the domain should be restarted on exit.
186 - onreboot: restart on exit with shutdown code reboot
187 - always: always restart on exit, ignore exit code
188 - never: never restart on exit, ignore exit code""")
190 gopts.var('on_poweroff', val='destroy|restart|preserve|rename-restart',
191 fn=set_value, default=None,
192 use="""Behaviour when a domain exits with reason 'poweroff'.
193 - destroy: the domain is cleaned up as normal;
194 - restart: a new domain is started in place of the old one;
195 - preserve: no clean-up is done until the domain is manually
196 destroyed (using xm destroy, for example);
197 - rename-restart: the old domain is not cleaned up, but is
198 renamed and a new domain started in its place.
199 """)
201 gopts.var('on_reboot', val='destroy|restart|preserve|rename-restart',
202 fn=set_value, default=None,
203 use="""Behaviour when a domain exits with reason 'reboot'.
204 - destroy: the domain is cleaned up as normal;
205 - restart: a new domain is started in place of the old one;
206 - preserve: no clean-up is done until the domain is manually
207 destroyed (using xm destroy, for example);
208 - rename-restart: the old domain is not cleaned up, but is
209 renamed and a new domain started in its place.
210 """)
212 gopts.var('on_crash', val='destroy|restart|preserve|rename-restart',
213 fn=set_value, default=None,
214 use="""Behaviour when a domain exits with reason 'crash'.
215 - destroy: the domain is cleaned up as normal;
216 - restart: a new domain is started in place of the old one;
217 - preserve: no clean-up is done until the domain is manually
218 destroyed (using xm destroy, for example);
219 - rename-restart: the old domain is not cleaned up, but is
220 renamed and a new domain started in its place.
221 """)
223 gopts.var('blkif', val='no|yes',
224 fn=set_bool, default=0,
225 use="Make the domain a block device backend.")
227 gopts.var('netif', val='no|yes',
228 fn=set_bool, default=0,
229 use="Make the domain a network interface backend.")
231 gopts.var('tpmif', val='no|yes',
232 fn=append_value, default=0,
233 use="Make the domain a TPM interface backend.")
235 gopts.var('disk', val='phy:DEV,VDEV,MODE[,DOM]',
236 fn=append_value, default=[],
237 use="""Add a disk device to a domain. The physical device is DEV,
238 which is exported to the domain as VDEV. The disk is read-only if MODE
239 is 'r', read-write if MODE is 'w'. If DOM is specified it defines the
240 backend driver domain to use for the disk.
241 The option may be repeated to add more than one disk.""")
243 gopts.var('pci', val='BUS,DEV,FUNC',
244 fn=append_value, default=[],
245 use="""Add a PCI device to a domain, using given params (in hex).
246 For example '-pci c0,02,1a'.
247 The option may be repeated to add more than one pci device.""")
249 gopts.var('ioports', val='FROM[-TO]',
250 fn=append_value, default=[],
251 use="""Add a legacy I/O range to a domain, using given params (in hex).
252 For example '-ioports 02f8-02ff'.
253 The option may be repeated to add more than one i/o range.""")
255 gopts.var('usb', val='PATH',
256 fn=append_value, default=[],
257 use="""Add a physical USB port to a domain, as specified by the path
258 to that port. This option may be repeated to add more than one port.""")
260 gopts.var('vif', val="type=TYPE,mac=MAC,bridge=BRIDGE,ip=IPADDR,script=SCRIPT,backend=DOM,vifname=NAME",
261 fn=append_value, default=[],
262 use="""Add a network interface with the given MAC address and bridge.
263 The vif is configured by calling the given configuration script.
264 If type is not specified, default is netfront not ioemu device.
265 If mac is not specified a random MAC address is used.
266 If not specified then the network backend chooses it's own MAC address.
267 If bridge is not specified the first bridge found is used.
268 If script is not specified the default script is used.
269 If backend is not specified the default backend driver domain is used.
270 If vifname is not specified the backend virtual interface will have name vifD.N
271 where D is the domain id and N is the interface id.
272 This option may be repeated to add more than one vif.
273 Specifying vifs will increase the number of interfaces as needed.""")
275 gopts.var('vtpm', val="instance=INSTANCE,backend=DOM",
276 fn=append_value, default=[],
277 use="""Add a TPM interface. On the backend side use the given
278 instance as virtual TPM instance. The given number is merely the
279 preferred instance number. The hotplug script will determine
280 which instance number will actually be assigned to the domain.
281 The associtation between virtual machine and the TPM instance
282 number can be found in /etc/xen/vtpm.db. Use the backend in the
283 given domain.""")
285 gopts.var('nics', val="NUM",
286 fn=set_int, default=-1,
287 use="""DEPRECATED. Use empty vif entries instead.
289 Set the number of network interfaces.
290 Use the vif option to define interface parameters, otherwise
291 defaults are used. Specifying vifs will increase the
292 number of interfaces as needed.""")
294 gopts.var('root', val='DEVICE',
295 fn=set_value, default='',
296 use="""Set the root= parameter on the kernel command line.
297 Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""")
299 gopts.var('extra', val="ARGS",
300 fn=set_value, default='',
301 use="Set extra arguments to append to the kernel command line.")
303 gopts.var('ip', val='IPADDR',
304 fn=set_value, default='',
305 use="Set the kernel IP interface address.")
307 gopts.var('gateway', val="IPADDR",
308 fn=set_value, default='',
309 use="Set the kernel IP gateway.")
311 gopts.var('netmask', val="MASK",
312 fn=set_value, default = '',
313 use="Set the kernel IP netmask.")
315 gopts.var('hostname', val="NAME",
316 fn=set_value, default='',
317 use="Set the kernel IP hostname.")
319 gopts.var('interface', val="INTF",
320 fn=set_value, default="eth0",
321 use="Set the kernel IP interface name.")
323 gopts.var('dhcp', val="off|dhcp",
324 fn=set_value, default='off',
325 use="Set the kernel dhcp option.")
327 gopts.var('nfs_server', val="IPADDR",
328 fn=set_value, default=None,
329 use="Set the address of the NFS server for NFS root.")
331 gopts.var('nfs_root', val="PATH",
332 fn=set_value, default=None,
333 use="Set the path of the root NFS directory.")
335 gopts.var('device_model', val='FILE',
336 fn=set_value, default='',
337 use="Path to device model program.")
339 gopts.var('fda', val='FILE',
340 fn=set_value, default='',
341 use="Path to fda")
343 gopts.var('fdb', val='FILE',
344 fn=set_value, default='',
345 use="Path to fdb")
347 gopts.var('serial', val='FILE',
348 fn=set_value, default='',
349 use="Path to serial or pty or vc")
351 gopts.var('localtime', val='no|yes',
352 fn=set_bool, default=0,
353 use="Is RTC set to localtime?")
355 gopts.var('stdvga', val='no|yes',
356 fn=set_bool, default=0,
357 use="Use std vga or cirrhus logic graphics")
359 gopts.var('isa', val='no|yes',
360 fn=set_bool, default=0,
361 use="Simulate an ISA only system?")
363 gopts.var('cdrom', val='FILE',
364 fn=set_value, default='',
365 use="Path to cdrom")
367 gopts.var('boot', val="a|b|c|d",
368 fn=set_value, default='c',
369 use="Default boot device")
371 gopts.var('nographic', val='no|yes',
372 fn=set_bool, default=0,
373 use="Should device models use graphics?")
375 gopts.var('ne2000', val='no|yes',
376 fn=set_bool, default=0,
377 use="Should device models use ne2000?")
379 gopts.var('audio', val='no|yes',
380 fn=set_bool, default=0,
381 use="Should device models enable audio?")
383 gopts.var('vnc', val='',
384 fn=set_value, default=None,
385 use="""Should the device model use VNC?""")
387 gopts.var('sdl', val='',
388 fn=set_value, default=None,
389 use="""Should the device model use SDL?""")
391 gopts.var('display', val='DISPLAY',
392 fn=set_value, default=None,
393 use="X11 display to use")
395 gopts.var('xauthority', val='XAUTHORITY',
396 fn=set_value, default=None,
397 use="X11 Authority to use")
399 gopts.var('uuid', val='',
400 fn=set_value, default=None,
401 use="""xenstore UUID (universally unique identifier) to use. One
402 will be randomly generated if this option is not set, just like MAC
403 addresses for virtual network interfaces. This must be a unique
404 value across the entire cluster.""")
407 def err(msg):
408 """Print an error to stderr and exit.
409 """
410 print >>sys.stderr, "Error:", msg
411 sys.exit(1)
414 def warn(msg):
415 """Print a warning to stdout.
416 """
417 print >>sys.stderr, "Warning:", msg
420 def strip(pre, s):
421 """Strip prefix 'pre' if present.
422 """
423 if s.startswith(pre):
424 return s[len(pre):]
425 else:
426 return s
428 def configure_image(vals):
429 """Create the image config.
430 """
431 config_image = [ vals.builder ]
432 config_image.append([ 'kernel', os.path.abspath(vals.kernel) ])
433 if vals.ramdisk:
434 config_image.append([ 'ramdisk', os.path.abspath(vals.ramdisk) ])
435 if vals.cmdline_ip:
436 cmdline_ip = strip('ip=', vals.cmdline_ip)
437 config_image.append(['ip', cmdline_ip])
438 if vals.root:
439 cmdline_root = strip('root=', vals.root)
440 config_image.append(['root', cmdline_root])
441 if vals.extra:
442 config_image.append(['args', vals.extra])
444 if vals.builder == 'vmx':
445 configure_vmx(config_image, vals)
447 return config_image
449 def configure_disks(config_devs, vals):
450 """Create the config for disks (virtual block devices).
451 """
452 for (uname, dev, mode, backend) in vals.disk:
453 config_vbd = ['vbd',
454 ['uname', uname],
455 ['dev', dev ],
456 ['mode', mode ] ]
457 if backend:
458 config_vbd.append(['backend', backend])
459 config_devs.append(['device', config_vbd])
461 def configure_pci(config_devs, vals):
462 """Create the config for pci devices.
463 """
464 for (bus, dev, func) in vals.pci:
465 config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]]
466 config_devs.append(['device', config_pci])
468 def configure_ioports(config_devs, vals):
469 """Create the config for legacy i/o ranges.
470 """
471 for (io_from, io_to) in vals.ioports:
472 config_ioports = ['ioports', ['from', io_from], ['to', io_to]]
473 config_devs.append(['device', config_ioports])
475 def configure_usb(config_devs, vals):
476 for path in vals.usb:
477 config_usb = ['usb', ['path', path]]
478 config_devs.append(['device', config_usb])
480 def configure_vtpm(config_devs, vals):
481 """Create the config for virtual TPM interfaces.
482 """
483 vtpm = vals.vtpm
484 vtpm_n = 1
485 for idx in range(0, vtpm_n):
486 if idx < len(vtpm):
487 d = vtpm[idx]
488 instance = d.get('instance')
489 if instance == "VTPMD":
490 instance = "0"
491 else:
492 if instance != None:
493 try:
494 if int(instance) == 0:
495 err('VM config error: vTPM instance must not be 0.')
496 except ValueError:
497 err('Vm config error: could not parse instance number.')
498 backend = d.get('backend')
499 config_vtpm = ['vtpm']
500 if instance:
501 config_vtpm.append(['pref_instance', instance])
502 if backend:
503 config_vtpm.append(['backend', backend])
504 config_devs.append(['device', config_vtpm])
507 def configure_vifs(config_devs, vals):
508 """Create the config for virtual network interfaces.
509 """
511 vifs = vals.vif
512 vifs_n = len(vifs)
514 if hasattr(vals, 'nics'):
515 if vals.nics > 0:
516 warn("The nics option is deprecated. Please use an empty vif "
517 "entry instead:\n\n vif = [ '' ]\n")
518 for _ in range(vifs_n, vals.nics):
519 vifs.append('')
520 vifs_n = len(vifs)
521 elif vals.nics == 0:
522 warn("The nics option is deprecated. Please remove it.")
524 for c in vifs:
525 d = comma_sep_kv_to_dict(c)
526 config_vif = ['vif']
528 def f(k):
529 if k not in ['backend', 'bridge', 'ip', 'mac', 'script', 'type',
530 'vifname']:
531 err('Invalid vif option: ' + k)
533 config_vif.append([k, d[k]])
535 map(f, d.keys())
536 config_devs.append(['device', config_vif])
539 def configure_vmx(config_image, vals):
540 """Create the config for VMX devices.
541 """
542 args = [ 'device_model', 'vcpus', 'cdrom', 'boot', 'fda', 'fdb',
543 'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'audio',
544 'vnc', 'vncviewer', 'sdl', 'display', 'ne2000', 'acpi', 'apic',
545 'xauthority' ]
546 for a in args:
547 if (vals.__dict__[a]):
548 config_image.append([a, vals.__dict__[a]])
550 def run_bootloader(vals):
551 if not os.access(vals.bootloader, os.X_OK):
552 err("Bootloader isn't executable")
553 if len(vals.disk) < 1:
554 err("No disks configured and boot loader requested")
555 (uname, dev, mode, backend) = vals.disk[0]
556 file = blkif.blkdev_uname_to_file(uname)
558 return bootloader(vals.bootloader, file, not vals.console_autoconnect,
559 vals.vcpus, vals.bootentry)
561 def make_config(vals):
562 """Create the domain configuration.
563 """
565 config = ['vm']
567 def add_conf(n):
568 if hasattr(vals, n):
569 v = getattr(vals, n)
570 if v:
571 config.append([n, v])
573 map(add_conf, ['name', 'memory', 'ssidref', 'maxmem', 'restart',
574 'on_poweroff', 'on_reboot', 'on_crash', 'vcpus'])
576 if vals.uuid is not None:
577 config.append(['uuid', vals.uuid])
578 if vals.cpu is not None:
579 config.append(['cpu', vals.cpu])
580 if vals.cpus is not None:
581 config.append(['cpus', vals.cpus])
582 if vals.cpu_weight is not None:
583 config.append(['cpu_weight', vals.cpu_weight])
584 if vals.blkif:
585 config.append(['backend', ['blkif']])
586 if vals.netif:
587 config.append(['backend', ['netif']])
588 if vals.tpmif:
589 config.append(['backend', ['tpmif']])
591 if vals.bootloader:
592 config.append(['bootloader', vals.bootloader])
593 config_image = run_bootloader(vals)
594 else:
595 config_image = configure_image(vals)
596 config.append(['image', config_image])
598 config_devs = []
599 configure_disks(config_devs, vals)
600 configure_pci(config_devs, vals)
601 configure_ioports(config_devs, vals)
602 configure_vifs(config_devs, vals)
603 configure_usb(config_devs, vals)
604 configure_vtpm(config_devs, vals)
605 config += config_devs
607 return config
609 def preprocess_disk(vals):
610 if not vals.disk: return
611 disk = []
612 for v in vals.disk:
613 d = v.split(',')
614 n = len(d)
615 if n == 3:
616 d.append(None)
617 elif n == 4:
618 pass
619 else:
620 err('Invalid disk specifier: ' + v)
621 disk.append(d)
622 vals.disk = disk
624 def preprocess_pci(vals):
625 if not vals.pci: return
626 pci = []
627 for v in vals.pci:
628 d = v.split(',')
629 if len(d) != 3:
630 err('Invalid pci specifier: ' + v)
631 # Components are in hex: add hex specifier.
632 hexd = map(lambda v: '0x'+v, d)
633 pci.append(hexd)
634 vals.pci = pci
636 def preprocess_ioports(vals):
637 if not vals.ioports: return
638 ioports = []
639 for v in vals.ioports:
640 d = v.split('-')
641 if len(d) < 1 or len(d) > 2:
642 err('Invalid i/o port range specifier: ' + v)
643 if len(d) == 1:
644 d.append(d[0])
645 # Components are in hex: add hex specifier.
646 hexd = map(lambda v: '0x'+v, d)
647 ioports.append(hexd)
648 vals.ioports = ioports
650 def preprocess_vtpm(vals):
651 if not vals.vtpm: return
652 vtpms = []
653 for vtpm in vals.vtpm:
654 d = {}
655 a = vtpm.split(',')
656 for b in a:
657 (k, v) = b.strip().split('=', 1)
658 k = k.strip()
659 v = v.strip()
660 if k not in ['backend', 'instance']:
661 err('Invalid vtpm specifier: ' + vtpm)
662 d[k] = v
663 vtpms.append(d)
664 vals.vtpm = vtpms
666 def preprocess_ip(vals):
667 if vals.ip or vals.dhcp != 'off':
668 dummy_nfs_server = '1.2.3.4'
669 ip = (vals.ip
670 + ':' + (vals.nfs_server or dummy_nfs_server)
671 + ':' + vals.gateway
672 + ':' + vals.netmask
673 + ':' + vals.hostname
674 + ':' + vals.interface
675 + ':' + vals.dhcp)
676 else:
677 ip = ''
678 vals.cmdline_ip = ip
680 def preprocess_nfs(vals):
681 if not vals.nfs_root: return
682 if not vals.nfs_server:
683 err('Must set nfs root and nfs server')
684 nfs = 'nfsroot=' + vals.nfs_server + ':' + vals.nfs_root
685 vals.extra = nfs + ' ' + vals.extra
688 def get_host_addr():
689 host = socket.gethostname()
690 addr = socket.gethostbyname(host)
691 return addr
693 VNC_BASE_PORT = 5500
695 def choose_vnc_display():
696 """Try to choose a free vnc display.
697 """
698 def netstat_local_ports():
699 """Run netstat to get a list of the local ports in use.
700 """
701 l = os.popen("netstat -nat").readlines()
702 r = []
703 # Skip 2 lines of header.
704 for x in l[2:]:
705 # Local port is field 3.
706 y = x.split()[3]
707 # Field is addr:port, split off the port.
708 y = y.split(':')[-1]
709 r.append(int(y))
710 return r
712 ports = netstat_local_ports()
713 for d in range(1, 100):
714 port = VNC_BASE_PORT + d
715 if port in ports: continue
716 return d
717 return None
719 vncpid = None
721 def spawn_vnc(display):
722 vncargs = (["vncviewer", "-log", "*:stdout:0",
723 "-listen", "%d" % (VNC_BASE_PORT + display) ])
724 global vncpid
725 vncpid = os.spawnvp(os.P_NOWAIT, "vncviewer", vncargs)
727 return VNC_BASE_PORT + display
729 def preprocess_vnc(vals):
730 """If vnc was specified, spawn a vncviewer in listen mode
731 and pass its address to the domain on the kernel command line.
732 """
733 if not (vals.vnc and vals.vncviewer) or vals.dryrun: return
734 vnc_display = choose_vnc_display()
735 if not vnc_display:
736 warn("No free vnc display")
737 return
738 print 'VNC=', vnc_display
739 vnc_port = spawn_vnc(vnc_display)
740 if vnc_port > 0:
741 vnc_host = get_host_addr()
742 vnc = 'VNC_VIEWER=%s:%d' % (vnc_host, vnc_port)
743 vals.extra = vnc + ' ' + vals.extra
745 def preprocess(vals):
746 if not vals.kernel and not vals.bootloader:
747 err("No kernel specified")
748 preprocess_disk(vals)
749 preprocess_pci(vals)
750 preprocess_ioports(vals)
751 preprocess_ip(vals)
752 preprocess_nfs(vals)
753 preprocess_vnc(vals)
754 preprocess_vtpm(vals)
757 def comma_sep_kv_to_dict(c):
758 """Convert comma-separated, equals-separated key-value pairs into a
759 dictionary.
760 """
761 d = {}
762 c = c.strip()
763 if len(c) > 0:
764 a = c.split(',')
765 for b in a:
766 if b.find('=') == -1:
767 err("%s should be a pair, separated by an equals sign." % b)
768 (k, v) = b.split('=', 1)
769 k = k.strip()
770 v = v.strip()
771 d[k] = v
772 return d
775 def make_domain(opts, config):
776 """Create, build and start a domain.
778 @param opts: options
779 @param config: configuration
780 @return: domain id
781 @rtype: int
782 """
784 try:
785 if opts.vals.load:
786 filename = os.path.abspath(opts.vals.load)
787 dominfo = server.xend_domain_restore(filename, config)
788 else:
789 dominfo = server.xend_domain_create(config)
790 except XendError, ex:
791 import signal
792 if vncpid:
793 os.kill(vncpid, signal.SIGKILL)
794 err(str(ex))
796 dom = sxp.child_value(dominfo, 'name')
798 if server.xend_domain_wait_for_devices(dom) < 0:
799 server.xend_domain_destroy(dom)
800 err("Device creation failed for domain %s" % dom)
802 if not opts.vals.paused:
803 if server.xend_domain_unpause(dom) < 0:
804 server.xend_domain_destroy(dom)
805 err("Failed to unpause domain %s" % dom)
806 opts.info("Started domain %s" % (dom))
807 return int(sxp.child_value(dominfo, 'domid'))
809 def parseCommandLine(argv):
810 gopts.reset()
811 args = gopts.parse(argv)
812 if gopts.vals.help:
813 gopts.usage()
814 if gopts.vals.help or gopts.vals.help_config:
815 gopts.load_defconfig(help=1)
816 if gopts.vals.help or gopts.vals.help_config:
817 return (None, None)
819 if not gopts.vals.display:
820 gopts.vals.display = os.getenv("DISPLAY")
822 if not gopts.vals.xauthority:
823 gopts.vals.xauthority = os.getenv("XAUTHORITY")
825 # Process remaining args as config variables.
826 for arg in args:
827 if '=' in arg:
828 (var, val) = arg.strip().split('=', 1)
829 gopts.setvar(var.strip(), val.strip())
830 if gopts.vals.config:
831 config = gopts.vals.config
832 else:
833 gopts.load_defconfig()
834 preprocess(gopts.vals)
835 if not gopts.getopt('name') and gopts.getopt('defconfig'):
836 gopts.setopt('name', os.path.basename(gopts.getopt('defconfig')))
837 config = make_config(gopts.vals)
839 return (gopts, config)
842 def main(argv):
843 try:
844 (opts, config) = parseCommandLine(argv)
845 except StandardError, ex:
846 err(str(ex))
848 if not opts:
849 return
851 if opts.vals.dryrun:
852 PrettyPrint.prettyprint(config)
853 else:
854 dom = make_domain(opts, config)
855 if opts.vals.console_autoconnect:
856 console.execConsole(dom)
858 if __name__ == '__main__':
859 main(sys.argv)