ia64/xen-unstable

view tools/python/xen/xm/main.py @ 7545:f23b897930d1

xm help notes that domid can be used in place of domname.
Signed-off-by: Daniel Stekloff <dsteklof@us.ibm.com>
author kaf24@firebug.cl.cam.ac.uk
date Thu Oct 27 18:22:45 2005 +0100 (2005-10-27)
parents a2cf10b8da5a
children f3ebb4d6baab
line source
1 # (C) Copyright IBM Corp. 2005
2 # Copyright (C) 2004 Mike Wray
3 # Copyright (c) 2005 XenSource Ltd
4 #
5 # Authors:
6 # Sean Dague <sean at dague dot net>
7 # Mike Wray <mike dot wray at hp dot com>
8 #
9 # This library is free software; you can redistribute it and/or
10 # modify it under the terms of version 2.1 of the GNU Lesser General Public
11 # License as published by the Free Software Foundation.
12 #
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 # Lesser General Public License for more details.
17 #
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 """Grand unified management application for Xen.
23 """
24 import os
25 import os.path
26 import sys
27 import commands
28 import re
29 from getopt import getopt
30 import socket
31 import warnings
32 warnings.filterwarnings('ignore', category=FutureWarning)
34 import xen.xend.XendError
35 import xen.xend.XendProtocol
37 from xen.xend import PrettyPrint
38 from xen.xend import sxp
39 from xen.xm.opts import *
41 import console
44 shorthelp = """Usage: xm <subcommand> [args]
45 Control, list, and manipulate Xen guest instances
47 xm common subcommands:
48 console <DomId> attach to console of DomId
49 create <CfgFile> create a domain based on Config File
50 destroy <DomId> terminate a domain immediately
51 help display this message
52 list [DomId, ...] list information about domains
53 mem-max <DomId> <Mem> set the maximum memory reservation for a domain
54 mem-set <DomId> <Mem> adjust the current memory usage for a domain
55 migrate <DomId> <Host> migrate a domain to another machine
56 pause <DomId> pause execution of a domain
57 reboot <DomId> reboot a domain
58 restore <File> create a domain from a saved state file
59 save <DomId> <File> save domain state (and config) to file
60 shutdown <DomId> shutdown a domain
61 top monitor system and domains in real-time
62 unpause <DomId> unpause a paused domain
64 <DomName> can be substituted for <DomId> in xm subcommands.
66 For a complete list of subcommands run 'xm help --long'
67 For more help on xm see the xm(1) man page
68 For more help on xm create, see the xmdomain.cfg(5) man page"""
70 longhelp = """Usage: xm <subcommand> [args]
71 Control, list, and manipulate Xen guest instances
73 xm full list of subcommands:
75 Domain Commands:
76 console <DomId> attach to console of DomId
77 create <ConfigFile> create a domain
78 destroy <DomId> terminate a domain immediately
79 domid <DomName> convert a domain name to a domain id
80 domname <DomId> convert a domain id to a domain name
81 list list information about domains
82 mem-max <DomId> <Mem> set domain maximum memory limit
83 mem-set <DomId> <Mem> set the domain's memory dynamically
84 migrate <DomId> <Host> migrate a domain to another machine
85 pause <DomId> pause execution of a domain
86 reboot [-w|-a] <DomId> reboot a domain
87 restore <File> create a domain from a saved state file
88 save <DomId> <File> save domain state (and config) to file
89 shutdown [-w|-a] <DomId> shutdown a domain
90 sysrq <DomId> <letter> send a sysrq to a domain
91 unpause <DomId> unpause a paused domain
92 set-vcpus <DomId> <VCPUs> enable the specified number of VCPUs in a domain
93 vcpu-list <DomId> list the VCPUs for a domain
94 vcpu-pin <DomId> <VCPU> <CPUs> set which cpus a VCPU can use.
96 Xen Host Commands:
97 dmesg [--clear] read or clear Xen's message buffer
98 info get information about the xen host
99 log print the xend log
100 top monitor system and domains in real-time
102 Scheduler Commands:
103 sched-bvt <options> set BVT scheduler parameters
104 sched-bvt-ctxallow <Allow>
105 Set the BVT scheduler context switch allowance
106 sched-sedf <options> set simple EDF parameters
108 Virtual Device Commands:
109 block-attach <DomId> <BackDev> <FrontDev> <Mode> [BackDomId]
110 Create a new virtual block device
111 block-detach <DomId> <DevId> Destroy a domain's virtual block device,
112 where <DevId> may either be the device ID
113 or the device name as mounted in the guest.
114 block-list <DomId> List virtual block devices for a domain
115 network-limit <DomId> <Vif> <Credit> <Period>
116 Limit the transmission rate of a virtual network interface
117 network-list <DomId> List virtual network interfaces for a domain
119 Vnet commands:
120 vnet-list [-l|--long] list vnets
121 vnet-create <config> create a vnet from a config file
122 vnet-delete <vnetid> delete a vnet
124 <DomName> can be substituted for <DomId> in xm subcommands.
126 For a short list of subcommands run 'xm help'
127 For more help on xm see the xm(1) man page
128 For more help on xm create, see the xmdomain.cfg(5) man page"""
130 ####################################################################
131 #
132 # Utility functions
133 #
134 ####################################################################
136 def arg_check(args,num,name):
137 if len(args) < num:
138 err("'xm %s' requires %s argument(s)!\n" % (name, num))
139 usage(name)
141 def unit(c):
142 if not c.isalpha():
143 return 0
144 base = 1
145 if c == 'G' or c == 'g': base = 1024 * 1024 * 1024
146 elif c == 'M' or c == 'm': base = 1024 * 1024
147 elif c == 'K' or c == 'k': base = 1024
148 else:
149 print 'ignoring unknown unit'
150 return base
152 def int_unit(str, dest):
153 base = unit(str[-1])
154 if not base:
155 return int(str)
157 value = int(str[:-1])
158 dst_base = unit(dest)
159 if dst_base == 0:
160 dst_base = 1
161 if dst_base > base:
162 return value / (dst_base / base)
163 else:
164 return value * (base / dst_base)
166 def err(msg):
167 print >>sys.stderr, "Error:", msg
169 def handle_xend_error(cmd, dom, ex):
170 error = str(ex)
171 if error == "Not found" and dom != None:
172 err("Domain '%s' not found when running 'xm %s'" % (dom, cmd))
173 sys.exit(1)
174 else:
175 err(error)
176 sys.exit(1)
179 #########################################################################
180 #
181 # Main xm functions
182 #
183 #########################################################################
185 def xm_save(args):
186 arg_check(args,2,"save")
188 dom = args[0] # TODO: should check if this exists
189 savefile = os.path.abspath(args[1])
191 if not os.access(os.path.dirname(savefile), os.W_OK):
192 err("xm save: Unable to create file %s" % savefile)
193 sys.exit(1)
195 from xen.xend.XendClient import server
196 server.xend_domain_save(dom, savefile)
198 def xm_restore(args):
199 arg_check(args,1,"restore")
201 savefile = os.path.abspath(args[0])
203 if not os.access(savefile, os.R_OK):
204 err("xm restore: Unable to read file %s" % savefile)
205 sys.exit(1)
207 from xen.xend.XendClient import server
208 info = server.xend_domain_restore(savefile)
209 PrettyPrint.prettyprint(info)
210 id = sxp.child_value(info, 'domid')
211 if id is not None:
212 server.xend_domain_unpause(domid)
215 def getDomains(domain_names):
216 from xen.xend.XendClient import server
217 if domain_names:
218 return map(server.xend_domain, domain_names)
219 else:
220 return server.xend_list_domains()
223 def xm_list(args):
224 use_long = 0
225 show_vcpus = 0
226 try:
227 (options, params) = getopt(args, 'lv', ['long','vcpus'])
228 except GetoptError, opterr:
229 err(opterr)
230 sys.exit(1)
232 for (k, v) in options:
233 if k in ['-l', '--long']:
234 use_long = 1
235 if k in ['-v', '--vcpus']:
236 show_vcpus = 1
238 if show_vcpus:
239 print >>sys.stderr, (
240 "xm list -v is deprecated. Please use xm vcpu-list.")
241 xm_vcpu_list(params)
242 return
244 doms = getDomains(params)
246 if use_long:
247 map(PrettyPrint.prettyprint, doms)
248 else:
249 xm_brief_list(doms)
252 def parse_doms_info(info):
253 def get_info(n, t, d):
254 return t(sxp.child_value(info, n, d))
256 return {
257 'dom' : get_info('domid', int, -1),
258 'name' : get_info('name', str, '??'),
259 'mem' : get_info('memory', int, 0),
260 'vcpus' : get_info('vcpus', int, 0),
261 'state' : get_info('state', str, '??'),
262 'cpu_time' : get_info('cpu_time', float, 0),
263 'ssidref' : get_info('ssidref', int, 0),
264 }
267 def xm_brief_list(doms):
268 print 'Name ID Mem(MiB) VCPUs State Time(s)'
269 for dom in doms:
270 d = parse_doms_info(dom)
271 if (d['ssidref'] != 0):
272 d['ssidstr'] = (" s:%04x/p:%04x" %
273 ((d['ssidref'] >> 16) & 0xffff,
274 d['ssidref'] & 0xffff))
275 else:
276 d['ssidstr'] = ""
277 print ("%(name)-32s %(dom)3d %(mem)8d %(vcpus)5d %(state)5s %(cpu_time)7.1f%(ssidstr)s" % d)
280 def xm_vcpu_list(args):
281 print 'Name ID VCPU CPU State Time(s) CPU Affinity'
283 from xen.xend.XendClient import server
284 if args:
285 dominfo = map(server.xend_domain_vcpuinfo, args)
286 else:
287 doms = server.xend_list_domains()
288 dominfo = map(
289 lambda x: server.xend_domain_vcpuinfo(sxp.child_value(x, 'name')),
290 doms)
292 for dom in dominfo:
293 def get_info(n):
294 return sxp.child_value(dom, n)
296 #
297 # convert a list of integers into a list of pairs indicating
298 # continuous sequences in the list:
299 #
300 # [0,1,2,3] -> [(0,3)]
301 # [1,2,4,5] -> [(1,2),(4,5)]
302 # [0] -> [(0,0)]
303 # [0,1,4,6,7] -> [(0,1),(4,4),(6,7)]
304 #
305 def list_to_rangepairs(cmap):
306 cmap.sort()
307 pairs = []
308 x = y = 0
309 for i in range(0,len(cmap)):
310 try:
311 if ((cmap[y+1] - cmap[i]) > 1):
312 pairs.append((cmap[x],cmap[y]))
313 x = y = i+1
314 else:
315 y = y + 1
316 # if we go off the end, then just add x to y
317 except IndexError:
318 pairs.append((cmap[x],cmap[y]))
320 return pairs
322 #
323 # Convert pairs to range string, e.g: [(1,2),(3,3),(5,7)] -> 1-2,3,5-7
324 #
325 def format_pairs(pairs):
326 if not pairs:
327 return "no cpus"
328 out = ""
329 for f,s in pairs:
330 if (f==s):
331 out += '%d'%f
332 else:
333 out += '%d-%d'%(f,s)
334 out += ','
335 # trim trailing ','
336 return out[:-1]
338 def format_cpumap(cpumap):
339 cpumap = map(lambda x: int(x), cpumap)
340 cpumap.sort()
342 from xen.xend.XendClient import server
343 for x in server.xend_node()[1:]:
344 if len(x) > 1 and x[0] == 'nr_cpus':
345 nr_cpus = int(x[1])
346 cpumap = filter(lambda x: x < nr_cpus, cpumap)
347 if len(cpumap) == nr_cpus:
348 return "any cpu"
349 break
351 return format_pairs(list_to_rangepairs(cpumap))
353 name = get_info('name')
354 domid = int(get_info('domid'))
356 for vcpu in sxp.children(dom, 'vcpu'):
357 def vinfo(n, t):
358 return t(sxp.child_value(vcpu, n))
360 number = vinfo('number', int)
361 cpu = vinfo('cpu', int)
362 cpumap = format_cpumap(vinfo('cpumap', list))
363 online = vinfo('online', int)
364 cpu_time = vinfo('cpu_time', float)
365 running = vinfo('running', int)
366 blocked = vinfo('blocked', int)
368 if online:
369 c = str(cpu)
370 if running:
371 s = 'r'
372 else:
373 s = '-'
374 if blocked:
375 s += 'b'
376 else:
377 s += '-'
378 s += '-'
379 else:
380 c = "-"
381 s = "--p"
383 print (
384 "%(name)-32s %(domid)3d %(number)4d %(c)3s %(s)-3s %(cpu_time)7.1f %(cpumap)s" %
385 locals())
388 def xm_reboot(args):
389 arg_check(args,1,"reboot")
390 from xen.xm import shutdown
391 # ugly hack because the opt parser apparently wants
392 # the subcommand name just to throw it away!
393 shutdown.main(["bogus", "-R"] + args)
395 def xm_pause(args):
396 arg_check(args, 1, "pause")
397 dom = args[0]
399 from xen.xend.XendClient import server
400 server.xend_domain_pause(dom)
402 def xm_unpause(args):
403 arg_check(args, 1, "unpause")
404 dom = args[0]
406 from xen.xend.XendClient import server
407 server.xend_domain_unpause(dom)
409 def xm_subcommand(command, args):
410 cmd = __import__(command, globals(), locals(), 'xen.xm')
411 cmd.main(["bogus"] + args)
414 #############################################################
416 def cpu_make_map(cpulist):
417 cpus = []
418 for c in cpulist.split(','):
419 if c.find('-') != -1:
420 (x,y) = c.split('-')
421 for i in range(int(x),int(y)+1):
422 cpus.append(int(i))
423 else:
424 cpus.append(int(c))
425 cpus.sort()
426 return cpus
428 def xm_vcpu_pin(args):
429 arg_check(args, 3, "vcpu-pin")
431 dom = args[0]
432 vcpu = int(args[1])
433 cpumap = cpu_make_map(args[2])
435 from xen.xend.XendClient import server
436 server.xend_domain_pincpu(dom, vcpu, cpumap)
438 def xm_mem_max(args):
439 arg_check(args, 2, "mem-max")
441 dom = args[0]
442 mem = int_unit(args[1], 'm')
444 from xen.xend.XendClient import server
445 server.xend_domain_maxmem_set(dom, mem)
447 def xm_mem_set(args):
448 arg_check(args, 2, "mem-set")
450 dom = args[0]
451 mem_target = int_unit(args[1], 'm')
453 from xen.xend.XendClient import server
454 server.xend_domain_mem_target_set(dom, mem_target)
456 def xm_set_vcpus(args):
457 from xen.xend.XendClient import server
458 server.xend_domain_set_vcpus(args[0], int(args[1]))
460 def xm_domid(args):
461 name = args[0]
463 from xen.xend.XendClient import server
464 dom = server.xend_domain(name)
465 print sxp.child_value(dom, 'domid')
467 def xm_domname(args):
468 name = args[0]
470 from xen.xend.XendClient import server
471 dom = server.xend_domain(name)
472 print sxp.child_value(dom, 'name')
474 def xm_sched_bvt(args):
475 arg_check(args, 6, "sched-bvt")
476 dom = args[0]
477 v = map(long, args[1:6])
478 from xen.xend.XendClient import server
479 server.xend_domain_cpu_bvt_set(dom, *v)
481 def xm_sched_bvt_ctxallow(args):
482 arg_check(args, 1, "sched-bvt-ctxallow")
484 slice = int(args[0])
485 from xen.xend.XendClient import server
486 server.xend_node_cpu_bvt_slice_set(slice)
488 def xm_sched_sedf(args):
489 arg_check(args, 6, "sched-sedf")
491 dom = args[0]
492 v = map(int, args[1:6])
493 from xen.xend.XendClient import server
494 server.xend_domain_cpu_sedf_set(dom, *v)
496 def xm_info(args):
497 from xen.xend.XendClient import server
498 info = server.xend_node()
500 for x in info[1:]:
501 if len(x) < 2:
502 print "%-23s: (none)" % x[0]
503 else:
504 print "%-23s:" % x[0], x[1]
506 # TODO: remove as soon as console server shows up
507 def xm_console(args):
508 arg_check(args,1,"console")
510 dom = args[0]
511 from xen.xend.XendClient import server
512 info = server.xend_domain(dom)
513 domid = int(sxp.child_value(info, 'domid', '-1'))
514 console.execConsole(domid)
517 def xm_top(args):
518 os.execvp('xentop', ['xentop'])
520 def xm_dmesg(args):
522 gopts = Opts(use="""[-c|--clear]
524 Read Xen's message buffer (boot output, warning and error messages) or clear
525 its contents if the [-c|--clear] flag is specified.
526 """)
528 gopts.opt('clear', short='c',
529 fn=set_true, default=0,
530 use="Clear the contents of the Xen message buffer.")
531 # Work around for gopts
532 myargs = args
533 myargs.insert(0, "bogus")
534 gopts.parse(myargs)
535 if not (1 <= len(myargs) <= 2):
536 err('Invalid arguments: ' + str(myargs))
538 from xen.xend.XendClient import server
539 if not gopts.vals.clear:
540 print server.xend_node_get_dmesg()
541 else:
542 server.xend_node_clear_dmesg()
544 def xm_log(args):
545 from xen.xend.XendClient import server
546 print server.xend_node_log()
548 def xm_network_limit(args):
549 arg_check(args,4,"network-limit")
550 dom = args[0]
551 v = map(int, args[1:4])
552 from xen.xend.XendClient import server
553 server.xend_domain_vif_limit(dom, *v)
555 def xm_network_list(args):
556 arg_check(args,1,"network-list")
557 dom = args[0]
558 from xen.xend.XendClient import server
559 for x in server.xend_domain_devices(dom, 'vif'):
560 sxp.show(x)
561 print
563 def xm_block_list(args):
564 arg_check(args,1,"block-list")
565 dom = args[0]
566 from xen.xend.XendClient import server
567 for x in server.xend_domain_devices(dom, 'vbd'):
568 sxp.show(x)
569 print
571 def xm_block_attach(args):
572 n = len(args)
573 if n == 0:
574 usage("block-attach")
576 if n < 4 or n > 5:
577 err("%s: Invalid argument(s)" % args[0])
578 usage("block-attach")
580 dom = args[0]
581 vbd = ['vbd',
582 ['uname', args[1]],
583 ['dev', args[2]],
584 ['mode', args[3]]]
585 if n == 5:
586 vbd.append(['backend', args[4]])
588 from xen.xend.XendClient import server
589 server.xend_domain_device_create(dom, vbd)
591 def xm_block_detach(args):
592 arg_check(args,2,"block-detach")
594 dom = args[0]
595 dev = args[1]
597 from xen.xend.XendClient import server
598 server.xend_domain_device_destroy(dom, 'vbd', dev)
600 def xm_vnet_list(args):
601 from xen.xend.XendClient import server
602 try:
603 (options, params) = getopt(args, 'l', ['long'])
604 except GetoptError, opterr:
605 err(opterr)
606 sys.exit(1)
608 use_long = 0
609 for (k, v) in options:
610 if k in ['-l', '--long']:
611 use_long = 1
613 if params:
614 use_long = 1
615 vnets = params
616 else:
617 vnets = server.xend_vnets()
619 for vnet in vnets:
620 try:
621 if use_long:
622 info = server.xend_vnet(vnet)
623 PrettyPrint.prettyprint(info)
624 else:
625 print vnet
626 except Exception, ex:
627 print vnet, ex
629 def xm_vnet_create(args):
630 arg_check(args, 1, "vnet-create")
631 conf = args[0]
632 from xen.xend.XendClient import server
633 server.xend_vnet_create(conf)
635 def xm_vnet_delete(args):
636 arg_check(args, 1, "vnet-delete")
637 vnet = args[0]
638 from xen.xend.XendClient import server
639 server.xend_vnet_delete(vnet)
641 commands = {
642 # console commands
643 "console": xm_console,
644 # xenstat commands
645 "top": xm_top,
646 # domain commands
647 "domid": xm_domid,
648 "domname": xm_domname,
649 "restore": xm_restore,
650 "save": xm_save,
651 "reboot": xm_reboot,
652 "list": xm_list,
653 # memory commands
654 "mem-max": xm_mem_max,
655 "mem-set": xm_mem_set,
656 # cpu commands
657 "vcpu-pin": xm_vcpu_pin,
658 "set-vcpus": xm_set_vcpus,
659 "vcpu-list": xm_vcpu_list,
660 # special
661 "pause": xm_pause,
662 "unpause": xm_unpause,
663 # host commands
664 "dmesg": xm_dmesg,
665 "info": xm_info,
666 "log": xm_log,
667 # scheduler
668 "sched-bvt": xm_sched_bvt,
669 "sched-bvt-ctxallow": xm_sched_bvt_ctxallow,
670 "sched-sedf": xm_sched_sedf,
671 # block
672 "block-attach": xm_block_attach,
673 "block-detach": xm_block_detach,
674 "block-list": xm_block_list,
675 # network
676 "network-limit": xm_network_limit,
677 "network-list": xm_network_list,
678 # vnet
679 "vnet-list": xm_vnet_list,
680 "vnet-create": xm_vnet_create,
681 "vnet-delete": xm_vnet_delete,
682 }
684 ## The commands supported by a separate argument parser in xend.xm.
685 subcommands = [
686 'create',
687 'destroy',
688 'migrate',
689 'sysrq',
690 'shutdown'
691 ]
693 for c in subcommands:
694 commands[c] = eval('lambda args: xm_subcommand("%s", args)' % c)
696 aliases = {
697 "balloon": "mem-set",
698 "vif-list": "network-list",
699 "vif-limit": "network-limit",
700 "vbd-create": "block-create",
701 "vbd-destroy": "block-destroy",
702 "vbd-list": "block-list",
703 }
705 help = {
706 "--long": longhelp
707 }
710 def xm_lookup_cmd(cmd):
711 if commands.has_key(cmd):
712 return commands[cmd]
713 elif aliases.has_key(cmd):
714 deprecated(cmd,aliases[cmd])
715 return commands[aliases[cmd]]
716 else:
717 if len( cmd ) > 1:
718 matched_commands = filter( lambda (command, func): command[ 0:len(cmd) ] == cmd, commands.iteritems() )
719 if len( matched_commands ) == 1:
720 return matched_commands[0][1]
721 err('Sub Command %s not found!' % cmd)
722 usage()
724 def deprecated(old,new):
725 err('Option %s is deprecated, and will be removed in future!!!' % old)
726 err('Option %s is the new replacement, see "xm help %s" for more info' % (new, new))
728 def usage(cmd=None):
729 if help.has_key(cmd):
730 print help[cmd]
731 else:
732 print shorthelp
733 sys.exit(1)
735 def main(argv=sys.argv):
736 if len(argv) < 2:
737 usage()
739 if re.compile('-*help').match(argv[1]):
740 if len(argv) > 2:
741 usage(argv[2])
742 else:
743 usage()
744 sys.exit(0)
746 cmd = xm_lookup_cmd(argv[1])
748 # strip off prog name and subcmd
749 args = argv[2:]
750 if cmd:
751 try:
752 rc = cmd(args)
753 if rc:
754 usage()
755 except socket.error, ex:
756 if os.geteuid() != 0:
757 err("Most commands need root access. Please try again as root.")
758 else:
759 err("Error connecting to xend: %s. Is xend running?" % ex[1])
760 sys.exit(1)
761 except IOError:
762 if os.geteuid() != 0:
763 err("Most commands need root access. Please try again as root.")
764 else:
765 err("Error connecting to xend: %s." % ex[1])
766 sys.exit(1)
767 except xen.xend.XendError.XendError, ex:
768 if len(args) > 0:
769 handle_xend_error(argv[1], args[0], ex)
770 else:
771 print "Unexpected error:", sys.exc_info()[0]
772 print
773 print "Please report to xen-devel@lists.xensource.com"
774 raise
775 except xen.xend.XendProtocol.XendError, ex:
776 if len(args) > 0:
777 handle_xend_error(argv[1], args[0], ex)
778 else:
779 print "Unexpected error:", sys.exc_info()[0]
780 print
781 print "Please report to xen-devel@lists.xensource.com"
782 raise
783 except SystemExit:
784 sys.exit(1)
785 except:
786 print "Unexpected error:", sys.exc_info()[0]
787 print
788 print "Please report to xen-devel@lists.xensource.com"
789 raise
791 else:
792 usage()
794 if __name__ == "__main__":
795 main()