ia64/xen-unstable

view tools/python/xen/xm/main.py @ 6422:e24fd7012ffb

merge?
author cl349@firebug.cl.cam.ac.uk
date Thu Aug 25 10:09:39 2005 +0000 (2005-08-25)
parents 2f20c2fce2c5 fd77dd32c8a4
children 4abd299ef2f6
line source
1 # (C) Copyright IBM Corp. 2005
2 # Copyright (C) 2004 Mike Wray
3 #
4 # Authors:
5 # Sean Dague <sean at dague dot net>
6 # Mike Wray <mike dot wray at hp dot com>
7 #
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of version 2.1 of the GNU Lesser General Public
10 # License as published by the Free Software Foundation.
11 #
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # Lesser General Public License for more details.
16 #
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 """Grand unified management application for Xen.
22 """
23 import os
24 import os.path
25 import sys
26 import commands
27 import re
28 from getopt import getopt
29 import socket
30 import warnings
31 warnings.filterwarnings('ignore', category=FutureWarning)
32 from xen.xend import PrettyPrint
33 from xen.xend import sxp
34 from xen.xm.opts import *
35 shorthelp = """Usage: xm <subcommand> [args]
36 Control, list, and manipulate Xen guest instances
38 xm common subcommands:
39 console <DomId> attach to console of DomId
40 create <CfgFile> create a domain based on Config File
41 destroy <DomId> terminate a domain immediately
42 help display this message
43 list [DomId, ...] list information about domains
44 mem-max <DomId> <Mem> set the maximum memory reservation for a domain
45 mem-set <DomId> <Mem> adjust the current memory usage for a domain
46 migrate <DomId> <Host> migrate a domain to another machine
47 pause <DomId> pause execution of a domain
48 reboot <DomId> reboot a domain
49 restore <File> create a domain from a saved state file
50 save <DomId> <File> save domain state (and config) to file
51 shutdown <DomId> shutdown a domain
52 top monitor system and domains in real-time
53 unpause <DomId> unpause a paused domain
55 For a complete list of subcommands run 'xm help --long'
56 For more help on xm see the xm(1) man page
57 For more help on xm create, see the xmdomain.cfg(5) man page"""
59 longhelp = """Usage: xm <subcommand> [args]
60 Control, list, and manipulate Xen guest instances
62 xm full list of subcommands:
64 Domain Commands:
65 console <DomId> attach to console of DomId
66 cpus-list <DomId> <VCpu> get the list of cpus for a VCPU
67 cpus-set <DomId> <VCpu> <CPUS> set which cpus a VCPU can use.
68 create <ConfigFile> create a domain
69 destroy <DomId> terminate a domain immediately
70 domid <DomName> convert a domain name to a domain id
71 domname <DomId> convert a domain id to a domain name
72 list list information about domains
73 mem-max <DomId> <Mem> set domain maximum memory limit
74 mem-set <DomId> <Mem> set the domain's memory dynamically
75 migrate <DomId> <Host> migrate a domain to another machine
76 pause <DomId> pause execution of a domain
77 reboot [-w|-a] <DomId> reboot a domain
78 restore <File> create a domain from a saved state file
79 save <DomId> <File> save domain state (and config) to file
80 shutdown [-w|-a] <DomId> shutdown a domain
81 sysrq <DomId> <letter> send a sysrq to a domain
82 unpause <DomId> unpause a paused domain
83 vcpu-enable <DomId> <VCPU> disable VCPU in a domain
84 vcpu-disable <DomId> <VCPU> enable VCPU in a domain
85 vcpu-list <DomId> get the list of VCPUs for a domain
87 Xen Host Commands:
88 dmesg [--clear] read or clear Xen's message buffer
89 info get information about the xen host
90 log print the xend log
91 top monitor system and domains in real-time
93 Scheduler Commands:
94 bvt <options> set BVT scheduler parameters
95 bvt_ctxallow <Allow> set the BVT scheduler context switch allowance
96 sedf <options> set simple EDF parameters
98 Virtual Device Commands:
99 block-create <DomId> <BackDev> <FrontDev> <Mode> [BackDomId]
100 Create a new virtual block device
101 block-destroy <DomId> <DevId> Destroy a domain's virtual block device
102 block-list <DomId> List virtual block devices for a domain
103 block-refresh <DomId> <DevId> Refresh a virtual block device for a domain
104 network-limit <DomId> <Vif> <Credit> <Period>
105 Limit the transmission rate of a virtual network interface
106 network-list <DomId> List virtual network interfaces for a domain
108 For a short list of subcommands run 'xm help'
109 For more help on xm see the xm(1) man page
110 For more help on xm create, see the xmdomain.cfg(5) man page"""
112 ####################################################################
113 #
114 # Utility functions
115 #
116 ####################################################################
118 def arg_check(args,num,name):
119 if len(args) < num:
120 err("'xm %s' requires %s argument(s)!\n" % (name, num))
121 usage(name)
123 def unit(c):
124 if not c.isalpha():
125 return 0
126 base = 1
127 if c == 'G' or c == 'g': base = 1024 * 1024 * 1024
128 elif c == 'M' or c == 'm': base = 1024 * 1024
129 elif c == 'K' or c == 'k': base = 1024
130 else:
131 print 'ignoring unknown unit'
132 return base
134 def int_unit(str, dest):
135 base = unit(str[-1])
136 if not base:
137 return int(str)
139 value = int(str[:-1])
140 dst_base = unit(dest)
141 if dst_base == 0:
142 dst_base = 1
143 if dst_base > base:
144 return value / (dst_base / base)
145 else:
146 return value * (base / dst_base)
148 def err(msg):
149 print >>sys.stderr, "Error:", msg
151 def handle_xend_error(cmd, dom, ex):
152 error = str(ex)
153 if error == "Not found" and dom != None:
154 err("Domain '%s' not found when running 'xm %s'" % (dom, cmd))
155 sys.exit(1)
156 else:
157 raise ex
160 #########################################################################
161 #
162 # Main xm functions
163 #
164 #########################################################################
166 def xm_create(args):
167 from xen.xm import create
168 # ugly hack because the opt parser apparently wants
169 # the subcommand name just to throw it away!
170 args.insert(0,"bogus")
171 create.main(args)
173 def xm_save(args):
174 arg_check(args,2,"save")
176 dom = args[0] # TODO: should check if this exists
177 savefile = os.path.abspath(args[1])
179 from xen.xend.XendClient import server
180 server.xend_domain_save(dom, savefile)
182 def xm_restore(args):
183 arg_check(args,1,"restore")
185 savefile = os.path.abspath(args[0])
187 from xen.xend.XendClient import server
188 info = server.xend_domain_restore(savefile)
189 PrettyPrint.prettyprint(info)
190 id = sxp.child_value(info, 'id')
191 if id is not None:
192 server.xend_domain_unpause(id)
194 def xm_migrate(args):
195 # TODO: arg_check
196 from xen.xm import migrate
197 # ugly hack because the opt parser apparently wants
198 # the subcommand name just to throw it away!
199 args.insert(0,"bogus")
200 migrate.main(args)
202 def xm_list(args):
203 use_long = 0
204 show_vcpus = 0
205 try:
206 (options, params) = getopt(args, 'lv', ['long','vcpus'])
207 except GetoptError, opterr:
208 err(opterr)
209 sys.exit(1)
211 n = len(params)
212 for (k, v) in options:
213 if k in ['-l', '--long']:
214 use_long = 1
215 if k in ['-v', '--vcpus']:
216 show_vcpus = 1
218 domsinfo = []
219 from xen.xend.XendClient import server
220 if n == 0:
221 doms = server.xend_domains()
222 doms.sort()
223 else:
224 doms = params
225 for dom in doms:
226 info = server.xend_domain(dom)
227 domsinfo.append(parse_doms_info(info))
229 if use_long:
230 for dom in doms:
231 info = server.xend_domain(dom)
232 PrettyPrint.prettyprint(info)
233 elif show_vcpus:
234 xm_show_vcpus(domsinfo)
235 else:
236 xm_brief_list(domsinfo)
238 def parse_doms_info(info):
239 dominfo = {}
240 dominfo['dom'] = int(sxp.child_value(info, 'id', '-1'))
241 dominfo['name'] = sxp.child_value(info, 'name', '??')
242 dominfo['mem'] = int(sxp.child_value(info, 'memory', '0'))
243 dominfo['cpu'] = str(sxp.child_value(info, 'cpu', '0'))
244 dominfo['vcpus'] = int(sxp.child_value(info, 'vcpus', '0'))
245 # if there is more than 1 cpu, the value doesn't mean much
246 if dominfo['vcpus'] > 1:
247 dominfo['cpu'] = '-'
248 dominfo['state'] = sxp.child_value(info, 'state', '??')
249 dominfo['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
250 # security identifiers
251 if ((int(sxp.child_value(info, 'ssidref', '0'))) != 0):
252 dominfo['ssidref1'] = int(sxp.child_value(info, 'ssidref', '0')) & 0xffff
253 dominfo['ssidref2'] = (int(sxp.child_value(info, 'ssidref', '0')) >> 16) & 0xffff
254 # get out the vcpu information
255 dominfo['vcpulist'] = []
256 vcpu_to_cpu = sxp.child_value(info, 'vcpu_to_cpu', '-1').split('|')
257 cpumap = sxp.child_value(info, 'cpumap', [])
258 mask = ((int(sxp.child_value(info, 'vcpus', '0')))**2) - 1
259 count = 0
260 for cpu in vcpu_to_cpu:
261 vcpuinfo = {}
262 vcpuinfo['name'] = sxp.child_value(info, 'name', '??')
263 vcpuinfo['dom'] = int(sxp.child_value(info, 'id', '-1'))
264 vcpuinfo['vcpu'] = int(count)
265 vcpuinfo['cpu'] = int(cpu)
266 vcpuinfo['cpumap'] = int(cpumap[count])&mask
267 count = count + 1
268 dominfo['vcpulist'].append(vcpuinfo)
269 return dominfo
271 def xm_brief_list(domsinfo):
272 print 'Name Id Mem(MB) CPU VCPU(s) State Time(s)'
273 for dominfo in domsinfo:
274 if dominfo.has_key("ssidref1"):
275 print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f s:%(ssidref2)02x/p:%(ssidref1)02x" % dominfo)
276 else:
277 print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f" % dominfo)
279 def xm_show_vcpus(domsinfo):
280 print 'Name Id VCPU CPU CPUMAP'
281 for dominfo in domsinfo:
282 for vcpuinfo in dominfo['vcpulist']:
283 print ("%(name)-16s %(dom)3d %(vcpu)4d %(cpu)3d 0x%(cpumap)x" %
284 vcpuinfo)
286 def xm_vcpu_list(args):
287 args.insert(0,"-v")
288 xm_list(args)
290 def xm_destroy(args):
291 arg_check(args,1,"destroy")
293 from xen.xm import destroy
294 # ugly hack because the opt parser apparently wants
295 # the subcommand name just to throw it away!
296 args.insert(0,"bogus")
297 destroy.main(args)
299 def xm_reboot(args):
300 arg_check(args,1,"reboot")
301 # ugly hack because the opt parser apparently wants
302 # the subcommand name just to throw it away!
303 args.insert(0,"bogus")
304 args.insert(2,"-R")
305 from xen.xm import shutdown
306 shutdown.main(args)
308 def xm_shutdown(args):
309 arg_check(args,1,"shutdown")
311 # ugly hack because the opt parser apparently wants
312 # the subcommand name just to throw it away!
313 args.insert(0,"bogus")
314 from xen.xm import shutdown
315 shutdown.main(args)
317 def xm_sysrq(args):
318 from xen.xm import sysrq
319 # ugly hack because the opt parser apparently wants
320 # the subcommand name just to throw it away!
321 args.insert(0,"bogus")
322 sysrq.main(args)
324 def xm_pause(args):
325 arg_check(args, 1, "pause")
326 dom = args[0]
328 from xen.xend.XendClient import server
329 server.xend_domain_pause(dom)
331 def xm_unpause(args):
332 arg_check(args, 1, "unpause")
333 dom = args[0]
335 from xen.xend.XendClient import server
336 server.xend_domain_unpause(dom)
338 #############################################################
340 def cpu_make_map(cpulist):
341 cpus = []
342 cpumap = 0
343 for c in cpulist.split(','):
344 if c.find('-') != -1:
345 (x,y) = c.split('-')
346 for i in range(int(x),int(y)+1):
347 cpus.append(int(i))
348 else:
349 cpus.append(int(c))
350 cpus.sort()
351 for c in cpus:
352 cpumap = cpumap | 1<<c
354 return cpumap
356 def xm_cpus_set(args):
357 arg_check(args, 3, "cpus-set")
359 dom = args[0]
360 vcpu = int(args[1])
361 cpumap = cpu_make_map(args[2])
363 from xen.xend.XendClient import server
364 server.xend_domain_pincpu(dom, vcpu, cpumap)
366 def xm_mem_max(args):
367 arg_check(args, 2, "mem-max")
369 dom = args[0]
370 mem = int_unit(args[1], 'm')
372 from xen.xend.XendClient import server
373 server.xend_domain_maxmem_set(dom, mem)
375 def xm_mem_set(args):
376 arg_check(args, 2, "mem-set")
378 dom = args[0]
379 mem_target = int_unit(args[1], 'm')
381 from xen.xend.XendClient import server
382 server.xend_domain_mem_target_set(dom, mem_target)
384 # TODO: why does this lookup by name? and what if that fails!?
385 def xm_vcpu_enable(args):
386 arg_check(args, 2, "vcpu-enable")
388 name = args[0]
389 vcpu = int(args[1])
391 from xen.xend.XendClient import server
392 dom = server.xend_domain(name)
393 id = sxp.child_value(dom, 'id')
394 server.xend_domain_vcpu_hotplug(id, vcpu, 1)
396 def xm_vcpu_disable(args):
397 arg_check(args, 2, "vcpu-disable")
399 name = args[0]
400 vcpu = int(args[1])
402 from xen.xend.XendClient import server
403 dom = server.xend_domain(name)
404 id = sxp.child_value(dom, 'id')
405 server.xend_domain_vcpu_hotplug(id, vcpu, 0)
407 def xm_domid(args):
408 name = args[0]
410 from xen.xend.XendClient import server
411 dom = server.xend_domain(name)
412 print sxp.child_value(dom, 'id')
414 def xm_domname(args):
415 name = args[0]
417 from xen.xend.XendClient import server
418 dom = server.xend_domain(name)
419 print sxp.child_value(dom, 'name')
421 def xm_bvt(args):
422 arg_check(args, 6, "bvt")
423 dom = args[0]
424 v = map(long, args[1:6])
425 from xen.xend.XendClient import server
426 server.xend_domain_cpu_bvt_set(dom, *v)
428 def xm_bvt_ctxallow(args):
429 arg_check(args, 1, "bvt_ctxallow")
431 slice = int(args[0])
432 from xen.xend.XendClient import server
433 server.xend_node_cpu_bvt_slice_set(slice)
435 def xm_sedf(args):
436 arg_check(args, 6, "sedf")
438 dom = args[0]
439 v = map(int, args[1:6])
440 from xen.xend.XendClient import server
441 server.xend_domain_cpu_sedf_set(dom, *v)
443 def xm_info(args):
444 from xen.xend.XendClient import server
445 info = server.xend_node()
447 for x in info[1:]:
448 print "%-23s:" % x[0], x[1]
450 # TODO: remove as soon as console server shows up
451 def xm_console(args):
452 arg_check(args,1,"console")
454 dom = args[0]
455 from xen.xend.XendClient import server
456 info = server.xend_domain(dom)
457 domid = int(sxp.child_value(info, 'id', '-1'))
458 cmd = "/usr/libexec/xen/xenconsole %d" % domid
459 os.execvp('/usr/libexec/xen/xenconsole', cmd.split())
460 console = sxp.child(info, "console")
462 def xm_top(args):
463 os.execv('/usr/sbin/xentop', ['/usr/sbin/xentop'])
465 def xm_dmesg(args):
467 gopts = Opts(use="""[-c|--clear]
469 Read Xen's message buffer (boot output, warning and error messages) or clear
470 its contents if the [-c|--clear] flag is specified.
471 """)
473 gopts.opt('clear', short='c',
474 fn=set_true, default=0,
475 use="Clear the contents of the Xen message buffer.")
476 # Work around for gopts
477 args.insert(0,"bogus")
478 gopts.parse(args)
479 if not (1 <= len(args) <= 2):
480 err('Invalid arguments: ' + str(args))
482 from xen.xend.XendClient import server
483 if not gopts.vals.clear:
484 print server.xend_node_get_dmesg()
485 else:
486 server.xend_node_clear_dmesg()
488 def xm_log(args):
489 from xen.xend.XendClient import server
490 print server.xend_node_log()
492 def xm_network_limit(args):
493 arg_check(args,4,"network-limit")
494 dom = args[0]
495 v = map(int, args[1:4])
496 from xen.xend.XendClient import server
497 server.xend_domain_vif_limit(dom, *v)
499 def xm_network_list(args):
500 arg_check(args,1,"network-list")
501 dom = args[0]
502 from xen.xend.XendClient import server
503 for x in server.xend_domain_devices(dom, 'vif'):
504 sxp.show(x)
505 print
507 def xm_block_list(args):
508 arg_check(args,1,"block-list")
509 dom = args[0]
510 from xen.xend.XendClient import server
511 for x in server.xend_domain_devices(dom, 'vbd'):
512 sxp.show(x)
513 print
515 def xm_block_create(args):
516 n = len(args)
517 if n < 4 or n > 5:
518 err("%s: Invalid argument(s)" % args[0])
519 usage("block-create")
521 dom = args[0]
522 vbd = ['vbd',
523 ['uname', args[1]],
524 ['dev', args[2]],
525 ['mode', args[3]]]
526 if n == 5:
527 vbd.append(['backend', args[4]])
529 from xen.xend.XendClient import server
530 server.xend_domain_device_create(dom, vbd)
532 def xm_block_refresh(args):
533 arg_check(args,2,"block-refresh")
535 dom = args[0]
536 dev = args[1]
538 from xen.xend.XendClient import server
539 server.xend_domain_device_refresh(dom, 'vbd', dev)
541 def xm_block_destroy(args):
542 arg_check(args,2,"block-destroy")
544 dom = args[0]
545 dev = args[1]
547 from xen.xend.XendClient import server
548 server.xend_domain_device_destroy(dom, 'vbd', dev)
550 commands = {
551 # console commands
552 "console": xm_console,
553 # xenstat commands
554 "top": xm_top,
555 # domain commands
556 "domid": xm_domid,
557 "domname": xm_domname,
558 "create": xm_create,
559 "destroy": xm_destroy,
560 "restore": xm_restore,
561 "save": xm_save,
562 "shutdown": xm_shutdown,
563 "reboot": xm_reboot,
564 "list": xm_list,
565 # memory commands
566 "mem-max": xm_mem_max,
567 "mem-set": xm_mem_set,
568 # cpu commands
569 "cpus-set": xm_cpus_set,
570 # "cpus-list": xm_cpus_list,
571 "vcpu-enable": xm_vcpu_enable,
572 "vcpu-disable": xm_vcpu_disable,
573 "vcpu-list": xm_vcpu_list,
574 # migration
575 "migrate": xm_migrate,
576 # special
577 "sysrq": xm_sysrq,
578 "pause": xm_pause,
579 "unpause": xm_unpause,
580 # host commands
581 "dmesg": xm_dmesg,
582 "info": xm_info,
583 "log": xm_log,
584 # scheduler
585 "bvt": xm_bvt,
586 "bvt_ctxallow": xm_bvt_ctxallow,
587 "sedf": xm_sedf,
588 # block
589 "block-create": xm_block_create,
590 "block-destroy": xm_block_destroy,
591 "block-list": xm_block_list,
592 "block-refresh": xm_block_refresh,
593 # network
594 "network-limit": xm_network_limit,
595 "network-list": xm_network_list
596 }
598 aliases = {
599 "balloon": "mem-set",
600 "vif-list": "network-list",
601 "vif-limit": "network-limit",
602 "vbd-create": "block-create",
603 "vbd-destroy": "block-destroy",
604 "vbd-list": "block-list",
605 "vbd-refresh": "block-refresh",
606 }
608 help = {
609 "--long": longhelp
610 }
612 def xm_lookup_cmd(cmd):
613 if commands.has_key(cmd):
614 return commands[cmd]
615 elif aliases.has_key(cmd):
616 deprecated(cmd,aliases[cmd])
617 return commands[aliases[cmd]]
618 else:
619 if len( cmd ) > 1:
620 matched_commands = filter( lambda (command, func): command[ 0:len(cmd) ] == cmd, commands.iteritems() )
621 if len( matched_commands ) == 1:
622 return matched_commands[0][1]
623 err('Sub Command %s not found!' % cmd)
624 usage()
626 def deprecated(old,new):
627 err('Option %s is deprecated, and will be removed in future!!!' % old)
628 err('Option %s is the new replacement, see "xm help %s" for more info' % (new, new))
630 def usage(cmd=None):
631 if cmd == "full":
632 print fullhelp
633 elif help.has_key(cmd):
634 print help[cmd]
635 else:
636 print shorthelp
637 sys.exit(1)
639 def main(argv=sys.argv):
640 if len(argv) < 2:
641 usage()
643 if re.compile('-*help').match(argv[1]):
644 if len(argv) > 2 and help.has_key(argv[2]):
645 usage(argv[2])
646 else:
647 usage()
648 sys.exit(0)
650 cmd = xm_lookup_cmd(argv[1])
652 # strip off prog name and subcmd
653 args = argv[2:]
654 if cmd:
655 try:
656 from xen.xend.XendClient import XendError
657 rc = cmd(args)
658 if rc:
659 usage()
660 except socket.error, ex:
661 print >>sys.stderr, ex
662 err("Error connecting to xend, is xend running?")
663 sys.exit(1)
664 except IOError:
665 err("Most commands need root access. Please try again as root")
666 sys.exit(1)
667 except XendError, ex:
668 if args[0] == "bogus":
669 args.remove("bogus")
670 if len(args) > 0:
671 handle_xend_error(argv[1], args[0], ex)
672 else:
673 print "Unexpected error:", sys.exc_info()[0]
674 print
675 print "Please report to xen-devel@lists.xensource.com"
676 raise
677 except SystemExit:
678 sys.exit(1)
679 except:
680 print "Unexpected error:", sys.exc_info()[0]
681 print
682 print "Please report to xen-devel@lists.xensource.com"
683 raise
685 else:
686 usage()
688 if __name__ == "__main__":
689 main()