xen-vtx-unstable

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