debuggers.hg
annotate tools/python/xen/xm/create.py @ 3639:ef59b38283a5
bitkeeper revision 1.1159.212.64 (42000361XrdUoEK_vD6RMga2eLmwZg)
Allow specification of backend vif MAC addresses. If a backend
MAC is not provided, generate one as before
Signed-off-by: Jody Belka <knew-xen@pimb.org>
Signed-off-by: ian.pratt@cl.cam.ac.uk
Allow specification of backend vif MAC addresses. If a backend
MAC is not provided, generate one as before
Signed-off-by: Jody Belka <knew-xen@pimb.org>
Signed-off-by: ian.pratt@cl.cam.ac.uk
author | iap10@labyrinth.cl.cam.ac.uk |
---|---|
date | Tue Feb 01 22:32:01 2005 +0000 (2005-02-01) |
parents | 3ced9b0f4dab |
children | bbe8541361dd |
rev | line source |
---|---|
mjw@1661 | 1 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com> |
mjw@1693 | 2 |
mjw@1661 | 3 """Domain creation. |
mjw@1661 | 4 """ |
mjw@1761 | 5 import random |
mjw@1661 | 6 import string |
mjw@1661 | 7 import sys |
mjw@1661 | 8 |
mjw@1661 | 9 from xen.xend import sxp |
mjw@1661 | 10 from xen.xend import PrettyPrint |
mjw@1759 | 11 from xen.xend.XendClient import server, XendError |
mjw@1661 | 12 |
kaf24@1676 | 13 from xen.util import console_client |
kaf24@1676 | 14 |
mjw@1661 | 15 from xen.xm.opts import * |
mjw@1661 | 16 |
mjw@1719 | 17 gopts = Opts(use="""[options] [vars] |
mjw@1661 | 18 |
mjw@1661 | 19 Create a domain. |
mjw@1693 | 20 |
mjw@1693 | 21 Domain creation parameters can be set by command-line switches, from |
mjw@1693 | 22 a python configuration script or an SXP config file. See documentation |
mjw@2327 | 23 for --defconfig, --config. Configuration variables can be set using |
mjw@1693 | 24 VAR=VAL on the command line. For example vmid=3 sets vmid to 3. |
mjw@1693 | 25 |
mjw@1661 | 26 """) |
mjw@1661 | 27 |
mjw@1661 | 28 gopts.opt('help', short='h', |
mjw@2327 | 29 fn=set_true, default=0, |
mjw@2327 | 30 use="Print this help.") |
mjw@1661 | 31 |
mjw@1693 | 32 gopts.opt('help_config', |
mjw@1693 | 33 fn=set_true, default=0, |
mjw@2327 | 34 use="Print help for the configuration script.") |
mjw@1693 | 35 |
mjw@1661 | 36 gopts.opt('quiet', short='q', |
mjw@2327 | 37 fn=set_true, default=0, |
mjw@2327 | 38 use="Quiet.") |
mjw@1661 | 39 |
mjw@1661 | 40 gopts.opt('path', val='PATH', |
mjw@2327 | 41 fn=set_value, default='.:/etc/xen', |
mjw@2327 | 42 use="""Search path for configuration scripts. |
mjw@2327 | 43 The value of PATH is a colon-separated directory list.""") |
mjw@1661 | 44 |
mjw@2327 | 45 gopts.opt('defconfig', short='f', val='FILE', |
mjw@2327 | 46 fn=set_value, default='xmdefconfig', |
mjw@2327 | 47 use="""Use the given Python configuration script. |
mjw@2327 | 48 The configuration script is loaded after arguments have been processed. |
mjw@2327 | 49 Each command-line option sets a configuration variable named after |
mjw@2327 | 50 its long option name, and these variables are placed in the |
mjw@2327 | 51 environment of the script before it is loaded. |
mjw@2327 | 52 Variables for options that may be repeated have list values. |
mjw@2327 | 53 Other variables can be set using VAR=VAL on the command line. |
mjw@2327 | 54 |
mjw@2327 | 55 After the script is loaded, option values that were not set on the |
mjw@2327 | 56 command line are replaced by the values set in the script.""") |
mjw@1661 | 57 |
cl349@2793 | 58 gopts.default('defconfig') |
cl349@2793 | 59 |
mjw@1661 | 60 gopts.opt('config', short='F', val='FILE', |
mjw@2327 | 61 fn=set_value, default=None, |
mjw@2327 | 62 use="""Domain configuration to use (SXP). |
mjw@2327 | 63 SXP is the underlying configuration format used by Xen. |
mjw@2327 | 64 SXP configurations can be hand-written or generated from Python configuration |
mjw@2327 | 65 scripts, using the -n (dryrun) option to print the configuration.""") |
mjw@1661 | 66 |
mjw@1661 | 67 gopts.opt('load', short='L', val='FILE', |
mjw@1661 | 68 fn=set_value, default=None, |
mjw@1661 | 69 use='Domain saved state to load.') |
mjw@1661 | 70 |
mjw@1661 | 71 gopts.opt('dryrun', short='n', |
mjw@1824 | 72 fn=set_true, default=0, |
mjw@2327 | 73 use="""Dry run - print the configuration but don't create the domain. |
mjw@2327 | 74 Loads the configuration script, creates the SXP configuration and prints it.""") |
mjw@1661 | 75 |
mjw@2242 | 76 gopts.opt('paused', short='p', |
mjw@2242 | 77 fn=set_true, default=0, |
mjw@2242 | 78 use='Leave the domain paused after it is created.') |
mjw@2242 | 79 |
kaf24@1676 | 80 gopts.opt('console_autoconnect', short='c', |
mjw@1824 | 81 fn=set_true, default=0, |
mjw@2242 | 82 use="Connect to the console after the domain is created.") |
mjw@1661 | 83 |
mjw@1719 | 84 gopts.var('name', val='NAME', |
mjw@1719 | 85 fn=set_value, default=None, |
mjw@2327 | 86 use="Domain name. Must be unique.") |
mjw@1719 | 87 |
mjw@1719 | 88 gopts.var('kernel', val='FILE', |
mjw@1824 | 89 fn=set_value, default=None, |
mjw@1824 | 90 use="Path to kernel image.") |
mjw@1661 | 91 |
mjw@1719 | 92 gopts.var('ramdisk', val='FILE', |
mjw@1824 | 93 fn=set_value, default='', |
mjw@1824 | 94 use="Path to ramdisk.") |
mjw@1661 | 95 |
mjw@1719 | 96 gopts.var('builder', val='FUNCTION', |
mjw@1824 | 97 fn=set_value, default='linux', |
mjw@1824 | 98 use="Function to use to build the domain.") |
mjw@1661 | 99 |
mjw@1719 | 100 gopts.var('memory', val='MEMORY', |
mjw@2327 | 101 fn=set_int, default=128, |
mjw@1824 | 102 use="Domain memory in MB.") |
mjw@1824 | 103 |
mjw@2441 | 104 gopts.var('maxmem', val='MEMORY', |
mjw@2441 | 105 fn=set_int, default=None, |
mjw@2441 | 106 use="Maximum domain memory in MB.") |
mjw@2441 | 107 |
mjw@2327 | 108 gopts.var('cpu', val='CPU', |
mjw@2327 | 109 fn=set_int, default=None, |
mjw@2327 | 110 use="CPU to run the domain on.") |
mjw@2327 | 111 |
cl349@3489 | 112 gopts.var('vcpus', val='VCPUS', |
cl349@3489 | 113 fn=set_int, default=1, |
cl349@3489 | 114 use="# of Virtual CPUS in domain.") |
cl349@3489 | 115 |
mjw@2288 | 116 gopts.var('cpu_weight', val='WEIGHT', |
mjw@2327 | 117 fn=set_float, default=None, |
mjw@2327 | 118 use="""Set the new domain's cpu weight. |
mjw@2327 | 119 WEIGHT is a float that controls the domain's share of the cpu.""") |
gm281@2274 | 120 |
mjw@1824 | 121 gopts.var('console', val='PORT', |
mjw@1824 | 122 fn=set_int, default=None, |
mjw@1824 | 123 use="Console port to use. Default is 9600 + domain id.") |
mjw@1661 | 124 |
mjw@1823 | 125 gopts.var('restart', val='onreboot|always|never', |
mjw@1824 | 126 fn=set_value, default=None, |
mjw@1824 | 127 use="""Whether the domain should be restarted on exit. |
mjw@2327 | 128 - onreboot: restart on exit with shutdown code reboot |
mjw@2327 | 129 - always: always restart on exit, ignore exit code |
mjw@2327 | 130 - never: never restart on exit, ignore exit code""") |
mjw@1711 | 131 |
mjw@1719 | 132 gopts.var('blkif', val='no|yes', |
mjw@1719 | 133 fn=set_bool, default=0, |
mjw@1661 | 134 use="Make the domain a block device backend.") |
mjw@1661 | 135 |
mjw@1719 | 136 gopts.var('netif', val='no|yes', |
mjw@1719 | 137 fn=set_bool, default=0, |
mjw@1661 | 138 use="Make the domain a network interface backend.") |
mjw@1661 | 139 |
mjw@2305 | 140 gopts.var('disk', val='phy:DEV,VDEV,MODE[,DOM]', |
mjw@1824 | 141 fn=append_value, default=[], |
mjw@1824 | 142 use="""Add a disk device to a domain. The physical device is DEV, |
mjw@2327 | 143 which is exported to the domain as VDEV. The disk is read-only if MODE |
mjw@2327 | 144 is 'r', read-write if MODE is 'w'. If DOM is specified it defines the |
mjw@2327 | 145 backend driver domain to use for the disk. |
mjw@2327 | 146 The option may be repeated to add more than one disk.""") |
mjw@1661 | 147 |
mjw@1719 | 148 gopts.var('pci', val='BUS,DEV,FUNC', |
mjw@1824 | 149 fn=append_value, default=[], |
mjw@1824 | 150 use="""Add a PCI device to a domain, using given params (in hex). |
mjw@1661 | 151 For example '-pci c0,02,1a'. |
mjw@2327 | 152 The option may be repeated to add more than one pci device.""") |
mjw@1661 | 153 |
mwilli2@3501 | 154 gopts.var('usb', val='PATH', |
mwilli2@3501 | 155 fn=append_value, default=[], |
mwilli2@3501 | 156 use="""Add a physical USB port to a domain, as specified by the path |
mwilli2@3501 | 157 to that port. This option may be repeated to add more than one port.""") |
mwilli2@3501 | 158 |
mjw@1719 | 159 gopts.var('ipaddr', val="IPADDR", |
mjw@1824 | 160 fn=append_value, default=[], |
mjw@1824 | 161 use="Add an IP address to the domain.") |
mjw@1661 | 162 |
iap10@3639 | 163 gopts.var('vif', val="mac=MAC,be_mac=MAC,bridge=BRIDGE,script=SCRIPT,backend=DOM", |
mjw@1824 | 164 fn=append_value, default=[], |
mjw@1824 | 165 use="""Add a network interface with the given MAC address and bridge. |
mjw@2327 | 166 The vif is configured by calling the given configuration script. |
mjw@2327 | 167 If mac is not specified a random MAC address is used. |
iap10@3639 | 168 The MAC address of the backend interface can be selected with be_mac. |
iap10@3639 | 169 If not specified then the network backend chooses it's own MAC address. |
mjw@2327 | 170 If bridge is not specified the default bridge is used. |
mjw@2327 | 171 If script is not specified the default script is used. |
mjw@2327 | 172 If backend is not specified the default backend driver domain is used. |
mjw@2327 | 173 This option may be repeated to add more than one vif. |
mjw@2327 | 174 Specifying vifs will increase the number of interfaces as needed.""") |
mjw@1661 | 175 |
mjw@1719 | 176 gopts.var('nics', val="NUM", |
mjw@1824 | 177 fn=set_int, default=1, |
mjw@1824 | 178 use="""Set the number of network interfaces. |
mjw@2327 | 179 Use the vif option to define interface parameters, otherwise |
mjw@2327 | 180 defaults are used. Specifying vifs will increase the |
mjw@2327 | 181 number of interfaces as needed.""") |
mjw@1661 | 182 |
mjw@1719 | 183 gopts.var('root', val='DEVICE', |
mjw@1824 | 184 fn=set_value, default='', |
mjw@1824 | 185 use="""Set the root= parameter on the kernel command line. |
mjw@2327 | 186 Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""") |
mjw@1661 | 187 |
mjw@1719 | 188 gopts.var('extra', val="ARGS", |
mjw@1824 | 189 fn=set_value, default='', |
mjw@1824 | 190 use="Set extra arguments to append to the kernel command line.") |
mjw@1661 | 191 |
mjw@1719 | 192 gopts.var('ip', val='IPADDR', |
mjw@1824 | 193 fn=set_value, default='', |
mjw@1824 | 194 use="Set the kernel IP interface address.") |
mjw@1661 | 195 |
mjw@1719 | 196 gopts.var('gateway', val="IPADDR", |
mjw@1824 | 197 fn=set_value, default='', |
mjw@1824 | 198 use="Set the kernel IP gateway.") |
mjw@1661 | 199 |
mjw@1719 | 200 gopts.var('netmask', val="MASK", |
mjw@1824 | 201 fn=set_value, default = '', |
mjw@1824 | 202 use="Set the kernel IP netmask.") |
mjw@1661 | 203 |
mjw@1719 | 204 gopts.var('hostname', val="NAME", |
mjw@1824 | 205 fn=set_value, default='', |
mjw@1824 | 206 use="Set the kernel IP hostname.") |
mjw@1661 | 207 |
mjw@1719 | 208 gopts.var('interface', val="INTF", |
mjw@1824 | 209 fn=set_value, default="eth0", |
mjw@1824 | 210 use="Set the kernel IP interface name.") |
mjw@1661 | 211 |
mjw@1719 | 212 gopts.var('dhcp', val="off|dhcp", |
mjw@1824 | 213 fn=set_value, default='off', |
mjw@1824 | 214 use="Set the kernel dhcp option.") |
mjw@1661 | 215 |
mjw@1719 | 216 gopts.var('nfs_server', val="IPADDR", |
mjw@1824 | 217 fn=set_value, default=None, |
mjw@1824 | 218 use="Set the address of the NFS server for NFS root.") |
mjw@1661 | 219 |
mjw@1719 | 220 gopts.var('nfs_root', val="PATH", |
mjw@1824 | 221 fn=set_value, default=None, |
mjw@1824 | 222 use="Set the path of the root NFS directory.") |
mjw@1661 | 223 |
iap10@3428 | 224 gopts.var('memmap', val='FILE', |
iap10@3428 | 225 fn=set_value, default='', |
iap10@3428 | 226 use="Path to memap SXP file.") |
iap10@3428 | 227 |
iap10@3428 | 228 gopts.var('device_model', val='FILE', |
iap10@3428 | 229 fn=set_value, default='', |
iap10@3428 | 230 use="Path to device model program.") |
iap10@3428 | 231 |
iap10@3428 | 232 gopts.var('device_config', val='FILE', |
iap10@3428 | 233 fn=set_value, default='', |
iap10@3428 | 234 use="Path to device model configuration.") |
iap10@3428 | 235 |
mjw@1661 | 236 def strip(pre, s): |
mjw@1661 | 237 """Strip prefix 'pre' if present. |
mjw@1661 | 238 """ |
mjw@1661 | 239 if s.startswith(pre): |
mjw@1661 | 240 return s[len(pre):] |
mjw@1661 | 241 else: |
mjw@1661 | 242 return s |
mjw@1661 | 243 |
mjw@1746 | 244 def configure_image(config, vals): |
mjw@1661 | 245 """Create the image config. |
mjw@1661 | 246 """ |
mjw@1746 | 247 config_image = [ vals.builder ] |
mjw@1746 | 248 config_image.append([ 'kernel', os.path.abspath(vals.kernel) ]) |
mjw@1746 | 249 if vals.ramdisk: |
mjw@1746 | 250 config_image.append([ 'ramdisk', os.path.abspath(vals.ramdisk) ]) |
mjw@1746 | 251 if vals.cmdline_ip: |
mjw@1746 | 252 cmdline_ip = strip('ip=', vals.cmdline_ip) |
mjw@1661 | 253 config_image.append(['ip', cmdline_ip]) |
mjw@1746 | 254 if vals.root: |
mjw@1746 | 255 cmdline_root = strip('root=', vals.root) |
mjw@1661 | 256 config_image.append(['root', cmdline_root]) |
mjw@1746 | 257 if vals.extra: |
mjw@1746 | 258 config_image.append(['args', vals.extra]) |
cl349@3489 | 259 if vals.vcpus: |
cl349@3489 | 260 config_image.append(['vcpus', vals.vcpus]) |
mjw@1661 | 261 config.append(['image', config_image ]) |
cl349@3489 | 262 |
mjw@1661 | 263 |
mjw@1746 | 264 def configure_disks(config_devs, vals): |
mjw@1661 | 265 """Create the config for disks (virtual block devices). |
mjw@1661 | 266 """ |
mjw@2305 | 267 for (uname, dev, mode, backend) in vals.disk: |
mjw@1661 | 268 config_vbd = ['vbd', |
mjw@1661 | 269 ['uname', uname], |
mjw@1661 | 270 ['dev', dev ], |
mjw@1661 | 271 ['mode', mode ] ] |
mjw@2305 | 272 if backend: |
mjw@2305 | 273 config_vbd.append(['backend', backend]) |
mjw@1661 | 274 config_devs.append(['device', config_vbd]) |
mjw@1661 | 275 |
mjw@1746 | 276 def configure_pci(config_devs, vals): |
mjw@1661 | 277 """Create the config for pci devices. |
mjw@1661 | 278 """ |
mjw@1746 | 279 for (bus, dev, func) in vals.pci: |
mjw@1661 | 280 config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]] |
mjw@1661 | 281 config_devs.append(['device', config_pci]) |
mjw@1661 | 282 |
mwilli2@3501 | 283 def configure_usb(config_devs, vals): |
mwilli2@3501 | 284 for path in vals.usb: |
mwilli2@3501 | 285 config_usb = ['usb', ['path', path]] |
mwilli2@3501 | 286 config_devs.append(['device', config_usb]) |
mwilli2@3501 | 287 |
mjw@1761 | 288 def randomMAC(): |
mjw@1761 | 289 """Generate a random MAC address. |
mjw@1761 | 290 |
mjw@1761 | 291 Uses OUI (Organizationally Unique Identifier) AA:00:00, an |
mjw@1761 | 292 unassigned one that used to belong to DEC. The OUI list is |
mjw@1761 | 293 available at 'standards.ieee.org'. |
mjw@1761 | 294 |
mjw@1761 | 295 The remaining 3 fields are random, with the first bit of the first |
mjw@1761 | 296 random field set 0. |
mjw@1761 | 297 |
mjw@2327 | 298 @return: MAC address string |
mjw@1761 | 299 """ |
kaf24@2674 | 300 random.seed() |
mjw@1761 | 301 mac = [ 0xaa, 0x00, 0x00, |
mjw@1761 | 302 random.randint(0x00, 0x7f), |
mjw@1761 | 303 random.randint(0x00, 0xff), |
mjw@1761 | 304 random.randint(0x00, 0xff) ] |
mjw@1808 | 305 return ':'.join(map(lambda x: "%02x" % x, mac)) |
mjw@1761 | 306 |
mjw@1746 | 307 def configure_vifs(config_devs, vals): |
mjw@1661 | 308 """Create the config for virtual network interfaces. |
mjw@1661 | 309 """ |
mjw@1746 | 310 vifs = vals.vif |
mjw@1746 | 311 vifs_n = max(vals.nics, len(vifs)) |
mjw@1661 | 312 |
mjw@1661 | 313 for idx in range(0, vifs_n): |
mjw@1661 | 314 if idx < len(vifs): |
mjw@1661 | 315 d = vifs[idx] |
mjw@1661 | 316 mac = d.get('mac') |
kaf24@3469 | 317 if not mac: |
kaf24@3469 | 318 mac = randomMAC() |
iap10@3639 | 319 be_mac = d.get('be_mac') |
mjw@1661 | 320 bridge = d.get('bridge') |
mjw@1761 | 321 script = d.get('script') |
mjw@2305 | 322 backend = d.get('backend') |
kaf24@3469 | 323 ip = d.get('ip') |
mjw@1661 | 324 else: |
mjw@1761 | 325 mac = randomMAC() |
iap10@3639 | 326 be_mac = None |
mjw@1661 | 327 bridge = None |
mjw@1761 | 328 script = None |
mjw@2305 | 329 backend = None |
kaf24@3469 | 330 ip = None |
mjw@1661 | 331 config_vif = ['vif'] |
mjw@1761 | 332 config_vif.append(['mac', mac]) |
iap10@3639 | 333 if be_mac: |
iap10@3639 | 334 config_vif.append(['be_mac', be_mac]) |
mjw@1661 | 335 if bridge: |
mjw@1661 | 336 config_vif.append(['bridge', bridge]) |
mjw@1761 | 337 if script: |
mjw@1761 | 338 config_vif.append(['script', script]) |
mjw@2305 | 339 if backend: |
mjw@2305 | 340 config_vif.append(['backend', backend]) |
kaf24@3469 | 341 if ip: |
kaf24@3469 | 342 config_vif.append(['ip', ip]) |
mjw@1661 | 343 config_devs.append(['device', config_vif]) |
mjw@1661 | 344 |
mjw@1746 | 345 def configure_vfr(config, vals): |
mjw@1746 | 346 if not vals.ipaddr: return |
mjw@1661 | 347 config_vfr = ['vfr'] |
mjw@1661 | 348 idx = 0 # No way of saying which IP is for which vif? |
mjw@1746 | 349 for ip in vals.ipaddr: |
mjw@1661 | 350 config_vfr.append(['vif', ['id', idx], ['ip', ip]]) |
mjw@1661 | 351 config.append(config_vfr) |
mjw@1661 | 352 |
iap10@3428 | 353 def configure_vmx(config_devs, vals): |
iap10@3428 | 354 """Create the config for VMX devices. |
iap10@3428 | 355 """ |
iap10@3428 | 356 memmap = vals.memmap |
iap10@3428 | 357 device_model = vals.device_model |
iap10@3428 | 358 device_config = vals.device_config |
iap10@3428 | 359 config_devs.append(['memmap', memmap]) |
iap10@3428 | 360 config_devs.append(['device_model', device_model]) |
iap10@3428 | 361 config_devs.append(['device_config', device_config]) |
mjw@1661 | 362 |
mjw@1746 | 363 def make_config(vals): |
mjw@1661 | 364 """Create the domain configuration. |
mjw@1661 | 365 """ |
mjw@1661 | 366 |
mjw@1661 | 367 config = ['vm', |
mjw@1746 | 368 ['name', vals.name ], |
mjw@2327 | 369 ['memory', vals.memory ]] |
mjw@2441 | 370 if vals.maxmem: |
mjw@2441 | 371 config.append(['maxmem', vals.maxmem]) |
mjw@2327 | 372 if vals.cpu is not None: |
mjw@1746 | 373 config.append(['cpu', vals.cpu]) |
mjw@2327 | 374 if vals.cpu_weight is not None: |
mjw@2327 | 375 config.append(['cpu_weight', vals.cpu_weight]) |
mjw@1746 | 376 if vals.blkif: |
mjw@1661 | 377 config.append(['backend', ['blkif']]) |
mjw@1746 | 378 if vals.netif: |
mjw@1661 | 379 config.append(['backend', ['netif']]) |
mjw@1823 | 380 if vals.restart: |
mjw@1823 | 381 config.append(['restart', vals.restart]) |
mjw@1824 | 382 if vals.console: |
mjw@1824 | 383 config.append(['console', vals.console]) |
mjw@1661 | 384 |
mjw@1746 | 385 configure_image(config, vals) |
mjw@1661 | 386 config_devs = [] |
mjw@1746 | 387 configure_disks(config_devs, vals) |
mjw@1746 | 388 configure_pci(config_devs, vals) |
mjw@1746 | 389 configure_vifs(config_devs, vals) |
mwilli2@3501 | 390 configure_usb(config_devs, vals) |
iap10@3428 | 391 configure_vmx(config_devs, vals) |
mjw@1661 | 392 config += config_devs |
mjw@1661 | 393 return config |
mjw@1661 | 394 |
mjw@1746 | 395 def preprocess_disk(opts, vals): |
mjw@1746 | 396 if not vals.disk: return |
mjw@1661 | 397 disk = [] |
mjw@1746 | 398 for v in vals.disk: |
mjw@1661 | 399 d = v.split(',') |
mjw@2305 | 400 n = len(d) |
mjw@2305 | 401 if n == 3: |
mjw@2307 | 402 d.append(None) |
mjw@2305 | 403 elif n == 4: |
mjw@2305 | 404 pass |
mjw@2305 | 405 else: |
mjw@1661 | 406 opts.err('Invalid disk specifier: ' + v) |
mjw@1661 | 407 disk.append(d) |
mjw@1746 | 408 vals.disk = disk |
mjw@1661 | 409 |
mjw@1746 | 410 def preprocess_pci(opts, vals): |
mjw@1746 | 411 if not vals.pci: return |
mjw@1661 | 412 pci = [] |
mjw@1746 | 413 for v in vals.pci: |
mjw@1661 | 414 d = v.split(',') |
mjw@1661 | 415 if len(d) != 3: |
mjw@1661 | 416 opts.err('Invalid pci specifier: ' + v) |
mjw@1661 | 417 # Components are in hex: add hex specifier. |
mjw@1661 | 418 hexd = map(lambda v: '0x'+v, d) |
mjw@1661 | 419 pci.append(hexd) |
mjw@1746 | 420 vals.pci = pci |
mjw@1661 | 421 |
mjw@1746 | 422 def preprocess_vifs(opts, vals): |
mjw@1746 | 423 if not vals.vif: return |
mjw@1661 | 424 vifs = [] |
mjw@1746 | 425 for vif in vals.vif: |
mjw@1661 | 426 d = {} |
mjw@1661 | 427 a = vif.split(',') |
mjw@1661 | 428 for b in a: |
mjw@1719 | 429 (k, v) = b.strip().split('=', 1) |
mjw@1661 | 430 k = k.strip() |
mjw@1661 | 431 v = v.strip() |
iap10@3639 | 432 if k not in ['mac', 'be_mac', 'bridge', 'script', 'backend', 'ip']: |
mjw@1661 | 433 opts.err('Invalid vif specifier: ' + vif) |
mjw@1661 | 434 d[k] = v |
mjw@1661 | 435 vifs.append(d) |
mjw@1746 | 436 vals.vif = vifs |
mjw@1661 | 437 |
mjw@1746 | 438 def preprocess_ip(opts, vals): |
iap10@2075 | 439 if vals.ip or vals.dhcp != 'off': |
iap10@2075 | 440 dummy_nfs_server = '1.2.3.4' |
iap10@2075 | 441 ip = (vals.ip |
mjw@1804 | 442 + ':' + (vals.nfs_server or dummy_nfs_server) |
mjw@1746 | 443 + ':' + vals.gateway |
mjw@1746 | 444 + ':' + vals.netmask |
mjw@1746 | 445 + ':' + vals.hostname |
mjw@1746 | 446 + ':' + vals.interface |
mjw@1746 | 447 + ':' + vals.dhcp) |
iap10@2075 | 448 else: |
iap10@2075 | 449 ip = '' |
mjw@1746 | 450 vals.cmdline_ip = ip |
mjw@1661 | 451 |
mjw@1746 | 452 def preprocess_nfs(opts, vals): |
mjw@1804 | 453 if not vals.nfs_root: return |
mjw@1804 | 454 if not vals.nfs_server: |
mjw@1804 | 455 opts.err('Must set nfs root and nfs server') |
mjw@1746 | 456 nfs = 'nfsroot=' + vals.nfs_server + ':' + vals.nfs_root |
mjw@1746 | 457 vals.extra = nfs + ' ' + vals.extra |
mjw@1661 | 458 |
mjw@1746 | 459 def preprocess(opts, vals): |
mjw@1746 | 460 if not vals.kernel: |
mjw@1661 | 461 opts.err("No kernel specified") |
mjw@1746 | 462 preprocess_disk(opts, vals) |
mjw@1746 | 463 preprocess_pci(opts, vals) |
mjw@1746 | 464 preprocess_vifs(opts, vals) |
mjw@1746 | 465 preprocess_ip(opts, vals) |
mjw@1746 | 466 preprocess_nfs(opts, vals) |
mjw@1661 | 467 |
mjw@1661 | 468 def make_domain(opts, config): |
mjw@1661 | 469 """Create, build and start a domain. |
mjw@1759 | 470 |
mjw@1759 | 471 @param opts: options |
mjw@1759 | 472 @param config: configuration |
mjw@1759 | 473 @return: domain id, console port |
mjw@1759 | 474 @rtype: (int, int) |
mjw@1661 | 475 """ |
mjw@1759 | 476 |
mjw@1759 | 477 try: |
mjw@1759 | 478 if opts.vals.load: |
mjw@1759 | 479 filename = os.path.abspath(opts.vals.load) |
mjw@1759 | 480 dominfo = server.xend_domain_restore(filename, config) |
mjw@1759 | 481 else: |
mjw@1759 | 482 dominfo = server.xend_domain_create(config) |
mjw@1759 | 483 except XendError, ex: |
mjw@1759 | 484 opts.err(str(ex)) |
mjw@1661 | 485 |
mjw@2013 | 486 dom = sxp.child_value(dominfo, 'name') |
mjw@1661 | 487 console_info = sxp.child(dominfo, 'console') |
mjw@1661 | 488 if console_info: |
mjw@1931 | 489 console_port = int(sxp.child_value(console_info, 'console_port')) |
mjw@1661 | 490 else: |
mjw@1661 | 491 console_port = None |
mjw@2242 | 492 |
mjw@2242 | 493 if not opts.vals.paused: |
mjw@2242 | 494 if server.xend_domain_unpause(dom) < 0: |
mjw@2242 | 495 server.xend_domain_destroy(dom) |
mjw@2242 | 496 opts.err("Failed to unpause domain %s" % dom) |
mjw@2013 | 497 opts.info("Started domain %s, console on port %d" |
mjw@1661 | 498 % (dom, console_port)) |
mjw@1661 | 499 return (dom, console_port) |
mjw@1661 | 500 |
mjw@1661 | 501 def main(argv): |
mjw@1661 | 502 opts = gopts |
mjw@1661 | 503 args = opts.parse(argv) |
mjw@1661 | 504 if opts.vals.help: |
mjw@1661 | 505 opts.usage() |
mjw@1693 | 506 if opts.vals.help or opts.vals.help_config: |
mjw@2327 | 507 opts.load_defconfig(help=1) |
mjw@1693 | 508 if opts.vals.help or opts.vals.help_config: |
mjw@1661 | 509 return |
mjw@1693 | 510 # Process remaining args as config variables. |
mjw@1693 | 511 for arg in args: |
mjw@1693 | 512 if '=' in arg: |
mjw@1719 | 513 (var, val) = arg.strip().split('=', 1) |
mjw@1693 | 514 gopts.setvar(var.strip(), val.strip()) |
mjw@1661 | 515 if opts.vals.config: |
mjw@1942 | 516 config = opts.vals.config |
mjw@1661 | 517 else: |
mjw@2327 | 518 opts.load_defconfig() |
mjw@1942 | 519 preprocess(opts, opts.vals) |
cl349@2794 | 520 if not opts.getopt('name') and opts.getopt('defconfig'): |
cl349@2794 | 521 opts.setopt('name', os.path.basename(opts.getopt('defconfig'))) |
mjw@1942 | 522 config = make_config(opts.vals) |
mjw@1661 | 523 if opts.vals.dryrun: |
mjw@1661 | 524 PrettyPrint.prettyprint(config) |
mjw@1661 | 525 else: |
mjw@1759 | 526 (dom, console) = make_domain(opts, config) |
kaf24@1676 | 527 if opts.vals.console_autoconnect: |
mjw@1759 | 528 console_client.connect('localhost', console) |
mjw@1661 | 529 |
mjw@1661 | 530 if __name__ == '__main__': |
mjw@1661 | 531 main(sys.argv) |