ia64/xen-unstable

view tools/examples/xc_dom_create.py @ 1372:5a6113c65ead

bitkeeper revision 1.891.1.12 (40a248b0WTGoOa9206iWkyGN0mTPNw)

Allow forcing of IRQ trigger-type to edge or level
(NB. DANGEROUS!).
author kaf24@scramble.cl.cam.ac.uk
date Wed May 12 15:54:24 2004 +0000 (2004-05-12)
parents 00059c1948cf
children 0fab6364d23b
line source
1 #!/usr/bin/env python
3 import string, sys, os, time, socket, getopt, signal, syslog
4 import Xc, xenctl.utils, xenctl.console_client, re
6 config_dir = '/etc/xc/'
7 config_file = xc_config_file = config_dir + 'defaults'
9 def main_usage ():
10 print >>sys.stderr,"""
11 Usage: %s <args>
13 This tool is used to create and start new domains. It reads defaults
14 from a file written in Python, having allowed variables to be set and
15 passed into the file. Further command line arguments allow the
16 defaults to be overridden. The defaults for each parameter are listed
17 in [] brackets. Arguments are as follows:
19 Arguments to control the parsing of the defaults file:
20 -f config_file -- Use the specified defaults script.
21 Default: ['%s']
22 -L state_file -- Load virtual machine memory state from state_file
23 -D foo=bar -- Set variable foo=bar before parsing config
24 E.g. '-D vmid=3;ip=1.2.3.4'
25 -h -- Print extended help message, including all arguments
26 -n -- Dry run only, don't actually create domain
27 -q -- Quiet - write output only to the system log
28 """ % (sys.argv[0], xc_config_file)
30 def extra_usage ():
31 print >>sys.stderr,"""
32 Arguments to override current config read from '%s':
33 -c -- Turn into console terminal after domain is created
34 -k image -- Path to kernel image ['%s']
35 -r ramdisk -- Path to ramdisk (or empty) ['%s']
36 -b builder_fn -- Function to use to build domain ['%s']
37 -m mem_size -- Initial memory allocation in MB [%dMB]
38 -N domain_name -- Set textual name of domain ['%s']
39 -a auto_restart -- Restart domain on exit, yes/no ['%d']
40 -e vbd_expert -- Saftey catch to avoid some disk accidents ['%d']
41 -d udisk,dev,rw -- Add disk, partition, or virtual disk to domain. E.g. to
42 make partion sda4 available to the domain as hda1 with
43 read-write access: '-d phy:sda4,hda1,rw' To add
44 multiple disks use multiple -d flags or seperate with ';'
45 Default: ['%s']
46 -i vfr_ipaddr -- Add IP address to the list which Xen will route to
47 the domain. Use multiple times to add more IP addrs.
48 Default: ['%s']
50 Args to override the kernel command line, which is concatenated from these:
51 -I cmdline_ip -- Override 'ip=ipaddr:nfsserv:gateway:netmask::eth0:off'
52 Default: ['%s']
53 -R cmdline_root -- Override root device parameters.
54 Default: ['%s']
55 -E cmdline_extra -- Override extra kernel args and rc script env vars.
56 Default: ['%s']
58 """ % (config_file,
59 image, ramdisk, builder_fn, mem_size, domain_name, auto_restart,
60 vbd_expert,
61 printvbds( vbd_list ),
62 reduce ( (lambda a,b: a+':'+b), vfr_ipaddr,'' )[1:],
63 cmdline_ip, cmdline_root, cmdline_extra)
65 def config_usage (): pass
67 def answer ( s ):
68 s = string.lower(s)
69 if s == 'yes' or s == 'true' or s == '1': return 1
70 return 0
72 def printvbds ( v ):
73 s=''
74 for (a,b,c) in v:
75 s = s + '; %s,%s,%s' % (a,b,c)
76 return s[2:]
78 def output(string):
79 global quiet
80 syslog.syslog(string)
81 if not quiet:
82 print string
83 return
85 bail=False; dryrun=False; extrahelp=False; quiet = False
86 image=''; ramdisk=''; builder_fn=''; restore=0; state_file=''
87 mem_size=0; domain_name=''; vfr_ipaddr=[];
88 vbd_expert=0; auto_restart=False;
89 vbd_list = []; cmdline_ip = ''; cmdline_root=''; cmdline_extra=''
90 pci_device_list = []; console_port = -1
91 auto_console = False
93 ##### Determine location of defaults file
94 #####
96 try:
97 opts, args = getopt.getopt(sys.argv[1:], "h?nqcf:D:k:r:b:m:N:a:e:d:i:I:R:E:L:" )
99 for opt in opts:
100 if opt[0] == '-f': config_file= opt[1]
101 if opt[0] == '-h' or opt[0] == '-?' : bail=True; extrahelp=True
102 if opt[0] == '-n': dryrun=True
103 if opt[0] == '-D':
104 for o in string.split( opt[1], ';' ):
105 (l,r) = string.split( o, '=' )
106 exec "%s='%s'" % (l,r)
107 if opt[0] == '-q': quiet = True
108 if opt[0] == '-L': restore = True; state_file = opt[1]
111 except getopt.GetoptError:
112 bail=True
115 try:
116 os.stat( config_file )
117 except:
118 try:
119 d = config_dir + config_file
120 os.stat( d )
121 config_file = d
122 except:
123 print >> sys.stderr, "Unable to open config file '%s'" % config_file
124 bail = True
127 ##### Parse the config file
128 #####
130 if not quiet:
131 print "Parsing config file '%s'" % config_file
133 try:
134 execfile ( config_file )
135 except (AssertionError,IOError):
136 print >>sys.stderr,"Exiting %s" % sys.argv[0]
137 bail = True
139 ##### Print out config if necessary
140 #####
142 if bail:
143 main_usage()
144 config_usage()
145 if extrahelp: extra_usage()
146 sys.exit(1)
148 ##### Parse any command line overrides
149 #####
151 x_vbd_list = []
152 x_vfr_ipaddr = []
154 for opt in opts:
155 if opt[0] == '-k': image = opt[1]
156 if opt[0] == '-r': ramdisk = opt[1]
157 if opt[0] == '-b': builder_fn = opt[1]
158 if opt[0] == '-m': mem_size = int(opt[1])
159 if opt[0] == '-C': cpu = int(opt[1])
160 if opt[0] == '-N': domain_name = opt[1]
161 if opt[0] == '-a': auto_restart = answer(opt[1])
162 if opt[0] == '-e': vbd_expert = answer(opt[1])
163 if opt[0] == '-I': cmdline_ip = opt[1]
164 if opt[0] == '-R': cmdline_root = opt[1]
165 if opt[0] == '-E': cmdline_extra = opt[1]
166 if opt[0] == '-i': x_vfr_ipaddr.append(opt[1])
167 if opt[0] == '-c': auto_console = True
168 if opt[0] == '-d':
169 try:
170 vv = string.split(opt[1],';')
171 for v in vv:
172 (udisk,dev,mode) = string.split(v,',')
173 x_vbd_list.append( (udisk,dev,mode) )
174 except:
175 print >>sys.stderr, "Invalid block device specification : %s" % opt[1]
176 sys.exit(1)
178 if x_vbd_list: vbd_list = x_vbd_list
179 if x_vfr_ipaddr: vfr_ipaddr = x_vfr_ipaddr
181 cmdline = cmdline_ip +' '+ cmdline_root +' '+ cmdline_extra
183 syslog.openlog('xc_dom_create.py %s' % config_file, 0, syslog.LOG_DAEMON)
185 ##### Print some debug info just in case things don't work out...
186 #####
188 output('VM image : "%s"' % image)
189 output('VM ramdisk : "%s"' % ramdisk)
190 output('VM memory (MB) : "%d"' % mem_size)
191 output('VM IP address(es) : "%s"'
192 % reduce((lambda a,b: a+'; '+b),vfr_ipaddr,'' )[2:])
193 output('VM block device(s) : "%s"' % printvbds( vbd_list ))
194 output('VM cmdline : "%s"' % cmdline)
196 if dryrun:
197 sys.exit(1)
199 ##### HACK HACK HACK
200 ##### Until everyone moves to the new I/O world, and a more robust domain
201 ##### controller (xend), we use this little trick to discover whether we
202 ##### are in a testing environment for new I/O stuff.
203 new_io_world = True
204 for line in os.popen('cat /proc/interrupts').readlines():
205 if re.search('blkdev', line):
206 new_io_world = False
208 ##### Code beyond this point is actually used to manage the mechanics of
209 ##### starting (and watching if necessary) guest virtual machines.
211 # Obtain an instance of the Xen control interface
212 xc = Xc.new()
214 # This function creates, builds and starts a domain, using the values
215 # in the global variables, set above. It is used in the subsequent
216 # code for starting the new domain and rebooting it if appropriate.
217 def make_domain():
218 """Create, build and start a domain.
219 Returns: [int] the ID of the new domain.
220 """
222 # set up access to the global variables declared above
223 global image, ramdisk, mem_size, cpu, domain_name, vfr_ipaddr, netmask
224 global vbd_list, cmdline, xc, vbd_expert, builder_fn
226 if not os.path.isfile( image ):
227 print "Image file '" + image + "' does not exist"
228 sys.exit()
230 if ramdisk and not os.path.isfile( ramdisk ):
231 print "Ramdisk file '" + ramdisk + "' does not exist"
232 sys.exit()
234 id = xc.domain_create( mem_kb=mem_size*1024, name=domain_name, cpu=cpu )
235 if id <= 0:
236 print "Error creating domain"
237 sys.exit()
239 cmsg = 'new_control_interface(dom='+str(id)+', console_port='+str(console_port)+')'
241 cons_response = xenctl.utils.xend_control_message(cmsg)
243 if not cons_response['success']:
244 print "Error creating initial event channel"
245 print "Error type: " + cons_response['error_type']
246 if cons_response['error_type'] == 'exception':
247 print "Exception type: " + cons_response['exception_type']
248 print "Exception value: " + cons_response['exception_value']
249 xc.domain_destroy ( dom=id )
250 sys.exit()
252 if restore:
253 ret = eval('xc.%s_restore ( dom=id, state_file=state_file, progress=1)' % (builder_fn) )
254 if ret < 0:
255 print "Error restoring domain"
256 print "Return code = " + str(ret)
257 xc.domain_destroy ( dom=id )
258 sys.exit()
259 else:
261 ret = eval('xc.%s_build ( dom=id, image=image, ramdisk=ramdisk, cmdline=cmdline, control_evtchn=cons_response["remote_port"] )' % builder_fn )
262 if ret < 0:
263 print "Error building Linux guest OS: "
264 print "Return code = " + str(ret)
265 xc.domain_destroy ( dom=id )
266 sys.exit()
268 # setup the virtual block devices
270 # set the expertise level appropriately
271 xenctl.utils.VBD_EXPERT_MODE = vbd_expert
273 if new_io_world:
274 cmsg = 'new_block_interface(dom='+str(id)+')'
275 xend_response = xenctl.utils.xend_control_message(cmsg)
276 if not xend_response['success']:
277 print "Error creating block interface"
278 print "Error type: " + xend_response['error_type']
279 if xend_response['error_type'] == 'exception':
280 print "Exception type: " + xend_response['exception_type']
281 print "Exception val: " + xend_response['exception_value']
282 xc.domain_destroy ( dom=id )
283 sys.exit()
285 for ( uname, virt_name, rw ) in vbd_list:
286 virt_dev = xenctl.utils.blkdev_name_to_number( virt_name )
288 segments = xenctl.utils.lookup_disk_uname( uname )
289 if not segments:
290 print "Error looking up %s\n" % uname
291 xc.domain_destroy ( dom=id )
292 sys.exit()
294 if new_io_world:
295 if len(segments) > 1:
296 print "New I/O world cannot deal with multi-extent vdisks"
297 xc.domain_destroy ( dom=id )
298 sys.exit()
299 seg = segments[0]
300 cmsg = 'new_block_device(dom=' + str(id) + \
301 ',handle=0,vdev=' + str(virt_dev) + \
302 ',pdev=' + str(seg['device']) + \
303 ',start_sect=' + str(seg['start_sector']) + \
304 ',nr_sect=' + str(seg['nr_sectors']) + \
305 ',readonly=' + str(not re.match('w',rw)) + ')'
306 xend_response = xenctl.utils.xend_control_message(cmsg)
307 if not xend_response['success']:
308 print "Error creating virtual block device"
309 print "Error type: " + xend_response['error_type']
310 if xend_response['error_type'] == 'exception':
311 print "Exception type: " + xend_response['exception_type']
312 print "Exception val: " + xend_response['exception_value']
313 xc.domain_destroy ( dom=id )
314 sys.exit()
315 else:
316 # check that setting up this VBD won't violate the sharing
317 # allowed by the current VBD expertise level
318 if xenctl.utils.vd_extents_validate(segments,
319 rw=='w' or rw=='rw') < 0:
320 xc.domain_destroy( dom = id )
321 sys.exit()
323 if xc.vbd_create( dom=id, vbd=virt_dev,
324 writeable= rw=='w' or rw=='rw' ):
325 print "Error creating VBD %d (writeable=%d)\n" % (virt_dev,rw)
326 xc.domain_destroy ( dom=id )
327 sys.exit()
329 if xc.vbd_setextents( dom=id,
330 vbd=virt_dev,
331 extents=segments):
332 print "Error populating VBD vbd=%d\n" % virt_dev
333 xc.domain_destroy ( dom=id )
334 sys.exit()
336 if new_io_world:
337 cmsg = 'new_network_interface(dom='+str(id)+')'
338 xend_response = xenctl.utils.xend_control_message(cmsg)
339 if not xend_response['success']:
340 print "Error creating network interface"
341 print "Error type: " + xend_response['error_type']
342 if xend_response['error_type'] == 'exception':
343 print "Exception type: " + xend_response['exception_type']
344 print "Exception val: " + xend_response['exception_value']
345 xc.domain_destroy ( dom=id )
346 sys.exit()
347 else:
348 # setup virtual firewall rules for all aliases
349 for ip in vfr_ipaddr:
350 xenctl.utils.setup_vfr_rules_for_vif( id, 0, ip )
352 if new_io_world:
353 # check for physical device access
354 for (pci_bus, pci_dev, pci_func) in pci_device_list:
355 if xc.physdev_pci_access_modify(
356 dom=id, bus=pci_bus, dev=pci_dev,
357 func=pci_func, enable=1 ) < 0:
358 print "Non-fatal error enabling PCI device access."
359 else:
360 print "Enabled PCI access (%d:%d:%d)." % \
361 (pci_bus,pci_dev,pci_func)
363 if restore:
364 # send an unsolicited ARP reply for all non link-local IPs
365 gw=xenctl.utils.get_current_ipgw()
366 if gw == '': gw='255.255.255.255'
367 nlb=open('/proc/sys/net/ipv4/ip_nonlocal_bind','r').read()[0]=='1'
368 if not nlb: print >>open('/proc/sys/net/ipv4/ip_nonlocal_bind','w'), '1'
369 for ip in vfr_ipaddr:
370 if not xenctl.utils.check_subnet(ip,'169.254.0.0','255.255.0.0'):
371 print '/usr/sbin/arping -A -b -I eth0 -c 1 -s %s %s' % (ip,gw)
372 os.system('/usr/sbin/arping -A -b -I eth0 -c 1 -s %s %s' % (ip,gw))
373 if not nlb: print >>open('/proc/sys/net/ipv4/ip_nonlocal_bind','w'), '0'
375 if xc.domain_start( dom=id ) < 0:
376 print "Error starting domain"
377 xc.domain_destroy ( dom=id )
378 sys.exit()
380 return (id, cons_response['console_port'])
381 # end of make_domain()
383 def mkpidfile():
384 global current_id
385 if not os.path.isdir('/var/run/xendomains/'):
386 os.mkdir('/var/run/xendomains/')
388 fd = open('/var/run/xendomains/%d.pid' % current_id, 'w')
389 print >> fd, str(os.getpid())
390 fd.close()
391 return
393 def rmpidfile():
394 global current_id
395 os.unlink('/var/run/xendomains/%d.pid' % current_id)
397 def death_handler(dummy1,dummy2):
398 global current_id
399 os.unlink('/var/run/xendomains/%d.pid' % current_id)
400 output('Auto-restart daemon: daemon PID = %d for domain %d is now exiting'
401 % (os.getpid(),current_id))
402 sys.exit(0)
403 return
405 # The starting / monitoring of the domain actually happens here...
407 # start the domain and record its ID number
408 (current_id, current_port) = make_domain()
409 output("VM started in domain %d. Console I/O available on TCP port %d." % (current_id,current_port))
411 if auto_console:
412 xenctl.console_client.connect('127.0.0.1',int(current_port))
414 # if the auto_restart flag is set then keep polling to see if the domain is
415 # alive - restart if it is not by calling make_domain() again (it's necessary
416 # to update the id variable, since the new domain may have a new ID)
418 if auto_restart:
419 # turn ourselves into a background daemon
420 try:
421 pid = os.fork()
422 if pid > 0:
423 sys.exit(0)
424 os.setsid()
425 pid = os.fork()
426 if pid > 0:
427 output('Auto-restart daemon PID = %d' % pid)
428 sys.exit(0)
429 signal.signal(signal.SIGTERM,death_handler)
430 except OSError:
431 print >> sys.stderr, 'Problem starting auto-restart daemon'
432 sys.exit(1)
434 mkpidfile()
436 while True:
437 time.sleep(1)
438 info = xc.domain_getinfo(current_id, 1)
439 if info == [] or info[0]['dom'] != current_id:
440 output("Auto-restart daemon: Domain %d has terminated, restarting VM in new domain"
441 % current_id)
442 rmpidfile()
443 (current_id, current_port) = make_domain()
444 mkpidfile()
445 output("Auto-restart daemon: VM restarted in domain %d. Console on port %d." % (current_id,current_port))