ia64/xen-unstable

view tools/python/xen/xm/create.py @ 1770:1331621fe269

bitkeeper revision 1.1076 (40f3f7b4Cj4P09-PODiTO2MMFlKicw)

Add device create and device destroy for an existing domain.
author mjw@wray-m-3.hpl.hp.com
date Tue Jul 13 14:54:44 2004 +0000 (2004-07-13)
parents 1858589ab205
children 9a1d945b5038 61599b006364
line source
1 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
3 """Domain creation.
4 """
5 import random
6 import string
7 import sys
9 from xen.xend import sxp
10 from xen.xend import PrettyPrint
11 from xen.xend.XendClient import server, XendError
13 from xen.util import console_client
15 from xen.xm.opts import *
17 gopts = Opts(use="""[options] [vars]
19 Create a domain.
21 Domain creation parameters can be set by command-line switches, from
22 a python configuration script or an SXP config file. See documentation
23 for --defaults, --config. Configuration variables can be set using
24 VAR=VAL on the command line. For example vmid=3 sets vmid to 3.
26 """)
28 gopts.opt('help', short='h',
29 fn=set_true, default=0,
30 use="Print this help.")
32 gopts.opt('help_config',
33 fn=set_true, default=0,
34 use="Print help for configuration file.")
36 gopts.opt('quiet', short='q',
37 fn=set_true, default=0,
38 use="Quiet.")
40 gopts.opt('path', val='PATH',
41 fn=set_value, default='.:/etc/xen',
42 use="Search path for default scripts.")
44 gopts.opt('defaults', short='f', val='FILE',
45 fn=set_value, default='xmdefaults',
46 use="""Use the given Python defaults script.
47 The defaults script is loaded after arguments have been processed.
48 Each command-line option sets a configuration variable named after
49 its long option name, and these variables are placed in the
50 environment of the script before it is loaded.
51 Variables for options that may be repeated have list values.
52 Other variables can be set using VAR=VAL on the command line.
54 After the script is loaded, option values that were not set on the
55 command line are replaced by the values set in the script.
56 """)
58 gopts.opt('config', short='F', val='FILE',
59 fn=set_value, default=None,
60 use="""Domain configuration to use (SXP).
61 SXP is the underlying configuration format used by Xen.
62 SXP configs can be hand-written or generated from Python defaults
63 scripts, using the -n (dryrun) option to print the config.
64 """)
66 gopts.opt('load', short='L', val='FILE',
67 fn=set_value, default=None,
68 use='Domain saved state to load.')
70 gopts.opt('dryrun', short='n',
71 fn=set_true, default=0,
72 use="""Dry run - print the config but don't create the domain.
73 The defaults file is loaded and the SXP configuration is created and printed.
74 """)
76 gopts.opt('console_autoconnect', short='c',
77 fn=set_true, default=0,
78 use="Connect to console after domain is created.")
80 gopts.var('name', val='NAME',
81 fn=set_value, default=None,
82 use="Domain name.")
84 gopts.var('kernel', val='FILE',
85 fn=set_value, default=None,
86 use="Path to kernel image.")
88 gopts.var('ramdisk', val='FILE',
89 fn=set_value, default='',
90 use="Path to ramdisk.")
92 gopts.var('builder', val='FUNCTION',
93 fn=set_value, default='linux',
94 use="Function to use to build the domain.")
96 gopts.var('memory', val='MEMORY',
97 fn=set_value, default=128,
98 use="Domain memory in MB.")
100 gopts.var('autorestart', val='no|yes',
101 fn=set_bool, default=0,
102 use="Whether to restart the domain on exit.")
104 gopts.var('blkif', val='no|yes',
105 fn=set_bool, default=0,
106 use="Make the domain a block device backend.")
108 gopts.var('netif', val='no|yes',
109 fn=set_bool, default=0,
110 use="Make the domain a network interface backend.")
112 gopts.var('disk', val='phy:DEV,VDEV,MODE',
113 fn=append_value, default=[],
114 use="""Add a disk device to a domain. The physical device is DEV,
115 which is exported to the domain as VDEV. The disk is read-only if MODE
116 is 'r', read-write if MODE is 'w'.
117 The option may be repeated to add more than one disk.
118 """)
120 gopts.var('pci', val='BUS,DEV,FUNC',
121 fn=append_value, default=[],
122 use="""Add a PCI device to a domain, using given params (in hex).
123 For example '-pci c0,02,1a'.
124 The option may be repeated to add more than one pci device.
125 """)
127 gopts.var('ipaddr', val="IPADDR",
128 fn=append_value, default=[],
129 use="Add an IP address to the domain.")
131 gopts.var('vif', val="mac=MAC,bridge=BRIDGE,script=SCRIPT",
132 fn=append_value, default=[],
133 use="""Add a network interface with the given MAC address and bridge.
134 The vif is configured by calling the given configuration script.
135 If mac is not specified a random MAC address is used.
136 If bridge is not specified the default bridge is used.
137 If script is not specified the default script is used.
138 This option may be repeated to add more than one vif.
139 Specifying vifs will increase the number of interfaces as needed.
140 """)
142 gopts.var('nics', val="NUM",
143 fn=set_int, default=1,
144 use="""Set the number of network interfaces.
145 Use the vif option to define interface parameters, otherwise
146 defaults are used. Specifying vifs will increase the
147 number of interfaces as needed.
148 """)
150 gopts.var('root', val='DEVICE',
151 fn=set_value, default='',
152 use="""Set the root= parameter on the kernel command line.
153 Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""")
155 gopts.var('extra', val="ARGS",
156 fn=set_value, default='',
157 use="Set extra arguments to append to the kernel command line.")
159 gopts.var('ip', val='IPADDR',
160 fn=set_value, default='',
161 use="Set the kernel IP interface address.")
163 gopts.var('gateway', val="IPADDR",
164 fn=set_value, default='',
165 use="Set the kernel IP gateway.")
167 gopts.var('netmask', val="MASK",
168 fn=set_value, default = '',
169 use="Set the kernel IP netmask.")
171 gopts.var('hostname', val="NAME",
172 fn=set_value, default='',
173 use="Set the kernel IP hostname.")
175 gopts.var('interface', val="INTF",
176 fn=set_value, default="eth0",
177 use="Set the kernel IP interface name.")
179 gopts.var('dhcp', val="off|dhcp",
180 fn=set_value, default='off',
181 use="Set the kernel dhcp option.")
183 gopts.var('nfs_server', val="IPADDR",
184 fn=set_value, default=None,
185 use="Set the address of the NFS server for NFS root.")
187 gopts.var('nfs_root', val="PATH",
188 fn=set_value, default=None,
189 use="Set the path of the root NFS directory.")
191 def strip(pre, s):
192 """Strip prefix 'pre' if present.
193 """
194 if s.startswith(pre):
195 return s[len(pre):]
196 else:
197 return s
199 def configure_image(config, vals):
200 """Create the image config.
201 """
202 config_image = [ vals.builder ]
203 config_image.append([ 'kernel', os.path.abspath(vals.kernel) ])
204 if vals.ramdisk:
205 config_image.append([ 'ramdisk', os.path.abspath(vals.ramdisk) ])
206 if vals.cmdline_ip:
207 cmdline_ip = strip('ip=', vals.cmdline_ip)
208 config_image.append(['ip', cmdline_ip])
209 if vals.root:
210 cmdline_root = strip('root=', vals.root)
211 config_image.append(['root', cmdline_root])
212 if vals.extra:
213 config_image.append(['args', vals.extra])
214 config.append(['image', config_image ])
216 def configure_disks(config_devs, vals):
217 """Create the config for disks (virtual block devices).
218 """
219 for (uname, dev, mode) in vals.disk:
220 config_vbd = ['vbd',
221 ['uname', uname],
222 ['dev', dev ],
223 ['mode', mode ] ]
224 config_devs.append(['device', config_vbd])
226 def configure_pci(config_devs, vals):
227 """Create the config for pci devices.
228 """
229 for (bus, dev, func) in vals.pci:
230 config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]]
231 config_devs.append(['device', config_pci])
233 def randomMAC():
234 """Generate a random MAC address.
236 Uses OUI (Organizationally Unique Identifier) AA:00:00, an
237 unassigned one that used to belong to DEC. The OUI list is
238 available at 'standards.ieee.org'.
240 The remaining 3 fields are random, with the first bit of the first
241 random field set 0.
243 returns array of 6 ints
244 """
245 mac = [ 0xaa, 0x00, 0x00,
246 random.randint(0x00, 0x7f),
247 random.randint(0x00, 0xff),
248 random.randint(0x00, 0xff) ]
249 return ':'.join(map(lambda x: "%02x" % x, mac))
251 def configure_vifs(config_devs, vals):
252 """Create the config for virtual network interfaces.
253 """
254 vifs = vals.vif
255 vifs_n = max(vals.nics, len(vifs))
257 for idx in range(0, vifs_n):
258 if idx < len(vifs):
259 d = vifs[idx]
260 mac = d.get('mac')
261 bridge = d.get('bridge')
262 script = d.get('script')
263 else:
264 mac = randomMAC()
265 bridge = None
266 script = None
267 config_vif = ['vif']
268 config_vif.append(['mac', mac])
269 if bridge:
270 config_vif.append(['bridge', bridge])
271 if script:
272 config_vif.append(['script', script])
273 config_devs.append(['device', config_vif])
275 def configure_vfr(config, vals):
276 if not vals.ipaddr: return
277 config_vfr = ['vfr']
278 idx = 0 # No way of saying which IP is for which vif?
279 for ip in vals.ipaddr:
280 config_vfr.append(['vif', ['id', idx], ['ip', ip]])
281 config.append(config_vfr)
284 def make_config(vals):
285 """Create the domain configuration.
286 """
288 config = ['vm',
289 ['name', vals.name ],
290 ['memory', vals.memory ] ]
291 if vals.cpu:
292 config.append(['cpu', vals.cpu])
293 if vals.blkif:
294 config.append(['backend', ['blkif']])
295 if vals.netif:
296 config.append(['backend', ['netif']])
297 if vals.autorestart:
298 config.append(['autorestart'])
300 configure_image(config, vals)
301 config_devs = []
302 configure_disks(config_devs, vals)
303 configure_pci(config_devs, vals)
304 configure_vifs(config_devs, vals)
305 config += config_devs
306 return config
308 def preprocess_disk(opts, vals):
309 if not vals.disk: return
310 disk = []
311 for v in vals.disk:
312 d = v.split(',')
313 if len(d) != 3:
314 opts.err('Invalid disk specifier: ' + v)
315 disk.append(d)
316 vals.disk = disk
318 def preprocess_pci(opts, vals):
319 if not vals.pci: return
320 pci = []
321 for v in vals.pci:
322 d = v.split(',')
323 if len(d) != 3:
324 opts.err('Invalid pci specifier: ' + v)
325 # Components are in hex: add hex specifier.
326 hexd = map(lambda v: '0x'+v, d)
327 pci.append(hexd)
328 vals.pci = pci
330 def preprocess_vifs(opts, vals):
331 if not vals.vif: return
332 vifs = []
333 for vif in vals.vif:
334 d = {}
335 a = vif.split(',')
336 for b in a:
337 (k, v) = b.strip().split('=', 1)
338 k = k.strip()
339 v = v.strip()
340 if k not in ['mac', 'bridge']:
341 opts.err('Invalid vif specifier: ' + vif)
342 d[k] = v
343 vifs.append(d)
344 vals.vif = vifs
346 def preprocess_ip(opts, vals):
347 setip = (vals.hostname or vals.netmask
348 or vals.gateway or vals.dhcp or vals.interface)
349 if not setip: return
350 dummy_nfs_server = '1.2.3.4'
351 ip = (vals.ip
352 + ':' + (vals.nfs_server or dummy_nfs_server)
353 + ':' + vals.gateway
354 + ':' + vals.netmask
355 + ':' + vals.hostname
356 + ':' + vals.interface
357 + ':' + vals.dhcp)
358 vals.cmdline_ip = ip
360 def preprocess_nfs(opts, vals):
361 if not vals.nfs_root: return
362 if not vals.nfs_server:
363 opts.err('Must set nfs root and nfs server')
364 nfs = 'nfsroot=' + vals.nfs_server + ':' + vals.nfs_root
365 vals.extra = nfs + ' ' + vals.extra
367 def preprocess(opts, vals):
368 if not vals.kernel:
369 opts.err("No kernel specified")
370 preprocess_disk(opts, vals)
371 preprocess_pci(opts, vals)
372 preprocess_vifs(opts, vals)
373 preprocess_ip(opts, vals)
374 preprocess_nfs(opts, vals)
376 def make_domain(opts, config):
377 """Create, build and start a domain.
379 @param opts: options
380 @param config: configuration
381 @return: domain id, console port
382 @rtype: (int, int)
383 """
385 try:
386 if opts.vals.load:
387 filename = os.path.abspath(opts.vals.load)
388 dominfo = server.xend_domain_restore(filename, config)
389 else:
390 dominfo = server.xend_domain_create(config)
391 except XendError, ex:
392 opts.err(str(ex))
394 dom = int(sxp.child_value(dominfo, 'id'))
395 console_info = sxp.child(dominfo, 'console')
396 if console_info:
397 console_port = int(sxp.child_value(console_info, 'port'))
398 else:
399 console_port = None
401 if server.xend_domain_unpause(dom) < 0:
402 server.xend_domain_destroy(dom)
403 opts.err("Failed to unpause domain %d" % dom)
404 opts.info("Started domain %d, console on port %d"
405 % (dom, console_port))
406 return (dom, console_port)
408 def main(argv):
409 opts = gopts
410 args = opts.parse(argv)
411 if opts.vals.help:
412 opts.usage()
413 if opts.vals.help or opts.vals.help_config:
414 opts.load_defaults(help=1)
415 if opts.vals.help or opts.vals.help_config:
416 return
417 # Process remaining args as config variables.
418 for arg in args:
419 if '=' in arg:
420 (var, val) = arg.strip().split('=', 1)
421 gopts.setvar(var.strip(), val.strip())
422 if opts.vals.config:
423 pass
424 else:
425 opts.load_defaults()
426 preprocess(opts, opts.vals)
427 config = make_config(opts.vals)
428 if opts.vals.dryrun:
429 PrettyPrint.prettyprint(config)
430 else:
431 (dom, console) = make_domain(opts, config)
432 if opts.vals.console_autoconnect:
433 console_client.connect('localhost', console)
435 if __name__ == '__main__':
436 main(sys.argv)