ia64/xen-unstable

view tools/examples/xm_dom_create.py @ 1473:961d5215a403

bitkeeper revision 1.946.1.6 (40cdc926l8Wh79r18XRQwvpcDIDqXA)

Add a config line for the network interface.
author mjw@wray-m-3.hpl.hp.com
date Mon Jun 14 15:49:58 2004 +0000 (2004-06-14)
parents 1d69c0528a2e
children 3cf2ba082a24
line source
1 #!/usr/bin/env python
3 import string
4 import sys
5 import os
6 import os.path
7 import time
8 import socket
9 import getopt
10 import signal
11 import syslog
13 import xenctl.console_client
15 from xenmgr import sxp
16 from xenmgr import PrettyPrint
17 from xenmgr.XendClient import server
19 config_dir = '/etc/xc/'
20 config_file = xc_config_file = config_dir + 'defaults'
22 def main_usage ():
23 print >>sys.stderr,"""
24 Usage: %s <args>
26 This tool is used to create and start new domains. It reads defaults
27 from a file written in Python, having allowed variables to be set and
28 passed into the file. Further command line arguments allow the
29 defaults to be overridden. The defaults for each parameter are listed
30 in [] brackets. Arguments are as follows:
32 Arguments to control the parsing of the defaults file:
33 -f config_file -- Use the specified defaults script.
34 Default: ['%s']
35 -L state_file -- Load virtual machine memory state from state_file
36 -D foo=bar -- Set variable foo=bar before parsing config
37 E.g. '-D vmid=3;ip=1.2.3.4'
38 -h -- Print extended help message, including all arguments
39 -n -- Dry run only, don't actually create domain
40 Prints the config, suitable for -F.
41 -q -- Quiet - write output only to the system log
42 -F domain_config -- Build domain using the config in the file.
43 Suitable files can be made using '-n' to output a config.
44 """ % (sys.argv[0], xc_config_file)
46 def extra_usage ():
47 print >>sys.stderr,"""
48 Arguments to override current config read from '%s':
49 -c -- Turn into console terminal after domain is created
50 -k image -- Path to kernel image ['%s']
51 -r ramdisk -- Path to ramdisk (or empty) ['%s']
52 -b builder_fn -- Function to use to build domain ['%s']
53 -m mem_size -- Initial memory allocation in MB [%dMB]
54 -N domain_name -- Set textual name of domain ['%s']
55 -a auto_restart -- Restart domain on exit, yes/no ['%d']
56 -e vbd_expert -- Safety catch to avoid some disk accidents ['%s']
57 -d udisk,dev,rw -- Add disk, partition, or virtual disk to domain. E.g. to
58 make partion sda4 available to the domain as hda1 with
59 read-write access: '-d phy:sda4,hda1,rw' To add
60 multiple disks use multiple -d flags or seperate with ';'
61 Default: ['%s']
62 -i vfr_ipaddr -- Add IP address to the list which Xen will route to
63 the domain. Use multiple times to add more IP addrs.
64 Default: ['%s']
66 Args to override the kernel command line, which is concatenated from these:
67 -I cmdline_ip -- Override 'ip=ipaddr:nfsserv:gateway:netmask::eth0:off'
68 Default: ['%s']
69 -R cmdline_root -- Override root device parameters.
70 Default: ['%s']
71 -E cmdline_extra -- Override extra kernel args and rc script env vars.
72 Default: ['%s']
74 """ % (config_file,
75 image, ramdisk, builder_fn, mem_size, domain_name, auto_restart,
76 vbd_expert,
77 printvbds( vbd_list ),
78 reduce ( (lambda a,b: a+':'+b), vfr_ipaddr,'' )[1:],
79 cmdline_ip, cmdline_root, cmdline_extra)
81 def config_usage (): pass
83 def answer ( s ):
84 s = string.lower(s)
85 if s == 'yes' or s == 'true' or s == '1': return 1
86 return 0
88 def printvbds ( v ):
89 s=''
90 for (a,b,c) in v:
91 s = s + '; %s,%s,%s' % (a,b,c)
92 return s[2:]
94 def output(string):
95 global quiet
96 syslog.syslog(string)
97 if not quiet:
98 print string
99 return
101 bail=False; dryrun=False; extrahelp=False; quiet = False
102 image=''; ramdisk=''; builder_fn='linux'; restore=0; state_file=''
103 mem_size=0; domain_name=''; vfr_ipaddr=[];
104 vbd_expert='rr'; auto_restart=False;
105 vbd_list = []; cmdline_ip = ''; cmdline_root=''; cmdline_extra=''
106 pci_device_list = []; console_port = -1
107 auto_console = False
108 config_from_file = False
110 ##### Determine location of defaults file
111 #####
113 try:
114 opts, args = getopt.getopt(sys.argv[1:], "h?nqcf:F:D:k:r:b:m:N:a:e:d:i:I:R:E:L:" )
116 for opt in opts:
117 if opt[0] == '-f': config_file= opt[1]
118 if opt[0] == '-h' or opt[0] == '-?' : bail=True; extrahelp=True
119 if opt[0] == '-n': dryrun=True
120 if opt[0] == '-D':
121 for o in string.split( opt[1], ';' ):
122 (l,r) = string.split( o, '=' )
123 exec "%s='%s'" % (l,r)
124 if opt[0] == '-q': quiet = True
125 if opt[0] == '-L': restore = True; state_file = opt[1]
126 if opt[0] == '-F': config_from_file = True; domain_config = opt[1]
129 except getopt.GetoptError:
130 bail=True
132 if not config_from_file:
133 try:
134 os.stat( config_file )
135 except:
136 try:
137 d = config_dir + config_file
138 os.stat( d )
139 config_file = d
140 except:
141 print >> sys.stderr, "Unable to open config file '%s'" % config_file
142 bail = True
145 ##### Parse the config file
146 #####
148 if not config_from_file:
149 if not quiet:
150 print "Parsing config file '%s'" % config_file
152 try:
153 execfile ( config_file )
154 except (AssertionError,IOError):
155 print >>sys.stderr,"Exiting %s" % sys.argv[0]
156 bail = True
158 ##### Print out config if necessary
159 #####
161 def bailout():
162 global extrahelp
163 main_usage()
164 config_usage()
165 if extrahelp: extra_usage()
166 sys.exit(1)
168 if bail:
169 bailout()
171 ##### Parse any command line overrides
172 #####
174 x_vbd_list = []
175 x_vfr_ipaddr = []
177 for opt in opts:
178 if opt[0] == '-k': image = opt[1]
179 if opt[0] == '-r': ramdisk = opt[1]
180 if opt[0] == '-b': builder_fn = opt[1]
181 if opt[0] == '-m': mem_size = int(opt[1])
182 if opt[0] == '-C': cpu = int(opt[1])
183 if opt[0] == '-N': domain_name = opt[1]
184 if opt[0] == '-a': auto_restart = answer(opt[1])
185 if opt[0] == '-e': vbd_expert = opt[1]
186 if opt[0] == '-I': cmdline_ip = opt[1]
187 if opt[0] == '-R': cmdline_root = opt[1]
188 if opt[0] == '-E': cmdline_extra = opt[1]
189 if opt[0] == '-i': x_vfr_ipaddr.append(opt[1])
190 if opt[0] == '-c': auto_console = True
191 if opt[0] == '-d':
192 try:
193 vv = string.split(opt[1],';')
194 for v in vv:
195 (udisk,dev,mode) = string.split(v,',')
196 x_vbd_list.append( (udisk,dev,mode) )
197 except:
198 print >>sys.stderr, "Invalid block device specification : %s" % opt[1]
199 sys.exit(1)
201 if x_vbd_list: vbd_list = x_vbd_list
202 if x_vfr_ipaddr: vfr_ipaddr = x_vfr_ipaddr
204 syslog.openlog('xc_dom_create.py %s' % config_file, 0, syslog.LOG_DAEMON)
206 def strip(pre, s):
207 if s.startswith(pre):
208 return s[len(pre):]
209 else:
210 return s
212 def make_domain_config():
213 global builder_fn, image, ramdisk, mem_size, domain_name
214 global cpu
215 global cmdline, cmdline_ip, cmdline_root
216 global vfr_ipaddr, vbd_list, vbd_expert
218 config = ['config',
219 ['name', domain_name ],
220 ['memory', mem_size ],
221 ]
222 if cpu:
223 config.append(['cpu', cpu])
225 config_image = [ builder_fn ]
226 config_image.append([ 'kernel', os.path.abspath(image) ])
227 if ramdisk:
228 config_image.append([ 'ramdisk', os.path.abspath(ramdisk) ])
229 if cmdline_ip:
230 cmdline_ip = strip("ip=", cmdline_ip)
231 config_image.append(['ip', cmdline_ip])
232 if cmdline_root:
233 cmdline_root = strip("root=", cmdline_root)
234 config_image.append(['root', cmdline_root])
235 if cmdline_extra:
236 config_image.append(['args', cmdline_extra])
237 config.append(['image', config_image ])
239 config_devs = []
240 for (uname, dev, mode) in vbd_list:
241 config_vbd = ['vbd',
242 ['uname', uname],
243 ['dev', dev ],
244 ['mode', mode ] ]
245 if vbd_expert != 'rr':
246 config_vbd.append(['sharing', vbd_expert])
247 config_devs.append(['device', config_vbd])
249 for (bus, dev, func) in pci_device_list:
250 config_pci = ['pci',
251 ['bus', bus ],
252 ['dev', dev ],
253 ['func', func] ]
254 config_devs.append(['device', config_pci])
256 # Add one vif with unspecified MAC.
257 config_devs.append(['device', ['vif']])
259 config += config_devs
261 config_vfr = ['vfr']
262 idx = 0 # No way of saying which IP is for which vif?
263 for ip in vfr_ipaddr:
264 config_vfr.append(['vif', ['id', idx], ['ip', ip]])
266 config.append(config_vfr)
267 return config
269 def parse_config_file(domain_file):
270 config = None
271 fin = None
272 try:
273 fin = file(domain_file, "rb")
274 config = sxp.parse(fin)
275 if len(config) >= 1:
276 config = config[0]
277 else:
278 raise StandardError("Invalid configuration")
279 except StandardError, ex:
280 print >> sys.stderr, "Error :", ex
281 sys.exit(1)
282 #finally:
283 if fin: fin.close()
284 return config
286 # This function creates, builds and starts a domain, using the values
287 # in the global variables, set above. It is used in the subsequent
288 # code for starting the new domain and rebooting it if appropriate.
289 def make_domain(config):
290 """Create, build and start a domain.
291 Returns: [int] the ID of the new domain.
292 """
293 global restore
295 if restore:
296 dominfo = server.xend_domain_restore(state_file, config)
297 else:
298 dominfo = server.xend_domain_create(config)
300 dom = int(sxp.child_value(dominfo, 'id'))
301 console_info = sxp.child(dominfo, 'console')
302 if console_info:
303 console_port = int(sxp.child_value(console_info, 'port'))
304 else:
305 console_port = None
307 if server.xend_domain_start(dom) < 0:
308 print "Error starting domain"
309 server.xend_domain_halt(dom)
310 sys.exit()
312 return (dom, console_port)
314 PID_DIR = '/var/run/xendomains/'
316 def pidfile(dom):
317 return PID_DIR + '%d.pid' % dom
319 def mkpidfile():
320 global current_id
321 if not os.path.isdir(PID_DIR):
322 os.mkdir(PID_DIR)
324 fd = open(pidfile(current_id), 'w')
325 print >> fd, str(os.getpid())
326 fd.close()
327 return
329 def rmpidfile():
330 global current_id
331 os.unlink(pidfile(current_id))
333 def death_handler(dummy1,dummy2):
334 global current_id
335 os.unlink(pidfile(current_id))
336 output('Auto-restart daemon: daemon PID = %d for domain %d is now exiting'
337 % (os.getpid(), current_id))
338 sys.exit(0)
339 return
341 #============================================================================
342 # The starting / monitoring of the domain actually happens here...
344 if config_from_file:
345 config = parse_config_file(domain_config)
346 else:
347 config = make_domain_config()
349 if dryrun:
350 print "# %s" % ' '.join(sys.argv)
351 PrettyPrint.prettyprint(config)
352 sys.exit(0)
353 elif quiet:
354 pass
355 else:
356 PrettyPrint.prettyprint(config)
358 # start the domain and record its ID number
359 (current_id, current_port) = make_domain(config)
361 def start_msg(prefix, dom, port):
362 output(prefix + "VM started in domain %d" % dom)
363 if port:
364 output(prefix + "Console I/O available on TCP port %d." % port)
366 start_msg('', current_id, current_port)
368 if current_port and auto_console:
369 xenctl.console_client.connect('127.0.0.1', current_port)
371 # if the auto_restart flag is set then keep polling to see if the domain is
372 # alive - restart if it is not by calling make_domain() again (it's necessary
373 # to update the id variable, since the new domain may have a new ID)
375 #todo: Replace this - get xend to watch them.
376 if auto_restart:
377 ARD = "Auto-restart daemon: "
378 # turn ourselves into a background daemon
379 try:
380 pid = os.fork()
381 if pid > 0:
382 sys.exit(0)
383 os.setsid()
384 pid = os.fork()
385 if pid > 0:
386 output(ARD + 'PID = %d' % pid)
387 sys.exit(0)
388 signal.signal(signal.SIGTERM,death_handler)
389 except OSError:
390 print >> sys.stderr, ARD+'Startup failed'
391 sys.exit(1)
393 mkpidfile()
395 while True:
396 time.sleep(1)
397 # todo: use new interface
398 info = xc.domain_getinfo(current_id, 1)
399 if info == [] or info[0]['dom'] != current_id:
400 output(ARD + "Domain %d terminated, restarting VM in new domain"
401 % current_id)
402 rmpidfile()
403 (current_id, current_port) = make_domain()
404 mkpidfile()
405 start_msg(ARD, current_id, current_port)