ia64/xen-unstable

view tools/python/xen/xm/main.py @ 7386:95ec0b134206

Patch for typo causing multiple output in xm list -l, courtesy of Laura Ramirez
<laura.ramirez@hp.com>.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@leeni.uk.xensource.com
date Thu Oct 13 23:16:03 2005 +0100 (2005-10-13)
parents b938c4965a8f
children bd3268de4145
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 For a complete list of subcommands run 'xm help --long'
65 For more help on xm see the xm(1) man page
66 For more help on xm create, see the xmdomain.cfg(5) man page"""
68 longhelp = """Usage: xm <subcommand> [args]
69 Control, list, and manipulate Xen guest instances
71 xm full list of subcommands:
73 Domain Commands:
74 console <DomId> attach to console of DomId
75 cpus-list <DomId> <VCpu> get the list of cpus for a VCPU
76 create <ConfigFile> create a domain
77 destroy <DomId> terminate a domain immediately
78 domid <DomName> convert a domain name to a domain id
79 domname <DomId> convert a domain id to a domain name
80 list list information about domains
81 mem-max <DomId> <Mem> set domain maximum memory limit
82 mem-set <DomId> <Mem> set the domain's memory dynamically
83 migrate <DomId> <Host> migrate a domain to another machine
84 pause <DomId> pause execution of a domain
85 reboot [-w|-a] <DomId> reboot a domain
86 restore <File> create a domain from a saved state file
87 save <DomId> <File> save domain state (and config) to file
88 shutdown [-w|-a] <DomId> shutdown a domain
89 sysrq <DomId> <letter> send a sysrq to a domain
90 unpause <DomId> unpause a paused domain
91 vcpu-enable <DomId> <VCPU> enable VCPU in a domain
92 vcpu-disable <DomId> <VCPU> disable VCPU in a domain
93 vcpu-list <DomId> get the list of 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 For a short list of subcommands run 'xm help'
125 For more help on xm see the xm(1) man page
126 For more help on xm create, see the xmdomain.cfg(5) man page"""
128 ####################################################################
129 #
130 # Utility functions
131 #
132 ####################################################################
134 def arg_check(args,num,name):
135 if len(args) < num:
136 err("'xm %s' requires %s argument(s)!\n" % (name, num))
137 usage(name)
139 def unit(c):
140 if not c.isalpha():
141 return 0
142 base = 1
143 if c == 'G' or c == 'g': base = 1024 * 1024 * 1024
144 elif c == 'M' or c == 'm': base = 1024 * 1024
145 elif c == 'K' or c == 'k': base = 1024
146 else:
147 print 'ignoring unknown unit'
148 return base
150 def int_unit(str, dest):
151 base = unit(str[-1])
152 if not base:
153 return int(str)
155 value = int(str[:-1])
156 dst_base = unit(dest)
157 if dst_base == 0:
158 dst_base = 1
159 if dst_base > base:
160 return value / (dst_base / base)
161 else:
162 return value * (base / dst_base)
164 def err(msg):
165 print >>sys.stderr, "Error:", msg
167 def handle_xend_error(cmd, dom, ex):
168 error = str(ex)
169 if error == "Not found" and dom != None:
170 err("Domain '%s' not found when running 'xm %s'" % (dom, cmd))
171 sys.exit(1)
172 else:
173 err(error)
174 sys.exit(1)
177 #########################################################################
178 #
179 # Main xm functions
180 #
181 #########################################################################
183 def xm_save(args):
184 arg_check(args,2,"save")
186 dom = args[0] # TODO: should check if this exists
187 savefile = os.path.abspath(args[1])
189 if not os.access(os.path.dirname(savefile), os.W_OK):
190 err("xm save: Unable to create file %s" % savefile)
191 sys.exit(1)
193 from xen.xend.XendClient import server
194 server.xend_domain_save(dom, savefile)
196 def xm_restore(args):
197 arg_check(args,1,"restore")
199 savefile = os.path.abspath(args[0])
201 if not os.access(savefile, os.R_OK):
202 err("xm restore: Unable to read file %s" % savefile)
203 sys.exit(1)
205 from xen.xend.XendClient import server
206 info = server.xend_domain_restore(savefile)
207 PrettyPrint.prettyprint(info)
208 id = sxp.child_value(info, 'domid')
209 if id is not None:
210 server.xend_domain_unpause(domid)
212 def xm_list(args):
213 use_long = 0
214 show_vcpus = 0
215 try:
216 (options, params) = getopt(args, 'lv', ['long','vcpus'])
217 except GetoptError, opterr:
218 err(opterr)
219 sys.exit(1)
221 n = len(params)
222 for (k, v) in options:
223 if k in ['-l', '--long']:
224 use_long = 1
225 if k in ['-v', '--vcpus']:
226 show_vcpus = 1
228 from xen.xend.XendClient import server
229 if n == 0:
230 doms = server.xend_list_domains()
231 else:
232 doms = map(server.xend_domain, params)
234 if use_long:
235 for dom in doms:
236 PrettyPrint.prettyprint(dom)
237 else:
238 domsinfo = map(parse_doms_info, doms)
240 if show_vcpus:
241 xm_show_vcpus(domsinfo)
242 else:
243 xm_brief_list(domsinfo)
245 def parse_doms_info(info):
246 dominfo = {}
247 dominfo['dom'] = int(sxp.child_value(info, 'domid', '-1'))
248 dominfo['name'] = sxp.child_value(info, 'name', '??')
249 dominfo['mem'] = int(sxp.child_value(info, 'memory', '0'))
250 dominfo['cpu'] = str(sxp.child_value(info, 'cpu', '0'))
251 dominfo['vcpus'] = int(sxp.child_value(info, 'vcpus', '0'))
252 # if there is more than 1 cpu, the value doesn't mean much
253 if dominfo['vcpus'] > 1:
254 dominfo['cpu'] = '-'
255 dominfo['state'] = sxp.child_value(info, 'state', '??')
256 dominfo['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
257 # security identifiers
258 if ((int(sxp.child_value(info, 'ssidref', '0'))) != 0):
259 dominfo['ssidref1'] = int(sxp.child_value(info, 'ssidref', '0')) & 0xffff
260 dominfo['ssidref2'] = (int(sxp.child_value(info, 'ssidref', '0')) >> 16) & 0xffff
261 # get out the vcpu information
262 dominfo['vcpulist'] = []
263 vcpu_to_cpu = sxp.child_value(info, 'vcpu_to_cpu', '-1').split('|')
264 cpumap = sxp.child_value(info, 'cpumap', [])
265 mask = ((int(sxp.child_value(info, 'vcpus', '0')))**2) - 1
266 count = 0
267 for cpu in vcpu_to_cpu:
268 vcpuinfo = {}
269 vcpuinfo['name'] = sxp.child_value(info, 'name', '??')
270 vcpuinfo['dom'] = int(sxp.child_value(info, 'domid', '-1'))
271 vcpuinfo['vcpu'] = int(count)
272 vcpuinfo['cpu'] = int(cpu)
273 vcpuinfo['cpumap'] = int(cpumap[count])&mask
274 count = count + 1
275 dominfo['vcpulist'].append(vcpuinfo)
276 return dominfo
278 def xm_brief_list(domsinfo):
279 print 'Name ID Mem(MiB) CPU VCPUs State Time(s)'
280 for dominfo in domsinfo:
281 if dominfo.has_key("ssidref1"):
282 print ("%(name)-16s %(dom)3d %(mem)8d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f s:%(ssidref2)02x/p:%(ssidref1)02x" % dominfo)
283 else:
284 print ("%(name)-16s %(dom)3d %(mem)8d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f" % dominfo)
286 def xm_show_vcpus(domsinfo):
287 print 'Name Id VCPU CPU CPUMAP'
288 for dominfo in domsinfo:
289 for vcpuinfo in dominfo['vcpulist']:
290 print ("%(name)-16s %(dom)3d %(vcpu)4d %(cpu)3d 0x%(cpumap)x" %
291 vcpuinfo)
293 def xm_vcpu_list(args):
294 xm_list(["-v"] + args)
296 def xm_reboot(args):
297 arg_check(args,1,"reboot")
298 from xen.xm import shutdown
299 # ugly hack because the opt parser apparently wants
300 # the subcommand name just to throw it away!
301 shutdown.main(["bogus", "-R"] + args)
303 def xm_pause(args):
304 arg_check(args, 1, "pause")
305 dom = args[0]
307 from xen.xend.XendClient import server
308 server.xend_domain_pause(dom)
310 def xm_unpause(args):
311 arg_check(args, 1, "unpause")
312 dom = args[0]
314 from xen.xend.XendClient import server
315 server.xend_domain_unpause(dom)
317 def xm_subcommand(command, args):
318 cmd = __import__(command, globals(), locals(), 'xen.xm')
319 cmd.main(["bogus"] + args)
322 #############################################################
324 def cpu_make_map(cpulist):
325 cpus = []
326 cpumap = 0
327 for c in cpulist.split(','):
328 if c.find('-') != -1:
329 (x,y) = c.split('-')
330 for i in range(int(x),int(y)+1):
331 cpus.append(int(i))
332 else:
333 cpus.append(int(c))
334 cpus.sort()
335 for c in cpus:
336 cpumap = cpumap | 1<<c
338 return cpumap
340 def xm_vcpu_pin(args):
341 arg_check(args, 3, "vcpu-pin")
343 dom = args[0]
344 vcpu = int(args[1])
345 cpumap = cpu_make_map(args[2])
347 from xen.xend.XendClient import server
348 server.xend_domain_pincpu(dom, vcpu, cpumap)
350 def xm_mem_max(args):
351 arg_check(args, 2, "mem-max")
353 dom = args[0]
354 mem = int_unit(args[1], 'm')
356 from xen.xend.XendClient import server
357 server.xend_domain_maxmem_set(dom, mem)
359 def xm_mem_set(args):
360 arg_check(args, 2, "mem-set")
362 dom = args[0]
363 mem_target = int_unit(args[1], 'm')
365 from xen.xend.XendClient import server
366 server.xend_domain_mem_target_set(dom, mem_target)
368 # TODO: why does this lookup by name? and what if that fails!?
369 def xm_vcpu_enable(args):
370 arg_check(args, 2, "vcpu-enable")
372 name = args[0]
373 vcpu = int(args[1])
375 from xen.xend.XendClient import server
376 dom = server.xend_domain(name)
377 id = sxp.child_value(dom, 'domid')
378 server.xend_domain_vcpu_hotplug(id, vcpu, 1)
380 def xm_vcpu_disable(args):
381 arg_check(args, 2, "vcpu-disable")
383 name = args[0]
384 vcpu = int(args[1])
386 from xen.xend.XendClient import server
387 dom = server.xend_domain(name)
388 id = sxp.child_value(dom, 'domid')
389 server.xend_domain_vcpu_hotplug(id, vcpu, 0)
391 def xm_domid(args):
392 name = args[0]
394 from xen.xend.XendClient import server
395 dom = server.xend_domain(name)
396 print sxp.child_value(dom, 'domid')
398 def xm_domname(args):
399 name = args[0]
401 from xen.xend.XendClient import server
402 dom = server.xend_domain(name)
403 print sxp.child_value(dom, 'name')
405 def xm_sched_bvt(args):
406 arg_check(args, 6, "sched-bvt")
407 dom = args[0]
408 v = map(long, args[1:6])
409 from xen.xend.XendClient import server
410 server.xend_domain_cpu_bvt_set(dom, *v)
412 def xm_sched_bvt_ctxallow(args):
413 arg_check(args, 1, "sched-bvt-ctxallow")
415 slice = int(args[0])
416 from xen.xend.XendClient import server
417 server.xend_node_cpu_bvt_slice_set(slice)
419 def xm_sched_sedf(args):
420 arg_check(args, 6, "sched-sedf")
422 dom = args[0]
423 v = map(int, args[1:6])
424 from xen.xend.XendClient import server
425 server.xend_domain_cpu_sedf_set(dom, *v)
427 def xm_info(args):
428 from xen.xend.XendClient import server
429 info = server.xend_node()
431 for x in info[1:]:
432 if len(x) < 2:
433 print "%-23s: (none)" % x[0]
434 else:
435 print "%-23s:" % x[0], x[1]
437 # TODO: remove as soon as console server shows up
438 def xm_console(args):
439 arg_check(args,1,"console")
441 dom = args[0]
442 from xen.xend.XendClient import server
443 info = server.xend_domain(dom)
444 domid = int(sxp.child_value(info, 'domid', '-1'))
445 console.execConsole(domid)
448 def xm_top(args):
449 os.execvp('xentop', ['xentop'])
451 def xm_dmesg(args):
453 gopts = Opts(use="""[-c|--clear]
455 Read Xen's message buffer (boot output, warning and error messages) or clear
456 its contents if the [-c|--clear] flag is specified.
457 """)
459 gopts.opt('clear', short='c',
460 fn=set_true, default=0,
461 use="Clear the contents of the Xen message buffer.")
462 # Work around for gopts
463 myargs = args
464 myargs.insert(0, "bogus")
465 gopts.parse(myargs)
466 if not (1 <= len(myargs) <= 2):
467 err('Invalid arguments: ' + str(myargs))
469 from xen.xend.XendClient import server
470 if not gopts.vals.clear:
471 print server.xend_node_get_dmesg()
472 else:
473 server.xend_node_clear_dmesg()
475 def xm_log(args):
476 from xen.xend.XendClient import server
477 print server.xend_node_log()
479 def xm_network_limit(args):
480 arg_check(args,4,"network-limit")
481 dom = args[0]
482 v = map(int, args[1:4])
483 from xen.xend.XendClient import server
484 server.xend_domain_vif_limit(dom, *v)
486 def xm_network_list(args):
487 arg_check(args,1,"network-list")
488 dom = args[0]
489 from xen.xend.XendClient import server
490 for x in server.xend_domain_devices(dom, 'vif'):
491 sxp.show(x)
492 print
494 def xm_block_list(args):
495 arg_check(args,1,"block-list")
496 dom = args[0]
497 from xen.xend.XendClient import server
498 for x in server.xend_domain_devices(dom, 'vbd'):
499 sxp.show(x)
500 print
502 def xm_block_attach(args):
503 n = len(args)
504 if n == 0:
505 usage("block-attach")
507 if n < 4 or n > 5:
508 err("%s: Invalid argument(s)" % args[0])
509 usage("block-attach")
511 dom = args[0]
512 vbd = ['vbd',
513 ['uname', args[1]],
514 ['dev', args[2]],
515 ['mode', args[3]]]
516 if n == 5:
517 vbd.append(['backend', args[4]])
519 from xen.xend.XendClient import server
520 server.xend_domain_device_create(dom, vbd)
522 def xm_block_detach(args):
523 arg_check(args,2,"block-detach")
525 dom = args[0]
526 dev = args[1]
528 from xen.xend.XendClient import server
529 server.xend_domain_device_destroy(dom, 'vbd', dev)
531 def xm_vnet_list(args):
532 from xen.xend.XendClient import server
533 try:
534 (options, params) = getopt(args, 'l', ['long'])
535 except GetoptError, opterr:
536 err(opterr)
537 sys.exit(1)
539 use_long = 0
540 for (k, v) in options:
541 if k in ['-l', '--long']:
542 use_long = 1
544 if params:
545 use_long = 1
546 vnets = params
547 else:
548 vnets = server.xend_vnets()
550 for vnet in vnets:
551 try:
552 if use_long:
553 info = server.xend_vnet(vnet)
554 PrettyPrint.prettyprint(info)
555 else:
556 print vnet
557 except Exception, ex:
558 print vnet, ex
560 def xm_vnet_create(args):
561 arg_check(args, 1, "vnet-create")
562 conf = args[0]
563 from xen.xend.XendClient import server
564 server.xend_vnet_create(conf)
566 def xm_vnet_delete(args):
567 arg_check(args, 1, "vnet-delete")
568 vnet = args[0]
569 from xen.xend.XendClient import server
570 server.xend_vnet_delete(vnet)
572 commands = {
573 # console commands
574 "console": xm_console,
575 # xenstat commands
576 "top": xm_top,
577 # domain commands
578 "domid": xm_domid,
579 "domname": xm_domname,
580 "restore": xm_restore,
581 "save": xm_save,
582 "reboot": xm_reboot,
583 "list": xm_list,
584 # memory commands
585 "mem-max": xm_mem_max,
586 "mem-set": xm_mem_set,
587 # cpu commands
588 "vcpu-pin": xm_vcpu_pin,
589 # "cpus-list": xm_cpus_list,
590 "vcpu-enable": xm_vcpu_enable,
591 "vcpu-disable": xm_vcpu_disable,
592 "vcpu-list": xm_vcpu_list,
593 # special
594 "pause": xm_pause,
595 "unpause": xm_unpause,
596 # host commands
597 "dmesg": xm_dmesg,
598 "info": xm_info,
599 "log": xm_log,
600 # scheduler
601 "sched-bvt": xm_sched_bvt,
602 "sched-bvt-ctxallow": xm_sched_bvt_ctxallow,
603 "sched-sedf": xm_sched_sedf,
604 # block
605 "block-attach": xm_block_attach,
606 "block-detach": xm_block_detach,
607 "block-list": xm_block_list,
608 # network
609 "network-limit": xm_network_limit,
610 "network-list": xm_network_list,
611 # vnet
612 "vnet-list": xm_vnet_list,
613 "vnet-create": xm_vnet_create,
614 "vnet-delete": xm_vnet_delete,
615 }
617 ## The commands supported by a separate argument parser in xend.xm.
618 subcommands = [
619 'create',
620 'destroy',
621 'migrate',
622 'sysrq',
623 'shutdown'
624 ]
626 for c in subcommands:
627 commands[c] = eval('lambda args: xm_subcommand("%s", args)' % c)
629 aliases = {
630 "balloon": "mem-set",
631 "vif-list": "network-list",
632 "vif-limit": "network-limit",
633 "vbd-create": "block-create",
634 "vbd-destroy": "block-destroy",
635 "vbd-list": "block-list",
636 }
638 help = {
639 "--long": longhelp
640 }
643 def xm_lookup_cmd(cmd):
644 if commands.has_key(cmd):
645 return commands[cmd]
646 elif aliases.has_key(cmd):
647 deprecated(cmd,aliases[cmd])
648 return commands[aliases[cmd]]
649 else:
650 if len( cmd ) > 1:
651 matched_commands = filter( lambda (command, func): command[ 0:len(cmd) ] == cmd, commands.iteritems() )
652 if len( matched_commands ) == 1:
653 return matched_commands[0][1]
654 err('Sub Command %s not found!' % cmd)
655 usage()
657 def deprecated(old,new):
658 err('Option %s is deprecated, and will be removed in future!!!' % old)
659 err('Option %s is the new replacement, see "xm help %s" for more info' % (new, new))
661 def usage(cmd=None):
662 if help.has_key(cmd):
663 print help[cmd]
664 else:
665 print shorthelp
666 sys.exit(1)
668 def main(argv=sys.argv):
669 if len(argv) < 2:
670 usage()
672 if re.compile('-*help').match(argv[1]):
673 if len(argv) > 2:
674 usage(argv[2])
675 else:
676 usage()
677 sys.exit(0)
679 cmd = xm_lookup_cmd(argv[1])
681 # strip off prog name and subcmd
682 args = argv[2:]
683 if cmd:
684 try:
685 rc = cmd(args)
686 if rc:
687 usage()
688 except socket.error, ex:
689 if os.geteuid() != 0:
690 err("Most commands need root access. Please try again as root.")
691 else:
692 err("Error connecting to xend: %s. Is xend running?" % ex[1])
693 sys.exit(1)
694 except IOError:
695 if os.geteuid() != 0:
696 err("Most commands need root access. Please try again as root.")
697 else:
698 err("Error connecting to xend: %s." % ex[1])
699 sys.exit(1)
700 except xen.xend.XendError.XendError, ex:
701 if len(args) > 0:
702 handle_xend_error(argv[1], args[0], ex)
703 else:
704 print "Unexpected error:", sys.exc_info()[0]
705 print
706 print "Please report to xen-devel@lists.xensource.com"
707 raise
708 except xen.xend.XendProtocol.XendError, ex:
709 if len(args) > 0:
710 handle_xend_error(argv[1], args[0], ex)
711 else:
712 print "Unexpected error:", sys.exc_info()[0]
713 print
714 print "Please report to xen-devel@lists.xensource.com"
715 raise
716 except SystemExit:
717 sys.exit(1)
718 except:
719 print "Unexpected error:", sys.exc_info()[0]
720 print
721 print "Please report to xen-devel@lists.xensource.com"
722 raise
724 else:
725 usage()
727 if __name__ == "__main__":
728 main()