xen-vtx-unstable

view tools/python/xen/xm/create.py @ 6774:4d899a738d59

merge?
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 15:05:49 2005 +0000 (2005-09-13)
parents bc5e0fc79696 dd668f7527cb
children e7c7196fa329 8ca0f98ba8e2
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=-1,
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, config, 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 config.append(['image', config_image ])
365 def configure_disks(opts, config_devs, vals):
366 """Create the config for disks (virtual block devices).
367 """
368 for (uname, dev, mode, backend) in vals.disk:
369 config_vbd = ['vbd',
370 ['uname', uname],
371 ['dev', dev ],
372 ['mode', mode ] ]
373 if backend:
374 config_vbd.append(['backend', backend])
375 config_devs.append(['device', config_vbd])
377 def configure_pci(opts, config_devs, vals):
378 """Create the config for pci devices.
379 """
380 for (bus, dev, func) in vals.pci:
381 config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]]
382 config_devs.append(['device', config_pci])
384 def configure_usb(opts, config_devs, vals):
385 for path in vals.usb:
386 config_usb = ['usb', ['path', path]]
387 config_devs.append(['device', config_usb])
389 def configure_vtpm(opts, config_devs, vals):
390 """Create the config for virtual TPM interfaces.
391 """
392 vtpm = vals.vtpm
393 vtpm_n = 1
394 for idx in range(0, vtpm_n):
395 if idx < len(vtpm):
396 d = vtpm[idx]
397 instance = d.get('instance')
398 if instance == "VTPMD":
399 instance = "0"
400 else:
401 try:
402 if int(instance) == 0:
403 opts.err('VM config error: vTPM instance must not be 0.')
404 except ValueError:
405 opts.err('Vm config error: could not parse instance number.')
406 backend = d.get('backend')
407 config_vtpm = ['vtpm']
408 if instance:
409 config_vtpm.append(['instance', instance])
410 if backend:
411 config_vtpm.append(['backend', backend])
412 config_devs.append(['device', config_vtpm])
414 def configure_tpmif(opts, config_devs, vals):
415 """Create the config for virtual TPM interfaces.
416 """
417 tpmif = vals.tpmif
418 tpmif_n = 1
419 for idx in range(0, tpmif_n):
420 if idx < len(tpmif):
421 d = tpmif[idx]
422 frontend = d.get('frontend')
423 config_tpmif = ['tpmif']
424 if frontend:
425 config_tpmif.append(['frontend', frontend])
426 config_devs.append(['device', config_tpmif])
429 def randomMAC():
430 """Generate a random MAC address.
432 Uses OUI (Organizationally Unique Identifier) AA:00:00, an
433 unassigned one that used to belong to DEC. The OUI list is
434 available at 'standards.ieee.org'.
436 The remaining 3 fields are random, with the first bit of the first
437 random field set 0.
439 @return: MAC address string
440 """
441 mac = [ 0xaa, 0x00, 0x00,
442 random.randint(0x00, 0x7f),
443 random.randint(0x00, 0xff),
444 random.randint(0x00, 0xff) ]
445 return ':'.join(map(lambda x: "%02x" % x, mac))
447 def configure_vifs(opts, config_devs, vals):
448 """Create the config for virtual network interfaces.
449 """
450 vifs = vals.vif
451 vifs_n = max(vals.nics, len(vifs))
453 for idx in range(0, vifs_n):
454 if idx < len(vifs):
455 d = vifs[idx]
456 mac = d.get('mac')
457 if not mac:
458 mac = randomMAC()
459 be_mac = d.get('be_mac')
460 bridge = d.get('bridge')
461 script = d.get('script')
462 backend = d.get('backend')
463 ip = d.get('ip')
464 vifname = d.get('vifname')
465 else:
466 mac = randomMAC()
467 be_mac = None
468 bridge = None
469 script = None
470 backend = None
471 ip = None
472 vifname = None
473 config_vif = ['vif']
474 config_vif.append(['mac', mac])
475 if vifname:
476 config_vif.append(['vifname', vifname])
477 if be_mac:
478 config_vif.append(['be_mac', be_mac])
479 if bridge:
480 config_vif.append(['bridge', bridge])
481 if script:
482 config_vif.append(['script', script])
483 if backend:
484 config_vif.append(['backend', backend])
485 if ip:
486 config_vif.append(['ip', ip])
487 config_devs.append(['device', config_vif])
489 def configure_vfr(opts, config, vals):
490 if not vals.ipaddr: return
491 config_vfr = ['vfr']
492 idx = 0 # No way of saying which IP is for which vif?
493 for ip in vals.ipaddr:
494 config_vfr.append(['vif', ['id', idx], ['ip', ip]])
495 config.append(config_vfr)
497 def configure_vmx(opts, config_devs, vals):
498 """Create the config for VMX devices.
499 """
500 args = [ 'memmap', 'device_model', 'cdrom',
501 'boot', 'fda', 'fdb', 'localtime', 'serial', 'macaddr', 'stdvga',
502 'isa', 'nographic', 'vnc', 'vncviewer', 'sdl', 'display']
503 for a in args:
504 if (vals.__dict__[a]):
505 config_devs.append([a, vals.__dict__[a]])
507 def run_bootloader(opts, config, vals):
508 if not os.access(vals.bootloader, os.X_OK):
509 opts.err("Bootloader isn't executable")
510 if len(vals.disk) < 1:
511 opts.err("No disks configured and boot loader requested")
512 (uname, dev, mode, backend) = vals.disk[0]
513 file = blkif.blkdev_uname_to_file(uname)
515 blcfg = bootloader(vals.bootloader, file, not vals.console_autoconnect,
516 vals.vcpus, vals.blentry)
518 config.append(['bootloader', vals.bootloader])
519 config.append(blcfg)
521 def make_config(opts, vals):
522 """Create the domain configuration.
523 """
525 config = ['vm',
526 ['name', vals.name ],
527 ['memory', vals.memory ],
528 ['ssidref', vals.ssidref ]]
529 if vals.maxmem:
530 config.append(['maxmem', vals.maxmem])
531 if vals.cpu is not None:
532 config.append(['cpu', vals.cpu])
533 if vals.cpu_weight is not None:
534 config.append(['cpu_weight', vals.cpu_weight])
535 if vals.blkif:
536 config.append(['backend', ['blkif']])
537 if vals.netif:
538 config.append(['backend', ['netif']])
539 if vals.tpmif:
540 config.append(['backend', ['tpmif']])
541 if vals.restart:
542 config.append(['restart', vals.restart])
544 if vals.bootloader:
545 run_bootloader(opts, config, vals)
546 else:
547 configure_image(opts, config, vals)
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 configure_vmx(opts, config_devs, vals)
555 config += config_devs
557 return config
559 def preprocess_disk(opts, vals):
560 if not vals.disk: return
561 disk = []
562 for v in vals.disk:
563 d = v.split(',')
564 n = len(d)
565 if n == 3:
566 d.append(None)
567 elif n == 4:
568 pass
569 else:
570 opts.err('Invalid disk specifier: ' + v)
571 disk.append(d)
572 vals.disk = disk
574 def preprocess_pci(opts, vals):
575 if not vals.pci: return
576 pci = []
577 for v in vals.pci:
578 d = v.split(',')
579 if len(d) != 3:
580 opts.err('Invalid pci specifier: ' + v)
581 # Components are in hex: add hex specifier.
582 hexd = map(lambda v: '0x'+v, d)
583 pci.append(hexd)
584 vals.pci = pci
586 def preprocess_vifs(opts, vals):
587 if not vals.vif: return
588 vifs = []
589 for vif in vals.vif:
590 d = {}
591 a = vif.split(',')
592 for b in a:
593 (k, v) = b.strip().split('=', 1)
594 k = k.strip()
595 v = v.strip()
596 if k not in ['mac', 'be_mac', 'bridge', 'script', 'backend', 'ip', 'vifname']:
597 opts.err('Invalid vif specifier: ' + vif)
598 d[k] = v
599 vifs.append(d)
600 vals.vif = vifs
602 def preprocess_vtpm(opts, vals):
603 if not vals.vtpm: return
604 vtpms = []
605 for vtpm in vals.vtpm:
606 d = {}
607 a = vtpm.split(',')
608 for b in a:
609 (k, v) = b.strip().split('=', 1)
610 k = k.strip()
611 v = v.strip()
612 if k not in ['backend', 'instance']:
613 opts.err('Invalid vtpm specifier: ' + vtpm)
614 d[k] = v
615 vtpms.append(d)
616 vals.vtpm = vtpms
618 def preprocess_tpmif(opts, vals):
619 if not vals.tpmif: return
620 tpmifs = []
621 for tpmif in vals.tpmif:
622 d = {}
623 a = tpmif.split(',')
624 for b in a:
625 (k, v) = b.strip().split('=', 1)
626 k = k.strip()
627 v = v.strip()
628 if k not in ['frontend']:
629 opts.err('Invalid tpmif specifier: ' + vtpm)
630 d[k] = v
631 tpmifs.append(d)
632 vals.tpmif = tpmifs
634 def preprocess_ip(opts, vals):
635 if vals.ip or vals.dhcp != 'off':
636 dummy_nfs_server = '1.2.3.4'
637 ip = (vals.ip
638 + ':' + (vals.nfs_server or dummy_nfs_server)
639 + ':' + vals.gateway
640 + ':' + vals.netmask
641 + ':' + vals.hostname
642 + ':' + vals.interface
643 + ':' + vals.dhcp)
644 else:
645 ip = ''
646 vals.cmdline_ip = ip
648 def preprocess_nfs(opts, vals):
649 if not vals.nfs_root: return
650 if not vals.nfs_server:
651 opts.err('Must set nfs root and nfs server')
652 nfs = 'nfsroot=' + vals.nfs_server + ':' + vals.nfs_root
653 vals.extra = nfs + ' ' + vals.extra
656 def get_host_addr():
657 host = socket.gethostname()
658 addr = socket.gethostbyname(host)
659 return addr
661 VNC_BASE_PORT = 5500
663 def choose_vnc_display():
664 """Try to choose a free vnc display.
665 """
666 def netstat_local_ports():
667 """Run netstat to get a list of the local ports in use.
668 """
669 l = os.popen("netstat -nat").readlines()
670 r = []
671 # Skip 2 lines of header.
672 for x in l[2:]:
673 # Local port is field 3.
674 y = x.split()[3]
675 # Field is addr:port, split off the port.
676 y = y.split(':')[1]
677 r.append(int(y))
678 return r
680 ports = netstat_local_ports()
681 for d in range(1, 100):
682 port = VNC_BASE_PORT + d
683 if port in ports: continue
684 return d
685 return None
687 vncpid = None
689 def spawn_vnc(display):
690 vncargs = (["vncviewer" + "-log", "*:stdout:0",
691 "-listen", "%d" % (VNC_BASE_PORT + display) ])
692 global vncpid
693 vncpid = os.spawnvp(os.P_NOWAIT, "vncviewer", vncargs)
695 return VNC_BASE_PORT + display
697 def preprocess_vnc(opts, vals):
698 """If vnc was specified, spawn a vncviewer in listen mode
699 and pass its address to the domain on the kernel command line.
700 """
701 if not (vals.vnc and vals.vncviewer) or vals.dryrun: return
702 vnc_display = choose_vnc_display()
703 if not vnc_display:
704 opts.warn("No free vnc display")
705 return
706 print 'VNC=', vnc_display
707 vnc_port = spawn_vnc(vnc_display)
708 if vnc_port > 0:
709 vnc_host = get_host_addr()
710 vnc = 'VNC_VIEWER=%s:%d' % (vnc_host, vnc_port)
711 vals.extra = vnc + ' ' + vals.extra
713 def preprocess(opts, vals):
714 if not vals.kernel:
715 opts.err("No kernel specified")
716 preprocess_disk(opts, vals)
717 preprocess_pci(opts, vals)
718 preprocess_vifs(opts, vals)
719 preprocess_ip(opts, vals)
720 preprocess_nfs(opts, vals)
721 preprocess_vnc(opts, vals)
722 preprocess_vtpm(opts, vals)
723 preprocess_tpmif(opts, vals)
725 def make_domain(opts, config):
726 """Create, build and start a domain.
728 @param opts: options
729 @param config: configuration
730 @return: domain id
731 @rtype: int
732 """
734 try:
735 if opts.vals.load:
736 filename = os.path.abspath(opts.vals.load)
737 dominfo = server.xend_domain_restore(filename, config)
738 else:
739 dominfo = server.xend_domain_create(config)
740 except XendError, ex:
741 import signal
742 if vncpid:
743 os.kill(vncpid, signal.SIGKILL)
744 opts.err(str(ex))
746 dom = sxp.child_value(dominfo, 'name')
748 if not opts.vals.paused:
749 if server.xend_domain_unpause(dom) < 0:
750 server.xend_domain_destroy(dom)
751 opts.err("Failed to unpause domain %s" % dom)
752 opts.info("Started domain %s" % (dom))
753 return int(sxp.child_value(dominfo, 'id'))
755 def get_dom0_alloc():
756 """Return current allocation memory of dom0 (in MB). Return 0 on error"""
757 PROC_XEN_BALLOON = "/proc/xen/balloon"
759 f = open(PROC_XEN_BALLOON, "r")
760 line = f.readline()
761 for x in line.split():
762 for n in x:
763 if not n.isdigit():
764 break
765 else:
766 f.close()
767 return int(x)/1024
768 f.close()
769 return 0
771 def balloon_out(dom0_min_mem, opts):
772 """Balloon out memory from dom0 if necessary"""
773 SLACK = 4
774 timeout = 20 # 2s
775 ret = 1
777 xc = xen.lowlevel.xc.new()
778 free_mem = xc.physinfo()['free_pages'] / 256
779 domU_need_mem = opts.vals.memory + SLACK
781 # we already have enough free memory, return success
782 if free_mem >= domU_need_mem:
783 del xc
784 return 0
786 dom0_cur_alloc = get_dom0_alloc()
787 dom0_new_alloc = dom0_cur_alloc - (domU_need_mem - free_mem)
788 if dom0_new_alloc < dom0_min_mem:
789 dom0_new_alloc = dom0_min_mem
791 server.xend_domain_mem_target_set(0, dom0_new_alloc)
793 while timeout > 0:
794 time.sleep(0.1) # sleep 100ms
796 free_mem = xc.physinfo()['free_pages'] / 256
797 if free_mem >= domU_need_mem:
798 ret = 0
799 break
800 timeout -= 1
802 del xc
803 return ret
805 def main(argv):
806 random.seed()
807 opts = gopts
808 args = opts.parse(argv)
809 if opts.vals.help:
810 opts.usage()
811 if opts.vals.help or opts.vals.help_config:
812 opts.load_defconfig(help=1)
813 if opts.vals.help or opts.vals.help_config:
814 return
815 # Process remaining args as config variables.
816 for arg in args:
817 if '=' in arg:
818 (var, val) = arg.strip().split('=', 1)
819 gopts.setvar(var.strip(), val.strip())
820 opts.vals.display = os.getenv("DISPLAY")
821 if opts.vals.config:
822 config = opts.vals.config
823 else:
824 opts.load_defconfig()
825 preprocess(opts, opts.vals)
826 if not opts.getopt('name') and opts.getopt('defconfig'):
827 opts.setopt('name', os.path.basename(opts.getopt('defconfig')))
828 config = make_config(opts, opts.vals)
830 if opts.vals.dryrun:
831 PrettyPrint.prettyprint(config)
832 else:
833 dom0_min_mem = xroot.get_dom0_min_mem()
834 if dom0_min_mem != 0:
835 if balloon_out(dom0_min_mem, opts):
836 print >>sys.stderr, "error: cannot allocate enough memory for domain"
837 sys.exit(1)
839 dom = make_domain(opts, config)
840 if opts.vals.console_autoconnect:
841 cmd = "/usr/libexec/xen/xenconsole %d" % dom
842 os.execvp('/usr/libexec/xen/xenconsole', cmd.split())
844 if __name__ == '__main__':
845 main(sys.argv)