ia64/xen-unstable

view tools/python/xen/xm/create.py @ 6936:993f52cdb4e4

Changed ssidref default to 0 when parsing config file.

Signed-off-by: Ewan Mellor<ewan@xensource.com>
author emellor@ewan
date Sat Sep 17 10:52:31 2005 +0100 (2005-09-17)
parents 2f5537317988
children 308260e5868c c0c96a494c76
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 #============================================================================
19 """Domain creation.
20 """
21 import random
22 import string
23 import sys
24 import socket
25 import commands
26 import time
28 import xen.lowlevel.xc
30 from xen.xend import sxp
31 from xen.xend import PrettyPrint
32 from xen.xend.XendClient import server, XendError
33 from xen.xend.XendBootloader import bootloader
34 from xen.xend import XendRoot; xroot = XendRoot.instance()
35 from xen.util import blkif
37 from xen.xm.opts import *
39 gopts = Opts(use="""[options] [vars]
41 Create a domain.
43 Domain creation parameters can be set by command-line switches, from
44 a python configuration script or an SXP config file. See documentation
45 for --defconfig, --config. Configuration variables can be set using
46 VAR=VAL on the command line. For example vmid=3 sets vmid to 3.
48 """)
50 gopts.opt('help', short='h',
51 fn=set_true, default=0,
52 use="Print this help.")
54 gopts.opt('help_config',
55 fn=set_true, default=0,
56 use="Print help for the configuration script.")
58 gopts.opt('quiet', short='q',
59 fn=set_true, default=0,
60 use="Quiet.")
62 gopts.opt('path', val='PATH',
63 fn=set_value, default='.:/etc/xen',
64 use="""Search path for configuration scripts.
65 The value of PATH is a colon-separated directory list.""")
67 gopts.opt('defconfig', short='f', val='FILE',
68 fn=set_value, default='xmdefconfig',
69 use="""Use the given Python configuration script.
70 The configuration script is loaded after arguments have been processed.
71 Each command-line option sets a configuration variable named after
72 its long option name, and these variables are placed in the
73 environment of the script before it is loaded.
74 Variables for options that may be repeated have list values.
75 Other variables can be set using VAR=VAL on the command line.
77 After the script is loaded, option values that were not set on the
78 command line are replaced by the values set in the script.""")
80 gopts.default('defconfig')
82 gopts.opt('config', short='F', val='FILE',
83 fn=set_value, default=None,
84 use="""Domain configuration to use (SXP).
85 SXP is the underlying configuration format used by Xen.
86 SXP configurations can be hand-written or generated from Python configuration
87 scripts, using the -n (dryrun) option to print the configuration.""")
89 gopts.opt('load', short='L', val='FILE',
90 fn=set_value, default=None,
91 use='Domain saved state to load.')
93 gopts.opt('dryrun', short='n',
94 fn=set_true, default=0,
95 use="""Dry run - print the configuration but don't create the domain.
96 Loads the configuration script, creates the SXP configuration and prints it.""")
98 gopts.opt('paused', short='p',
99 fn=set_true, default=0,
100 use='Leave the domain paused after it is created.')
102 gopts.opt('console_autoconnect', short='c',
103 fn=set_true, default=0,
104 use="Connect to the console after the domain is created.")
106 gopts.var('vncviewer', val='no|yes',
107 fn=set_bool, default=None,
108 use="""Spawn a vncviewer listening for a vnc server in the domain.
109 The address of the vncviewer is passed to the domain on the kernel command
110 line using 'VNC_SERVER=<host>:<port>'. The port used by vnc is 5500 + DISPLAY.
111 A display value with a free port is chosen if possible.
112 Only valid when vnc=1.
113 """)
115 gopts.var('name', val='NAME',
116 fn=set_value, default=None,
117 use="Domain name. Must be unique.")
119 gopts.var('bootloader', val='FILE',
120 fn=set_value, default=None,
121 use="Path to bootloader.")
123 gopts.var('bootentry', val='NAME',
124 fn=set_value, default=None,
125 use="Entry to boot via boot loader")
127 gopts.var('kernel', val='FILE',
128 fn=set_value, default=None,
129 use="Path to kernel image.")
131 gopts.var('ramdisk', val='FILE',
132 fn=set_value, default='',
133 use="Path to ramdisk.")
135 gopts.var('builder', val='FUNCTION',
136 fn=set_value, default='linux',
137 use="Function to use to build the domain.")
139 gopts.var('memory', val='MEMORY',
140 fn=set_int, default=128,
141 use="Domain memory in MB.")
143 gopts.var('ssidref', val='SSIDREF',
144 fn=set_u32, default=0,
145 use="Security Identifier.")
147 gopts.var('maxmem', val='MEMORY',
148 fn=set_int, default=None,
149 use="Maximum domain memory in MB.")
151 gopts.var('cpu', val='CPU',
152 fn=set_int, default=None,
153 use="CPU to run the domain on.")
155 gopts.var('vcpus', val='VCPUS',
156 fn=set_int, default=1,
157 use="# of Virtual CPUS in domain.")
159 gopts.var('cpu_weight', val='WEIGHT',
160 fn=set_float, default=None,
161 use="""Set the new domain's cpu weight.
162 WEIGHT is a float that controls the domain's share of the cpu.""")
164 gopts.var('restart', val='onreboot|always|never',
165 fn=set_value, default=None,
166 use="""Whether the domain should be restarted on exit.
167 - onreboot: restart on exit with shutdown code reboot
168 - always: always restart on exit, ignore exit code
169 - never: never restart on exit, ignore exit code""")
171 gopts.var('blkif', val='no|yes',
172 fn=set_bool, default=0,
173 use="Make the domain a block device backend.")
175 gopts.var('netif', val='no|yes',
176 fn=set_bool, default=0,
177 use="Make the domain a network interface backend.")
179 gopts.var('tpmif', val='frontend=DOM',
180 fn=append_value, default=[],
181 use="""Make the domain a TPM interface backend. If frontend is given,
182 the frontend in that domain is connected to this backend (not
183 completely implemented, yet)""")
185 gopts.var('disk', val='phy:DEV,VDEV,MODE[,DOM]',
186 fn=append_value, default=[],
187 use="""Add a disk device to a domain. The physical device is DEV,
188 which is exported to the domain as VDEV. The disk is read-only if MODE
189 is 'r', read-write if MODE is 'w'. If DOM is specified it defines the
190 backend driver domain to use for the disk.
191 The option may be repeated to add more than one disk.""")
193 gopts.var('pci', val='BUS,DEV,FUNC',
194 fn=append_value, default=[],
195 use="""Add a PCI device to a domain, using given params (in hex).
196 For example '-pci c0,02,1a'.
197 The option may be repeated to add more than one pci device.""")
199 gopts.var('usb', val='PATH',
200 fn=append_value, default=[],
201 use="""Add a physical USB port to a domain, as specified by the path
202 to that port. This option may be repeated to add more than one port.""")
204 gopts.var('ipaddr', val="IPADDR",
205 fn=append_value, default=[],
206 use="Add an IP address to the domain.")
208 gopts.var('vif', val="mac=MAC,be_mac=MAC,bridge=BRIDGE,script=SCRIPT,backend=DOM,vifname=NAME",
209 fn=append_value, default=[],
210 use="""Add a network interface with the given MAC address and bridge.
211 The vif is configured by calling the given configuration script.
212 If mac is not specified a random MAC address is used.
213 The MAC address of the backend interface can be selected with be_mac.
214 If not specified then the network backend chooses it's own MAC address.
215 If bridge is not specified the default bridge is used.
216 If script is not specified the default script is used.
217 If backend is not specified the default backend driver domain is used.
218 If vifname is not specified the backend virtual interface will have name vifD.N
219 where D is the domain id and N is the interface id.
220 This option may be repeated to add more than one vif.
221 Specifying vifs will increase the number of interfaces as needed.""")
223 gopts.var('vtpm', val="instance=INSTANCE,backend=DOM",
224 fn=append_value, default=[],
225 use="""Add a tpm interface. On the backend side us the the given
226 instance as virtual TPM instance. Use the backend in the given
227 domain.""")
229 gopts.var('nics', val="NUM",
230 fn=set_int, default=1,
231 use="""Set the number of network interfaces.
232 Use the vif option to define interface parameters, otherwise
233 defaults are used. Specifying vifs will increase the
234 number of interfaces as needed.""")
236 gopts.var('root', val='DEVICE',
237 fn=set_value, default='',
238 use="""Set the root= parameter on the kernel command line.
239 Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""")
241 gopts.var('extra', val="ARGS",
242 fn=set_value, default='',
243 use="Set extra arguments to append to the kernel command line.")
245 gopts.var('ip', val='IPADDR',
246 fn=set_value, default='',
247 use="Set the kernel IP interface address.")
249 gopts.var('gateway', val="IPADDR",
250 fn=set_value, default='',
251 use="Set the kernel IP gateway.")
253 gopts.var('netmask', val="MASK",
254 fn=set_value, default = '',
255 use="Set the kernel IP netmask.")
257 gopts.var('hostname', val="NAME",
258 fn=set_value, default='',
259 use="Set the kernel IP hostname.")
261 gopts.var('interface', val="INTF",
262 fn=set_value, default="eth0",
263 use="Set the kernel IP interface name.")
265 gopts.var('dhcp', val="off|dhcp",
266 fn=set_value, default='off',
267 use="Set the kernel dhcp option.")
269 gopts.var('nfs_server', val="IPADDR",
270 fn=set_value, default=None,
271 use="Set the address of the NFS server for NFS root.")
273 gopts.var('nfs_root', val="PATH",
274 fn=set_value, default=None,
275 use="Set the path of the root NFS directory.")
277 gopts.var('memmap', val='FILE',
278 fn=set_value, default='',
279 use="Path to memap SXP file.")
281 gopts.var('device_model', val='FILE',
282 fn=set_value, default='',
283 use="Path to device model program.")
285 gopts.var('fda', val='FILE',
286 fn=set_value, default='',
287 use="Path to fda")
289 gopts.var('fdb', val='FILE',
290 fn=set_value, default='',
291 use="Path to fdb")
293 gopts.var('serial', val='FILE',
294 fn=set_value, default='',
295 use="Path to serial or pty or vc")
297 gopts.var('localtime', val='no|yes',
298 fn=set_bool, default=0,
299 use="Is RTC set to localtime?")
301 gopts.var('stdvga', val='no|yes',
302 fn=set_bool, default=0,
303 use="Use std vga or cirrhus logic graphics")
305 gopts.var('isa', val='no|yes',
306 fn=set_bool, default=0,
307 use="Simulate an ISA only system?")
309 gopts.var('cdrom', val='FILE',
310 fn=set_value, default='',
311 use="Path to cdrom")
313 gopts.var('macaddr', val='MACADDR',
314 fn=set_value, default='',
315 use="Macaddress of the first network interface")
317 gopts.var('boot', val="a|b|c|d",
318 fn=set_value, default='c',
319 use="Default boot device")
321 gopts.var('nographic', val='no|yes',
322 fn=set_bool, default=0,
323 use="Should device models use graphics?")
325 gopts.var('vnc', val='',
326 fn=set_value, default=None,
327 use="""Should the device model use VNC?""")
329 gopts.var('sdl', val='',
330 fn=set_value, default=None,
331 use="""Should the device model use SDL?""")
333 gopts.var('display', val='DISPLAY',
334 fn=set_value, default='localhost:0',
335 use="X11 display to use")
337 def strip(pre, s):
338 """Strip prefix 'pre' if present.
339 """
340 if s.startswith(pre):
341 return s[len(pre):]
342 else:
343 return s
345 def configure_image(opts, vals):
346 """Create the image config.
347 """
348 config_image = [ vals.builder ]
349 config_image.append([ 'kernel', os.path.abspath(vals.kernel) ])
350 if vals.ramdisk:
351 config_image.append([ 'ramdisk', os.path.abspath(vals.ramdisk) ])
352 if vals.cmdline_ip:
353 cmdline_ip = strip('ip=', vals.cmdline_ip)
354 config_image.append(['ip', cmdline_ip])
355 if vals.root:
356 cmdline_root = strip('root=', vals.root)
357 config_image.append(['root', cmdline_root])
358 if vals.extra:
359 config_image.append(['args', vals.extra])
360 if vals.vcpus:
361 config_image.append(['vcpus', vals.vcpus])
362 return config_image
364 def configure_disks(opts, config_devs, vals):
365 """Create the config for disks (virtual block devices).
366 """
367 for (uname, dev, mode, backend) in vals.disk:
368 config_vbd = ['vbd',
369 ['uname', uname],
370 ['dev', dev ],
371 ['mode', mode ] ]
372 if backend:
373 config_vbd.append(['backend', backend])
374 config_devs.append(['device', config_vbd])
376 def configure_pci(opts, config_devs, vals):
377 """Create the config for pci devices.
378 """
379 for (bus, dev, func) in vals.pci:
380 config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]]
381 config_devs.append(['device', config_pci])
383 def configure_usb(opts, config_devs, vals):
384 for path in vals.usb:
385 config_usb = ['usb', ['path', path]]
386 config_devs.append(['device', config_usb])
388 def configure_vtpm(opts, config_devs, vals):
389 """Create the config for virtual TPM interfaces.
390 """
391 vtpm = vals.vtpm
392 vtpm_n = 1
393 for idx in range(0, vtpm_n):
394 if idx < len(vtpm):
395 d = vtpm[idx]
396 instance = d.get('instance')
397 if instance == "VTPMD":
398 instance = "0"
399 else:
400 try:
401 if int(instance) == 0:
402 opts.err('VM config error: vTPM instance must not be 0.')
403 except ValueError:
404 opts.err('Vm config error: could not parse instance number.')
405 backend = d.get('backend')
406 config_vtpm = ['vtpm']
407 if instance:
408 config_vtpm.append(['instance', instance])
409 if backend:
410 config_vtpm.append(['backend', backend])
411 config_devs.append(['device', config_vtpm])
413 def configure_tpmif(opts, config_devs, vals):
414 """Create the config for virtual TPM interfaces.
415 """
416 tpmif = vals.tpmif
417 tpmif_n = 1
418 for idx in range(0, tpmif_n):
419 if idx < len(tpmif):
420 d = tpmif[idx]
421 frontend = d.get('frontend')
422 config_tpmif = ['tpmif']
423 if frontend:
424 config_tpmif.append(['frontend', frontend])
425 config_devs.append(['device', config_tpmif])
428 def randomMAC():
429 """Generate a random MAC address.
431 Uses OUI (Organizationally Unique Identifier) AA:00:00, an
432 unassigned one that used to belong to DEC. The OUI list is
433 available at 'standards.ieee.org'.
435 The remaining 3 fields are random, with the first bit of the first
436 random field set 0.
438 @return: MAC address string
439 """
440 mac = [ 0xaa, 0x00, 0x00,
441 random.randint(0x00, 0x7f),
442 random.randint(0x00, 0xff),
443 random.randint(0x00, 0xff) ]
444 return ':'.join(map(lambda x: "%02x" % x, mac))
446 def configure_vifs(opts, config_devs, vals):
447 """Create the config for virtual network interfaces.
448 """
449 vifs = vals.vif
450 vifs_n = max(vals.nics, len(vifs))
452 for idx in range(0, vifs_n):
453 if idx < len(vifs):
454 d = vifs[idx]
455 mac = d.get('mac')
456 if not mac:
457 mac = randomMAC()
458 be_mac = d.get('be_mac')
459 bridge = d.get('bridge')
460 script = d.get('script')
461 backend = d.get('backend')
462 ip = d.get('ip')
463 vifname = d.get('vifname')
464 else:
465 mac = randomMAC()
466 be_mac = None
467 bridge = None
468 script = None
469 backend = None
470 ip = None
471 vifname = None
472 config_vif = ['vif']
473 config_vif.append(['mac', mac])
474 if vifname:
475 config_vif.append(['vifname', vifname])
476 if be_mac:
477 config_vif.append(['be_mac', be_mac])
478 if bridge:
479 config_vif.append(['bridge', bridge])
480 if script:
481 config_vif.append(['script', script])
482 if backend:
483 config_vif.append(['backend', backend])
484 if ip:
485 config_vif.append(['ip', ip])
486 config_devs.append(['device', config_vif])
488 def configure_vfr(opts, config, vals):
489 if not vals.ipaddr: return
490 config_vfr = ['vfr']
491 idx = 0 # No way of saying which IP is for which vif?
492 for ip in vals.ipaddr:
493 config_vfr.append(['vif', ['id', idx], ['ip', ip]])
494 config.append(config_vfr)
496 def configure_vmx(opts, config_image, vals):
497 """Create the config for VMX devices.
498 """
499 args = [ 'memmap', 'device_model', 'cdrom',
500 'boot', 'fda', 'fdb', 'localtime', 'serial', 'macaddr', 'stdvga',
501 'isa', 'nographic', 'vnc', 'vncviewer', 'sdl', 'display']
502 for a in args:
503 if (vals.__dict__[a]):
504 config_image.append([a, vals.__dict__[a]])
506 def run_bootloader(opts, vals):
507 if not os.access(vals.bootloader, os.X_OK):
508 opts.err("Bootloader isn't executable")
509 if len(vals.disk) < 1:
510 opts.err("No disks configured and boot loader requested")
511 (uname, dev, mode, backend) = vals.disk[0]
512 file = blkif.blkdev_uname_to_file(uname)
514 return bootloader(vals.bootloader, file, not vals.console_autoconnect,
515 vals.vcpus, vals.blentry)
517 def make_config(opts, vals):
518 """Create the domain configuration.
519 """
521 config = ['vm',
522 ['name', vals.name ],
523 ['memory', vals.memory ],
524 ['ssidref', vals.ssidref ]]
525 if vals.maxmem:
526 config.append(['maxmem', vals.maxmem])
527 if vals.cpu is not None:
528 config.append(['cpu', vals.cpu])
529 if vals.cpu_weight is not None:
530 config.append(['cpu_weight', vals.cpu_weight])
531 if vals.blkif:
532 config.append(['backend', ['blkif']])
533 if vals.netif:
534 config.append(['backend', ['netif']])
535 if vals.tpmif:
536 config.append(['backend', ['tpmif']])
537 if vals.restart:
538 config.append(['restart', vals.restart])
540 if vals.bootloader:
541 config.append(['bootloader', vals.bootloader])
542 config_image = run_bootloader(opts, vals)
543 else:
544 config_image = configure_image(opts, vals)
545 configure_vmx(opts, config_image, vals)
546 config.append(['image', config_image ])
548 config_devs = []
549 configure_disks(opts, config_devs, vals)
550 configure_pci(opts, config_devs, vals)
551 configure_vifs(opts, config_devs, vals)
552 configure_usb(opts, config_devs, vals)
553 configure_vtpm(opts, config_devs, vals)
554 config += config_devs
556 return config
558 def preprocess_disk(opts, vals):
559 if not vals.disk: return
560 disk = []
561 for v in vals.disk:
562 d = v.split(',')
563 n = len(d)
564 if n == 3:
565 d.append(None)
566 elif n == 4:
567 pass
568 else:
569 opts.err('Invalid disk specifier: ' + v)
570 disk.append(d)
571 vals.disk = disk
573 def preprocess_pci(opts, vals):
574 if not vals.pci: return
575 pci = []
576 for v in vals.pci:
577 d = v.split(',')
578 if len(d) != 3:
579 opts.err('Invalid pci specifier: ' + v)
580 # Components are in hex: add hex specifier.
581 hexd = map(lambda v: '0x'+v, d)
582 pci.append(hexd)
583 vals.pci = pci
585 def preprocess_vifs(opts, vals):
586 if not vals.vif: return
587 vifs = []
588 for vif in vals.vif:
589 d = {}
590 a = vif.split(',')
591 for b in a:
592 (k, v) = b.strip().split('=', 1)
593 k = k.strip()
594 v = v.strip()
595 if k not in ['mac', 'be_mac', 'bridge', 'script', 'backend', 'ip', 'vifname']:
596 opts.err('Invalid vif specifier: ' + vif)
597 d[k] = v
598 vifs.append(d)
599 vals.vif = vifs
601 def preprocess_vtpm(opts, vals):
602 if not vals.vtpm: return
603 vtpms = []
604 for vtpm in vals.vtpm:
605 d = {}
606 a = vtpm.split(',')
607 for b in a:
608 (k, v) = b.strip().split('=', 1)
609 k = k.strip()
610 v = v.strip()
611 if k not in ['backend', 'instance']:
612 opts.err('Invalid vtpm specifier: ' + vtpm)
613 d[k] = v
614 vtpms.append(d)
615 vals.vtpm = vtpms
617 def preprocess_tpmif(opts, vals):
618 if not vals.tpmif: return
619 tpmifs = []
620 for tpmif in vals.tpmif:
621 d = {}
622 a = tpmif.split(',')
623 for b in a:
624 (k, v) = b.strip().split('=', 1)
625 k = k.strip()
626 v = v.strip()
627 if k not in ['frontend']:
628 opts.err('Invalid tpmif specifier: ' + vtpm)
629 d[k] = v
630 tpmifs.append(d)
631 vals.tpmif = tpmifs
633 def preprocess_ip(opts, vals):
634 if vals.ip or vals.dhcp != 'off':
635 dummy_nfs_server = '1.2.3.4'
636 ip = (vals.ip
637 + ':' + (vals.nfs_server or dummy_nfs_server)
638 + ':' + vals.gateway
639 + ':' + vals.netmask
640 + ':' + vals.hostname
641 + ':' + vals.interface
642 + ':' + vals.dhcp)
643 else:
644 ip = ''
645 vals.cmdline_ip = ip
647 def preprocess_nfs(opts, vals):
648 if not vals.nfs_root: return
649 if not vals.nfs_server:
650 opts.err('Must set nfs root and nfs server')
651 nfs = 'nfsroot=' + vals.nfs_server + ':' + vals.nfs_root
652 vals.extra = nfs + ' ' + vals.extra
655 def get_host_addr():
656 host = socket.gethostname()
657 addr = socket.gethostbyname(host)
658 return addr
660 VNC_BASE_PORT = 5500
662 def choose_vnc_display():
663 """Try to choose a free vnc display.
664 """
665 def netstat_local_ports():
666 """Run netstat to get a list of the local ports in use.
667 """
668 l = os.popen("netstat -nat").readlines()
669 r = []
670 # Skip 2 lines of header.
671 for x in l[2:]:
672 # Local port is field 3.
673 y = x.split()[3]
674 # Field is addr:port, split off the port.
675 y = y.split(':')[-1]
676 r.append(int(y))
677 return r
679 ports = netstat_local_ports()
680 for d in range(1, 100):
681 port = VNC_BASE_PORT + d
682 if port in ports: continue
683 return d
684 return None
686 vncpid = None
688 def spawn_vnc(display):
689 vncargs = (["vncviewer" + "-log", "*:stdout:0",
690 "-listen", "%d" % (VNC_BASE_PORT + display) ])
691 global vncpid
692 vncpid = os.spawnvp(os.P_NOWAIT, "vncviewer", vncargs)
694 return VNC_BASE_PORT + display
696 def preprocess_vnc(opts, vals):
697 """If vnc was specified, spawn a vncviewer in listen mode
698 and pass its address to the domain on the kernel command line.
699 """
700 if not (vals.vnc and vals.vncviewer) or vals.dryrun: return
701 vnc_display = choose_vnc_display()
702 if not vnc_display:
703 opts.warn("No free vnc display")
704 return
705 print 'VNC=', vnc_display
706 vnc_port = spawn_vnc(vnc_display)
707 if vnc_port > 0:
708 vnc_host = get_host_addr()
709 vnc = 'VNC_VIEWER=%s:%d' % (vnc_host, vnc_port)
710 vals.extra = vnc + ' ' + vals.extra
712 def preprocess(opts, vals):
713 if not vals.kernel:
714 opts.err("No kernel specified")
715 preprocess_disk(opts, vals)
716 preprocess_pci(opts, vals)
717 preprocess_vifs(opts, vals)
718 preprocess_ip(opts, vals)
719 preprocess_nfs(opts, vals)
720 preprocess_vnc(opts, vals)
721 preprocess_vtpm(opts, vals)
722 preprocess_tpmif(opts, vals)
724 def make_domain(opts, config):
725 """Create, build and start a domain.
727 @param opts: options
728 @param config: configuration
729 @return: domain id
730 @rtype: int
731 """
733 try:
734 if opts.vals.load:
735 filename = os.path.abspath(opts.vals.load)
736 dominfo = server.xend_domain_restore(filename, config)
737 else:
738 dominfo = server.xend_domain_create(config)
739 except XendError, ex:
740 import signal
741 if vncpid:
742 os.kill(vncpid, signal.SIGKILL)
743 opts.err(str(ex))
745 dom = sxp.child_value(dominfo, 'name')
747 if not opts.vals.paused:
748 if server.xend_domain_unpause(dom) < 0:
749 server.xend_domain_destroy(dom)
750 opts.err("Failed to unpause domain %s" % dom)
751 opts.info("Started domain %s" % (dom))
752 return int(sxp.child_value(dominfo, 'domid'))
754 def get_dom0_alloc():
755 """Return current allocation memory of dom0 (in MB). Return 0 on error"""
756 PROC_XEN_BALLOON = "/proc/xen/balloon"
758 f = open(PROC_XEN_BALLOON, "r")
759 line = f.readline()
760 for x in line.split():
761 for n in x:
762 if not n.isdigit():
763 break
764 else:
765 f.close()
766 return int(x)/1024
767 f.close()
768 return 0
770 def balloon_out(dom0_min_mem, opts):
771 """Balloon out memory from dom0 if necessary"""
772 SLACK = 4
773 timeout = 20 # 2s
774 ret = 1
776 xc = xen.lowlevel.xc.new()
777 free_mem = xc.physinfo()['free_pages'] / 256
778 domU_need_mem = opts.vals.memory + SLACK
780 # we already have enough free memory, return success
781 if free_mem >= domU_need_mem:
782 del xc
783 return 0
785 dom0_cur_alloc = get_dom0_alloc()
786 dom0_new_alloc = dom0_cur_alloc - (domU_need_mem - free_mem)
787 if dom0_new_alloc < dom0_min_mem:
788 dom0_new_alloc = dom0_min_mem
790 server.xend_domain_mem_target_set(0, dom0_new_alloc)
792 while timeout > 0:
793 time.sleep(0.1) # sleep 100ms
795 free_mem = xc.physinfo()['free_pages'] / 256
796 if free_mem >= domU_need_mem:
797 ret = 0
798 break
799 timeout -= 1
801 del xc
802 return ret
804 def main(argv):
805 random.seed()
806 opts = gopts
807 args = opts.parse(argv)
808 if opts.vals.help:
809 opts.usage()
810 if opts.vals.help or opts.vals.help_config:
811 opts.load_defconfig(help=1)
812 if opts.vals.help or opts.vals.help_config:
813 return
814 # Process remaining args as config variables.
815 for arg in args:
816 if '=' in arg:
817 (var, val) = arg.strip().split('=', 1)
818 gopts.setvar(var.strip(), val.strip())
819 opts.vals.display = os.getenv("DISPLAY")
820 if opts.vals.config:
821 config = opts.vals.config
822 else:
823 opts.load_defconfig()
824 preprocess(opts, opts.vals)
825 if not opts.getopt('name') and opts.getopt('defconfig'):
826 opts.setopt('name', os.path.basename(opts.getopt('defconfig')))
827 config = make_config(opts, opts.vals)
829 if opts.vals.dryrun:
830 PrettyPrint.prettyprint(config)
831 else:
832 dom0_min_mem = xroot.get_dom0_min_mem()
833 if dom0_min_mem != 0:
834 if balloon_out(dom0_min_mem, opts):
835 print >>sys.stderr, "error: cannot allocate enough memory for domain"
836 sys.exit(1)
838 dom = make_domain(opts, config)
839 if opts.vals.console_autoconnect:
840 cmd = "/usr/libexec/xen/xenconsole %d" % dom
841 os.execvp('/usr/libexec/xen/xenconsole', cmd.split())
843 if __name__ == '__main__':
844 main(sys.argv)