ia64/xen-unstable

view tools/python/xen/xm/create.py @ 6552:a9873d384da4

Merge.
author adsharma@los-vmm.sc.intel.com
date Thu Aug 25 12:24:48 2005 -0700 (2005-08-25)
parents 112d44270733 56dd9a7b37f9
children dfaf788ab18c
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('disk', val='phy:DEV,VDEV,MODE[,DOM]',
180 fn=append_value, default=[],
181 use="""Add a disk device to a domain. The physical device is DEV,
182 which is exported to the domain as VDEV. The disk is read-only if MODE
183 is 'r', read-write if MODE is 'w'. If DOM is specified it defines the
184 backend driver domain to use for the disk.
185 The option may be repeated to add more than one disk.""")
187 gopts.var('pci', val='BUS,DEV,FUNC',
188 fn=append_value, default=[],
189 use="""Add a PCI device to a domain, using given params (in hex).
190 For example '-pci c0,02,1a'.
191 The option may be repeated to add more than one pci device.""")
193 gopts.var('usb', val='PATH',
194 fn=append_value, default=[],
195 use="""Add a physical USB port to a domain, as specified by the path
196 to that port. This option may be repeated to add more than one port.""")
198 gopts.var('ipaddr', val="IPADDR",
199 fn=append_value, default=[],
200 use="Add an IP address to the domain.")
202 gopts.var('vif', val="mac=MAC,be_mac=MAC,bridge=BRIDGE,script=SCRIPT,backend=DOM,vifname=NAME",
203 fn=append_value, default=[],
204 use="""Add a network interface with the given MAC address and bridge.
205 The vif is configured by calling the given configuration script.
206 If mac is not specified a random MAC address is used.
207 The MAC address of the backend interface can be selected with be_mac.
208 If not specified then the network backend chooses it's own MAC address.
209 If bridge is not specified the default bridge is used.
210 If script is not specified the default script is used.
211 If backend is not specified the default backend driver domain is used.
212 If vifname is not specified the backend virtual interface will have name vifD.N
213 where D is the domain id and N is the interface id.
214 This option may be repeated to add more than one vif.
215 Specifying vifs will increase the number of interfaces as needed.""")
217 gopts.var('nics', val="NUM",
218 fn=set_int, default=1,
219 use="""Set the number of network interfaces.
220 Use the vif option to define interface parameters, otherwise
221 defaults are used. Specifying vifs will increase the
222 number of interfaces as needed.""")
224 gopts.var('root', val='DEVICE',
225 fn=set_value, default='',
226 use="""Set the root= parameter on the kernel command line.
227 Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""")
229 gopts.var('extra', val="ARGS",
230 fn=set_value, default='',
231 use="Set extra arguments to append to the kernel command line.")
233 gopts.var('ip', val='IPADDR',
234 fn=set_value, default='',
235 use="Set the kernel IP interface address.")
237 gopts.var('gateway', val="IPADDR",
238 fn=set_value, default='',
239 use="Set the kernel IP gateway.")
241 gopts.var('netmask', val="MASK",
242 fn=set_value, default = '',
243 use="Set the kernel IP netmask.")
245 gopts.var('hostname', val="NAME",
246 fn=set_value, default='',
247 use="Set the kernel IP hostname.")
249 gopts.var('interface', val="INTF",
250 fn=set_value, default="eth0",
251 use="Set the kernel IP interface name.")
253 gopts.var('dhcp', val="off|dhcp",
254 fn=set_value, default='off',
255 use="Set the kernel dhcp option.")
257 gopts.var('nfs_server', val="IPADDR",
258 fn=set_value, default=None,
259 use="Set the address of the NFS server for NFS root.")
261 gopts.var('nfs_root', val="PATH",
262 fn=set_value, default=None,
263 use="Set the path of the root NFS directory.")
265 gopts.var('memmap', val='FILE',
266 fn=set_value, default='',
267 use="Path to memap SXP file.")
269 gopts.var('device_model', val='FILE',
270 fn=set_value, default='',
271 use="Path to device model program.")
273 gopts.var('fda', val='FILE',
274 fn=set_value, default='',
275 use="Path to fda")
277 gopts.var('fdb', val='FILE',
278 fn=set_value, default='',
279 use="Path to fdb")
281 gopts.var('serial', val='FILE',
282 fn=set_value, default='',
283 use="Path to serial or pty or vc")
285 gopts.var('localtime', val='no|yes',
286 fn=set_bool, default=0,
287 use="Is RTC set to localtime?")
289 gopts.var('stdvga', val='no|yes',
290 fn=set_bool, default=0,
291 use="Use std vga or cirrhus logic graphics")
293 gopts.var('isa', val='no|yes',
294 fn=set_bool, default=0,
295 use="Simulate an ISA only system?")
297 gopts.var('cdrom', val='FILE',
298 fn=set_value, default='',
299 use="Path to cdrom")
301 gopts.var('macaddr', val='MACADDR',
302 fn=set_value, default='',
303 use="Macaddress of the first network interface")
305 gopts.var('boot', val="a|b|c|d",
306 fn=set_value, default='c',
307 use="Default boot device")
309 gopts.var('nographic', val='no|yes',
310 fn=set_bool, default=0,
311 use="Should device models use graphics?")
313 gopts.var('vnc', val='',
314 fn=set_value, default=None,
315 use="""Should the device model use VNC?""")
317 gopts.var('sdl', val='',
318 fn=set_value, default=None,
319 use="""Should the device model use SDL?""")
321 gopts.var('display', val='DISPLAY',
322 fn=set_value, default='localhost:0',
323 use="X11 display to use")
325 def strip(pre, s):
326 """Strip prefix 'pre' if present.
327 """
328 if s.startswith(pre):
329 return s[len(pre):]
330 else:
331 return s
333 def configure_image(opts, config, vals):
334 """Create the image config.
335 """
336 config_image = [ vals.builder ]
337 config_image.append([ 'kernel', os.path.abspath(vals.kernel) ])
338 if vals.ramdisk:
339 config_image.append([ 'ramdisk', os.path.abspath(vals.ramdisk) ])
340 if vals.cmdline_ip:
341 cmdline_ip = strip('ip=', vals.cmdline_ip)
342 config_image.append(['ip', cmdline_ip])
343 if vals.root:
344 cmdline_root = strip('root=', vals.root)
345 config_image.append(['root', cmdline_root])
346 if vals.extra:
347 config_image.append(['args', vals.extra])
348 if vals.vcpus:
349 config_image.append(['vcpus', vals.vcpus])
350 config.append(['image', config_image ])
353 def configure_disks(opts, config_devs, vals):
354 """Create the config for disks (virtual block devices).
355 """
356 for (uname, dev, mode, backend) in vals.disk:
357 config_vbd = ['vbd',
358 ['uname', uname],
359 ['dev', dev ],
360 ['mode', mode ] ]
361 if backend:
362 config_vbd.append(['backend', backend])
363 config_devs.append(['device', config_vbd])
365 def configure_pci(opts, config_devs, vals):
366 """Create the config for pci devices.
367 """
368 for (bus, dev, func) in vals.pci:
369 config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]]
370 config_devs.append(['device', config_pci])
372 def configure_usb(opts, config_devs, vals):
373 for path in vals.usb:
374 config_usb = ['usb', ['path', path]]
375 config_devs.append(['device', config_usb])
377 def randomMAC():
378 """Generate a random MAC address.
380 Uses OUI (Organizationally Unique Identifier) AA:00:00, an
381 unassigned one that used to belong to DEC. The OUI list is
382 available at 'standards.ieee.org'.
384 The remaining 3 fields are random, with the first bit of the first
385 random field set 0.
387 @return: MAC address string
388 """
389 mac = [ 0xaa, 0x00, 0x00,
390 random.randint(0x00, 0x7f),
391 random.randint(0x00, 0xff),
392 random.randint(0x00, 0xff) ]
393 return ':'.join(map(lambda x: "%02x" % x, mac))
395 def configure_vifs(opts, config_devs, vals):
396 """Create the config for virtual network interfaces.
397 """
398 vifs = vals.vif
399 vifs_n = max(vals.nics, len(vifs))
401 for idx in range(0, vifs_n):
402 if idx < len(vifs):
403 d = vifs[idx]
404 mac = d.get('mac')
405 if not mac:
406 mac = randomMAC()
407 be_mac = d.get('be_mac')
408 bridge = d.get('bridge')
409 script = d.get('script')
410 backend = d.get('backend')
411 ip = d.get('ip')
412 vifname = d.get('vifname')
413 else:
414 mac = randomMAC()
415 be_mac = None
416 bridge = None
417 script = None
418 backend = None
419 ip = None
420 vifname = None
421 config_vif = ['vif']
422 config_vif.append(['mac', mac])
423 if vifname:
424 config_vif.append(['vifname', vifname])
425 if be_mac:
426 config_vif.append(['be_mac', be_mac])
427 if bridge:
428 config_vif.append(['bridge', bridge])
429 if script:
430 config_vif.append(['script', script])
431 if backend:
432 config_vif.append(['backend', backend])
433 if ip:
434 config_vif.append(['ip', ip])
435 config_devs.append(['device', config_vif])
437 def configure_vfr(opts, config, vals):
438 if not vals.ipaddr: return
439 config_vfr = ['vfr']
440 idx = 0 # No way of saying which IP is for which vif?
441 for ip in vals.ipaddr:
442 config_vfr.append(['vif', ['id', idx], ['ip', ip]])
443 config.append(config_vfr)
445 def configure_vmx(opts, config_devs, vals):
446 """Create the config for VMX devices.
447 """
448 args = [ 'memmap', 'device_model', 'cdrom',
449 'boot', 'fda', 'fdb', 'localtime', 'serial', 'macaddr', 'stdvga',
450 'isa', 'nographic', 'vnc', 'vncviewer', 'sdl', 'display']
451 for a in args:
452 if (vals.__dict__[a]):
453 config_devs.append([a, vals.__dict__[a]])
455 def run_bootloader(opts, config, vals):
456 if not os.access(vals.bootloader, os.X_OK):
457 opts.err("Bootloader isn't executable")
458 if len(vals.disk) < 1:
459 opts.err("No disks configured and boot loader requested")
460 (uname, dev, mode, backend) = vals.disk[0]
461 file = blkif.blkdev_uname_to_file(uname)
463 blcfg = bootloader(vals.bootloader, file, not vals.console_autoconnect,
464 vals.vcpus, vals.blentry)
466 config.append(['bootloader', vals.bootloader])
467 config.append(blcfg)
469 def make_config(opts, vals):
470 """Create the domain configuration.
471 """
473 config = ['vm',
474 ['name', vals.name ],
475 ['memory', vals.memory ],
476 ['ssidref', vals.ssidref ]]
477 if vals.maxmem:
478 config.append(['maxmem', vals.maxmem])
479 if vals.cpu is not None:
480 config.append(['cpu', vals.cpu])
481 if vals.cpu_weight is not None:
482 config.append(['cpu_weight', vals.cpu_weight])
483 if vals.blkif:
484 config.append(['backend', ['blkif']])
485 if vals.netif:
486 config.append(['backend', ['netif']])
487 if vals.restart:
488 config.append(['restart', vals.restart])
490 if vals.bootloader:
491 run_bootloader(opts, config, vals)
492 else:
493 configure_image(opts, config, vals)
494 config_devs = []
495 configure_disks(opts, config_devs, vals)
496 configure_pci(opts, config_devs, vals)
497 configure_vifs(opts, config_devs, vals)
498 configure_usb(opts, config_devs, vals)
499 configure_vmx(opts, config_devs, vals)
500 config += config_devs
502 return config
504 def preprocess_disk(opts, vals):
505 if not vals.disk: return
506 disk = []
507 for v in vals.disk:
508 d = v.split(',')
509 n = len(d)
510 if n == 3:
511 d.append(None)
512 elif n == 4:
513 pass
514 else:
515 opts.err('Invalid disk specifier: ' + v)
516 disk.append(d)
517 vals.disk = disk
519 def preprocess_pci(opts, vals):
520 if not vals.pci: return
521 pci = []
522 for v in vals.pci:
523 d = v.split(',')
524 if len(d) != 3:
525 opts.err('Invalid pci specifier: ' + v)
526 # Components are in hex: add hex specifier.
527 hexd = map(lambda v: '0x'+v, d)
528 pci.append(hexd)
529 vals.pci = pci
531 def preprocess_vifs(opts, vals):
532 if not vals.vif: return
533 vifs = []
534 for vif in vals.vif:
535 d = {}
536 a = vif.split(',')
537 for b in a:
538 (k, v) = b.strip().split('=', 1)
539 k = k.strip()
540 v = v.strip()
541 if k not in ['mac', 'be_mac', 'bridge', 'script', 'backend', 'ip', 'vifname']:
542 opts.err('Invalid vif specifier: ' + vif)
543 d[k] = v
544 vifs.append(d)
545 vals.vif = vifs
547 def preprocess_ip(opts, vals):
548 if vals.ip or vals.dhcp != 'off':
549 dummy_nfs_server = '1.2.3.4'
550 ip = (vals.ip
551 + ':' + (vals.nfs_server or dummy_nfs_server)
552 + ':' + vals.gateway
553 + ':' + vals.netmask
554 + ':' + vals.hostname
555 + ':' + vals.interface
556 + ':' + vals.dhcp)
557 else:
558 ip = ''
559 vals.cmdline_ip = ip
561 def preprocess_nfs(opts, vals):
562 if not vals.nfs_root: return
563 if not vals.nfs_server:
564 opts.err('Must set nfs root and nfs server')
565 nfs = 'nfsroot=' + vals.nfs_server + ':' + vals.nfs_root
566 vals.extra = nfs + ' ' + vals.extra
569 def get_host_addr():
570 host = socket.gethostname()
571 addr = socket.gethostbyname(host)
572 return addr
574 VNC_BASE_PORT = 5500
576 def choose_vnc_display():
577 """Try to choose a free vnc display.
578 """
579 def netstat_local_ports():
580 """Run netstat to get a list of the local ports in use.
581 """
582 l = os.popen("netstat -nat").readlines()
583 r = []
584 # Skip 2 lines of header.
585 for x in l[2:]:
586 # Local port is field 3.
587 y = x.split()[3]
588 # Field is addr:port, split off the port.
589 y = y.split(':')[1]
590 r.append(int(y))
591 return r
593 ports = netstat_local_ports()
594 for d in range(1, 100):
595 port = VNC_BASE_PORT + d
596 if port in ports: continue
597 return d
598 return None
600 vncpid = None
602 def spawn_vnc(display):
603 vncargs = (["vncviewer" + "-log", "*:stdout:0",
604 "-listen", "%d" % (VNC_BASE_PORT + display) ])
605 global vncpid
606 vncpid = os.spawnvp(os.P_NOWAIT, "vncviewer", vncargs)
608 return VNC_BASE_PORT + display
610 def preprocess_vnc(opts, vals):
611 """If vnc was specified, spawn a vncviewer in listen mode
612 and pass its address to the domain on the kernel command line.
613 """
614 if not (vals.vnc and vals.vncviewer) or vals.dryrun: return
615 vnc_display = choose_vnc_display()
616 if not vnc_display:
617 opts.warn("No free vnc display")
618 return
619 print 'VNC=', vnc_display
620 vnc_port = spawn_vnc(vnc_display)
621 if vnc_port > 0:
622 vnc_host = get_host_addr()
623 vnc = 'VNC_VIEWER=%s:%d' % (vnc_host, vnc_port)
624 vals.extra = vnc + ' ' + vals.extra
626 def preprocess(opts, vals):
627 if not vals.kernel:
628 opts.err("No kernel specified")
629 preprocess_disk(opts, vals)
630 preprocess_pci(opts, vals)
631 preprocess_vifs(opts, vals)
632 preprocess_ip(opts, vals)
633 preprocess_nfs(opts, vals)
634 preprocess_vnc(opts, vals)
636 def make_domain(opts, config):
637 """Create, build and start a domain.
639 @param opts: options
640 @param config: configuration
641 @return: domain id
642 @rtype: int
643 """
645 try:
646 if opts.vals.load:
647 filename = os.path.abspath(opts.vals.load)
648 dominfo = server.xend_domain_restore(filename, config)
649 else:
650 dominfo = server.xend_domain_create(config)
651 except XendError, ex:
652 import signal
653 if vncpid:
654 os.kill(vncpid, signal.SIGKILL)
655 opts.err(str(ex))
657 dom = sxp.child_value(dominfo, 'name')
659 if not opts.vals.paused:
660 if server.xend_domain_unpause(dom) < 0:
661 server.xend_domain_destroy(dom)
662 opts.err("Failed to unpause domain %s" % dom)
663 opts.info("Started domain %s" % (dom))
664 return int(sxp.child_value(dominfo, 'id'))
666 def get_dom0_alloc():
667 """Return current allocation memory of dom0 (in MB). Return 0 on error"""
668 PROC_XEN_BALLOON = "/proc/xen/balloon"
670 f = open(PROC_XEN_BALLOON, "r")
671 line = f.readline()
672 for x in line.split():
673 for n in x:
674 if not n.isdigit():
675 break
676 else:
677 f.close()
678 return int(x)/1024
679 f.close()
680 return 0
682 def balloon_out(dom0_min_mem, opts):
683 """Balloon out memory from dom0 if necessary"""
684 SLACK = 4
685 timeout = 20 # 2s
686 ret = 0
688 xc = xen.lowlevel.xc.new()
689 pinfo = xc.physinfo()
690 free_mem = pinfo['free_pages'] / 256
691 domU_need_mem = opts.vals.memory + SLACK
693 dom0_cur_alloc = get_dom0_alloc()
694 dom0_new_alloc = dom0_cur_alloc - (domU_need_mem - free_mem)
696 if free_mem < domU_need_mem and dom0_new_alloc < dom0_min_mem:
697 ret = 1
698 if free_mem < domU_need_mem and ret == 0:
700 server.xend_domain_mem_target_set(0, dom0_new_alloc)
702 while dom0_cur_alloc > dom0_new_alloc and timeout > 0:
703 time.sleep(0.1) # sleep 100ms
704 dom0_cur_alloc = get_dom0_alloc()
705 timeout -= 1
707 if dom0_cur_alloc > dom0_new_alloc:
708 ret = 1
710 del xc
711 return ret
713 def main(argv):
714 random.seed()
715 opts = gopts
716 args = opts.parse(argv)
717 if opts.vals.help:
718 opts.usage()
719 if opts.vals.help or opts.vals.help_config:
720 opts.load_defconfig(help=1)
721 if opts.vals.help or opts.vals.help_config:
722 return
723 # Process remaining args as config variables.
724 for arg in args:
725 if '=' in arg:
726 (var, val) = arg.strip().split('=', 1)
727 gopts.setvar(var.strip(), val.strip())
728 opts.vals.display = os.getenv("DISPLAY")
729 if opts.vals.config:
730 config = opts.vals.config
731 else:
732 opts.load_defconfig()
733 preprocess(opts, opts.vals)
734 if not opts.getopt('name') and opts.getopt('defconfig'):
735 opts.setopt('name', os.path.basename(opts.getopt('defconfig')))
736 config = make_config(opts, opts.vals)
738 if opts.vals.dryrun:
739 PrettyPrint.prettyprint(config)
740 else:
741 dom0_min_mem = xroot.get_dom0_min_mem()
742 if dom0_min_mem != 0:
743 if balloon_out(dom0_min_mem, opts):
744 print >>sys.stderr, "error: cannot allocate enough memory for domain"
745 sys.exit(1)
747 dom = make_domain(opts, config)
748 if opts.vals.console_autoconnect:
749 cmd = "/usr/libexec/xen/xenconsole %d" % dom
750 os.execvp('/usr/libexec/xen/xenconsole', cmd.split())
752 if __name__ == '__main__':
753 main(sys.argv)