ia64/xen-unstable

view tools/python/xen/xm/main.py @ 11588:92bfc59726a4

[XM] Move 'xm sysrq' into main.py

* There's not need for sysrq to be in its own file.
* Bonus advantage: can use arg_check rather than gopts for argument
validation.

Signed-off-by: Alastair Tse <atse@xensource.com>
author atse@norwich.uk.xensource.com
date Fri Sep 22 16:32:30 2006 +0100 (2006-09-22)
parents ad22c711ccb7
children dfbadf4696fd
line source
1 # (C) Copyright IBM Corp. 2005
2 # Copyright (C) 2004 Mike Wray
3 # Copyright (c) 2005-2006 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 sys
26 import re
27 import getopt
28 import socket
29 import traceback
30 import xmlrpclib
31 import traceback
32 import datetime
33 from select import select
35 import warnings
36 warnings.filterwarnings('ignore', category=FutureWarning)
38 from xen.xend import PrettyPrint
39 from xen.xend import sxp
40 from xen.xend import XendClient
41 from xen.xend.XendClient import server
43 from xen.xm.opts import OptionError, Opts, wrap, set_true
44 from xen.xm import console
45 from xen.util import security
47 # getopt.gnu_getopt is better, but only exists in Python 2.3+. Use
48 # getopt.getopt if gnu_getopt is not available. This will mean that options
49 # may only be specified before positional arguments.
50 if not hasattr(getopt, 'gnu_getopt'):
51 getopt.gnu_getopt = getopt.getopt
53 # General help message
55 USAGE_HELP = "Usage: xm <subcommand> [args]\n\n" \
56 "Control, list, and manipulate Xen guest instances.\n"
58 USAGE_FOOTER = '<Domain> can either be the Domain Name or Id.\n' \
59 'For more help on \'xm\' see the xm(1) man page.\n' \
60 'For more help on \'xm create\' see the xmdomain.cfg(5) '\
61 ' man page.\n'
63 # Help strings are indexed by subcommand name in this way:
64 # 'subcommand': (argstring, description)
66 SUBCOMMAND_HELP = {
67 # common commands
69 'console' : ('<Domain>',
70 'Attach to <Domain>\'s console.'),
71 'create' : ('<ConfigFile> [options] [vars]',
72 'Create a domain based on <ConfigFile>.'),
73 'destroy' : ('<Domain>',
74 'Terminate a domain immediately.'),
75 'help' : ('', 'Display this message.'),
76 'list' : ('[options] [Domain, ...]',
77 'List information about all/some domains.'),
78 'mem-max' : ('<Domain> <Mem>',
79 'Set the maximum amount reservation for a domain.'),
80 'mem-set' : ('<Domain> <Mem>',
81 'Set the current memory usage for a domain.'),
82 'migrate' : ('<Domain> <Host>',
83 'Migrate a domain to another machine.'),
84 'pause' : ('<Domain>', 'Pause execution of a domain.'),
85 'reboot' : ('<Domain> [-wa]', 'Reboot a domain.'),
86 'restore' : ('<CheckpointFile>',
87 'Restore a domain from a saved state.'),
88 'save' : ('<Domain> <CheckpointFile>',
89 'Save a domain state to restore later.'),
90 'shutdown' : ('<Domain> [-waRH]', 'Shutdown a domain.'),
91 'top' : ('', 'Monitor a host and the domains in real time.'),
92 'unpause' : ('<Domain>', 'Unpause a paused domain.'),
93 'uptime' : ('[-s] <Domain>', 'Print uptime for a domain.'),
95 # less used commands
97 'dmesg' : ('[-c|--clear]',
98 'Read and/or clear Xend\'s message buffer.'),
99 'domid' : ('<DomainName>', 'Convert a domain name to domain id.'),
100 'domname' : ('<DomId>', 'Convert a domain id to domain name.'),
101 'dump-core' : ('[-L|--live] [-C|--crash] <Domain> [Filename]',
102 'Dump core for a specific domain.'),
103 'info' : ('', 'Get information about Xen host.'),
104 'log' : ('', 'Print Xend log'),
105 'rename' : ('<Domain> <NewDomainName>', 'Rename a domain.'),
106 'sched-sedf' : ('<Domain> [options]', 'Get/set EDF parameters.'),
107 'sched-credit': ('-d <Domain> [-w[=WEIGHT]|-c[=CAP]]',
108 'Get/set credit scheduler parameters.'),
109 'sysrq' : ('<Domain> <letter>', 'Send a sysrq to a domain.'),
110 'vcpu-list' : ('[<Domain>]',
111 'List the VCPUs for a domain or all domains.'),
112 'vcpu-pin' : ('<Domain> <VCPU> <CPUs>',
113 'Set which CPUs a VCPU can use.'),
114 'vcpu-set' : ('<Domain> <vCPUs>',
115 'Set the number of active VCPUs for allowed for the'
116 ' domain.'),
118 # device commands
120 'block-attach' : ('<Domain> <BackDev> <FrontDev> <Mode>',
121 'Create a new virtual block device.'),
122 'block-configure': ('<Domain> <BackDev> <FrontDev> <Mode> [BackDomId]',
123 'Change block device configuration'),
124 'block-detach' : ('<Domain> <DevId>',
125 'Destroy a domain\'s virtual block device.'),
126 'block-list' : ('<Domain> [--long]',
127 'List virtual block devices for a domain.'),
128 'network-attach': ('<Domain> [--script=<script>] [--ip=<ip>] '
129 '[--mac=<mac>]',
130 'Create a new virtual network device.'),
131 'network-detach': ('<Domain> <DevId>',
132 'Destroy a domain\'s virtual network device.'),
133 'network-list' : ('<Domain> [--long]',
134 'List virtual network interfaces for a domain.'),
135 'vnet-create' : ('<ConfigFile>','Create a vnet from ConfigFile.'),
136 'vnet-delete' : ('<VnetId>', 'Delete a Vnet.'),
137 'vnet-list' : ('[-l|--long]', 'List Vnets.'),
138 'vtpm-list' : ('<Domain> [--long]', 'List virtual TPM devices.'),
140 # security
142 'addlabel' : ('<label> {dom <ConfigFile>|res <resource>} [<policy>]',
143 'Add security label to domain.'),
144 'rmlabel' : ('{dom <ConfigFile>|res <Resource>}',
145 'Remove a security label from domain.'),
146 'getlabel' : ('{dom <ConfigFile>|res <Resource>}',
147 'Show security label for domain or resource.'),
148 'dry-run' : ('<ConfigFile>',
149 'Test if a domain can access its resources.'),
150 'resources' : ('', 'Show info for each labeled resource.'),
151 'cfgbootpolicy' : ('<policy> [kernelversion]',
152 'Add policy to boot configuration.'),
153 'dumppolicy' : ('', 'Print hypervisor ACM state information.'),
154 'loadpolicy' : ('<policy.bin>', 'Load binary policy into hypervisor.'),
155 'makepolicy' : ('<policy>', 'Build policy and create .bin/.map '
156 'files.'),
157 'labels' : ('[policy] [type=dom|res|any]',
158 'List <type> labels for (active) policy.'),
159 'serve' : ('', 'Proxy Xend XMLRPC over stdio.'),
160 }
162 SUBCOMMAND_OPTIONS = {
163 'sched-sedf': (
164 ('-p [MS]', '--period[=MS]', 'Relative deadline(ms)'),
165 ('-s [MS]', '--slice[=MS]' ,
166 'Worst-case execution time(ms). (slice < period)'),
167 ('-l [MS]', '--latency[=MS]',
168 'Scaled period (ms) when domain performs heavy I/O'),
169 ('-e [FLAG]', '--extra[=FLAG]',
170 'Flag (0 or 1) controls if domain can run in extra time.'),
171 ('-w [FLOAT]', '--weight[=FLOAT]',
172 'CPU Period/slice (do not set with --period/--slice)'),
173 ),
174 'sched-credit': (
175 ('-d DOMAIN', '--domain=DOMAIN', 'Domain to modify'),
176 ('-w WEIGHT', '--weight=WEIGHT', 'Weight (int)'),
177 ('-c CAP', '--cap=CAP', 'Cap (int)'),
178 ),
179 'list': (
180 ('-l', '--long', 'Output all VM details in SXP'),
181 ('', '--label', 'Include security labels'),
182 ),
183 'dmesg': (
184 ('-c', '--clear', 'Clear dmesg buffer'),
185 ),
186 'vnet-list': (
187 ('-l', '--long', 'List Vnets as SXP'),
188 ),
189 'network-list': (
190 ('-l', '--long', 'List resources as SXP'),
191 ),
192 }
194 common_commands = [
195 "console",
196 "create",
197 "destroy",
198 "dump-core",
199 "help",
200 "list",
201 "mem-set",
202 "migrate",
203 "pause",
204 "reboot",
205 "restore",
206 "save",
207 "shutdown",
208 "top",
209 "unpause",
210 "uptime",
211 "vcpu-set",
212 ]
214 domain_commands = [
215 "console",
216 "create",
217 "destroy",
218 "domid",
219 "domname",
220 "dump-core",
221 "list",
222 "mem-max",
223 "mem-set",
224 "migrate",
225 "pause",
226 "reboot",
227 "rename",
228 "restore",
229 "save",
230 "shutdown",
231 "sysrq",
232 "top",
233 "unpause",
234 "uptime",
235 "vcpu-list",
236 "vcpu-pin",
237 "vcpu-set",
238 ]
240 host_commands = [
241 "dmesg",
242 "info",
243 "log",
244 "serve",
245 ]
247 scheduler_commands = [
248 "sched-credit",
249 "sched-sedf",
250 ]
252 device_commands = [
253 "block-attach",
254 "block-detach",
255 "block-list",
256 "block-configure",
257 "network-attach",
258 "network-detach",
259 "network-list",
260 "vtpm-list",
261 ]
263 vnet_commands = [
264 "vnet-list",
265 "vnet-create",
266 "vnet-delete",
267 ]
269 acm_commands = [
270 "labels",
271 "addlabel",
272 "rmlabel",
273 "getlabel",
274 "dry-run",
275 "resources",
276 "makepolicy",
277 "loadpolicy",
278 "cfgbootpolicy",
279 "dumppolicy",
280 ]
282 all_commands = (domain_commands + host_commands + scheduler_commands +
283 device_commands + vnet_commands + acm_commands)
285 ####################################################################
286 #
287 # Help/usage printing functions
288 #
289 ####################################################################
291 def cmdHelp(cmd):
292 """Print help for a specific subcommand."""
294 try:
295 args, desc = SUBCOMMAND_HELP[cmd]
296 except KeyError:
297 shortHelp()
298 return
300 print 'Usage: xm %s %s' % (cmd, args)
301 print
302 print desc
304 try:
305 # If options help message is defined, print this.
306 for shortopt, longopt, desc in SUBCOMMAND_OPTIONS[cmd]:
307 if shortopt and longopt:
308 optdesc = '%s, %s' % (shortopt, longopt)
309 elif shortopt:
310 optdesc = shortopt
311 elif longopt:
312 optdesc = longopt
314 wrapped_desc = wrap(desc, 43)
315 print ' %-30s %-43s' % (optdesc, wrapped_desc[0])
316 for line in wrapped_desc[1:]:
317 print ' ' * 33 + line
318 print
319 except KeyError:
320 # if the command is an external module, we grab usage help
321 # from the module itself.
322 if cmd in IMPORTED_COMMANDS:
323 try:
324 cmd_module = __import__(cmd, globals(), locals(), 'xen.xm')
325 cmd_usage = getattr(cmd_module, "help", None)
326 if cmd_usage:
327 print cmd_usage()
328 except ImportError:
329 pass
331 def shortHelp():
332 """Print out generic help when xm is called without subcommand."""
334 print USAGE_HELP
335 print 'Common \'xm\' commands:\n'
337 for command in common_commands:
338 try:
339 args, desc = SUBCOMMAND_HELP[command]
340 except KeyError:
341 continue
342 wrapped_desc = wrap(desc, 50)
343 print ' %-20s %-50s' % (command, wrapped_desc[0])
344 for line in wrapped_desc[1:]:
345 print ' ' * 22 + line
347 print
348 print USAGE_FOOTER
349 print 'For a complete list of subcommands run \'xm help\'.'
351 def longHelp():
352 """Print out full help when xm is called with xm --help or xm help"""
354 print USAGE_HELP
355 print 'xm full list of subcommands:\n'
357 for command in all_commands:
358 try:
359 args, desc = SUBCOMMAND_HELP[command]
360 except KeyError:
361 continue
363 wrapped_desc = wrap(desc, 50)
364 print ' %-20s %-50s' % (command, wrapped_desc[0])
365 for line in wrapped_desc[1:]:
366 print ' ' * 22 + line
368 print
369 print USAGE_FOOTER
371 def usage(cmd = None):
372 """ Print help usage information and exits """
373 if cmd:
374 cmdHelp(cmd)
375 else:
376 shortHelp()
377 sys.exit(1)
380 ####################################################################
381 #
382 # Utility functions
383 #
384 ####################################################################
386 def arg_check(args, name, lo, hi = -1):
387 n = len([i for i in args if i != '--'])
389 if hi == -1:
390 if n != lo:
391 err("'xm %s' requires %d argument%s.\n" % (name, lo,
392 lo == 1 and '' or 's'))
393 usage(name)
394 else:
395 if n < lo or n > hi:
396 err("'xm %s' requires between %d and %d arguments.\n" %
397 (name, lo, hi))
398 usage(name)
401 def unit(c):
402 if not c.isalpha():
403 return 0
404 base = 1
405 if c == 'G' or c == 'g': base = 1024 * 1024 * 1024
406 elif c == 'M' or c == 'm': base = 1024 * 1024
407 elif c == 'K' or c == 'k': base = 1024
408 else:
409 print 'ignoring unknown unit'
410 return base
412 def int_unit(str, dest):
413 base = unit(str[-1])
414 if not base:
415 return int(str)
417 value = int(str[:-1])
418 dst_base = unit(dest)
419 if dst_base == 0:
420 dst_base = 1
421 if dst_base > base:
422 return value / (dst_base / base)
423 else:
424 return value * (base / dst_base)
426 def err(msg):
427 print >>sys.stderr, "Error:", msg
430 #########################################################################
431 #
432 # Main xm functions
433 #
434 #########################################################################
436 def xm_save(args):
437 arg_check(args, "save", 2)
439 try:
440 dominfo = parse_doms_info(server.xend.domain(args[0]))
441 except xmlrpclib.Fault, ex:
442 raise ex
444 domid = dominfo['domid']
445 savefile = os.path.abspath(args[1])
447 if not os.access(os.path.dirname(savefile), os.W_OK):
448 err("xm save: Unable to create file %s" % savefile)
449 sys.exit(1)
451 server.xend.domain.save(domid, savefile)
453 def xm_restore(args):
454 arg_check(args, "restore", 1)
456 savefile = os.path.abspath(args[0])
458 if not os.access(savefile, os.R_OK):
459 err("xm restore: Unable to read file %s" % savefile)
460 sys.exit(1)
462 server.xend.domain.restore(savefile)
465 def getDomains(domain_names, full = 0):
466 if domain_names:
467 return [server.xend.domain(dom) for dom in domain_names]
468 else:
469 return server.xend.domains(1)
472 def xm_list(args):
473 use_long = 0
474 show_vcpus = 0
475 show_labels = 0
476 try:
477 (options, params) = getopt.gnu_getopt(args, 'lv',
478 ['long','vcpus','label'])
479 except getopt.GetoptError, opterr:
480 err(opterr)
481 usage('list')
482 sys.exit(1)
484 for (k, v) in options:
485 if k in ['-l', '--long']:
486 use_long = 1
487 if k in ['-v', '--vcpus']:
488 show_vcpus = 1
489 if k in ['--label']:
490 show_labels = 1
492 if show_vcpus:
493 print >>sys.stderr, (
494 "xm list -v is deprecated. Please use xm vcpu-list.")
495 xm_vcpu_list(params)
496 return
498 doms = getDomains(params, use_long)
500 if use_long:
501 map(PrettyPrint.prettyprint, doms)
502 elif show_labels:
503 xm_label_list(doms)
504 else:
505 xm_brief_list(doms)
508 def parse_doms_info(info):
509 def get_info(n, t, d):
510 return t(sxp.child_value(info, n, d))
512 return {
513 'domid' : get_info('domid', int, -1),
514 'name' : get_info('name', str, '??'),
515 'mem' : get_info('memory', int, 0),
516 'vcpus' : get_info('online_vcpus', int, 0),
517 'state' : get_info('state', str, '??'),
518 'cpu_time' : get_info('cpu_time', float, 0),
519 'up_time' : get_info('up_time', float, -1),
520 'seclabel' : security.get_security_printlabel(info),
521 }
524 def parse_sedf_info(info):
525 def get_info(n, t, d):
526 return t(sxp.child_value(info, n, d))
528 return {
529 'domid' : get_info('domid', int, -1),
530 'period' : get_info('period', int, -1),
531 'slice' : get_info('slice', int, -1),
532 'latency' : get_info('latency', int, -1),
533 'extratime': get_info('extratime', int, -1),
534 'weight' : get_info('weight', int, -1),
535 }
537 def xm_brief_list(doms):
538 print '%-40s %3s %8s %5s %5s %9s' % \
539 ('Name', 'ID', 'Mem(MiB)', 'VCPUs', 'State', 'Time(s)')
541 format = "%(name)-40s %(domid)3d %(mem)8d %(vcpus)5d %(state)5s " \
542 "%(cpu_time)8.1f"
544 for dom in doms:
545 d = parse_doms_info(dom)
546 print format % d
548 def xm_label_list(doms):
549 print '%-32s %3s %8s %5s %5s %9s %-8s' % \
550 ('Name', 'ID', 'Mem(MiB)', 'VCPUs', 'State', 'Time(s)', 'Label')
552 output = []
553 format = '%(name)-32s %(domid)3d %(mem)8d %(vcpus)5d %(state)5s ' \
554 '%(cpu_time)8.1f %(seclabel)9s'
556 for dom in doms:
557 d = parse_doms_info(dom)
558 if security.active_policy not in ['INACTIVE', 'NULL', 'DEFAULT']:
559 if not d['seclabel']:
560 d['seclabel'] = 'ERROR'
561 elif security.active_policy in ['DEFAULT']:
562 d['seclabel'] = 'DEFAULT'
563 else:
564 d['seclabel'] = 'INACTIVE'
565 output.append((format % d, d['seclabel']))
567 #sort by labels
568 output.sort(lambda x,y: cmp( x[1].lower(), y[1].lower()))
569 for line, label in output:
570 print line
573 def xm_vcpu_list(args):
575 if args:
576 dominfo = map(server.xend.domain.getVCPUInfo, args)
577 else:
578 doms = server.xend.domains(False)
579 dominfo = map(server.xend.domain.getVCPUInfo, doms)
581 print '%-32s %3s %5s %5s %5s %9s %s' % \
582 ('Name', 'ID', 'VCPUs', 'CPU', 'State', 'Time(s)', 'CPU Affinity')
584 format = '%(name)-32s %(domid)3d %(number)5d %(c)5s %(s)5s ' \
585 ' %(cpu_time)8.1f %(cpumap)s'
587 for dom in dominfo:
588 def get_info(n):
589 return sxp.child_value(dom, n)
591 #
592 # convert a list of integers into a list of pairs indicating
593 # continuous sequences in the list:
594 #
595 # [0,1,2,3] -> [(0,3)]
596 # [1,2,4,5] -> [(1,2),(4,5)]
597 # [0] -> [(0,0)]
598 # [0,1,4,6,7] -> [(0,1),(4,4),(6,7)]
599 #
600 def list_to_rangepairs(cmap):
601 cmap.sort()
602 pairs = []
603 x = y = 0
604 for i in range(0,len(cmap)):
605 try:
606 if ((cmap[y+1] - cmap[i]) > 1):
607 pairs.append((cmap[x],cmap[y]))
608 x = y = i+1
609 else:
610 y = y + 1
611 # if we go off the end, then just add x to y
612 except IndexError:
613 pairs.append((cmap[x],cmap[y]))
615 return pairs
617 #
618 # Convert pairs to range string, e.g: [(1,2),(3,3),(5,7)] -> 1-2,3,5-7
619 #
620 def format_pairs(pairs):
621 if not pairs:
622 return "no cpus"
623 out = ""
624 for f,s in pairs:
625 if (f==s):
626 out += '%d'%f
627 else:
628 out += '%d-%d'%(f,s)
629 out += ','
630 # trim trailing ','
631 return out[:-1]
633 def format_cpumap(cpumap):
634 cpumap = map(lambda x: int(x), cpumap)
635 cpumap.sort()
637 for x in server.xend.node.info()[1:]:
638 if len(x) > 1 and x[0] == 'nr_cpus':
639 nr_cpus = int(x[1])
640 # normalize cpumap by modulus nr_cpus, and drop duplicates
641 cpumap = dict.fromkeys(
642 map(lambda x: x % nr_cpus, cpumap)).keys()
643 if len(cpumap) == nr_cpus:
644 return "any cpu"
645 break
647 return format_pairs(list_to_rangepairs(cpumap))
649 name = get_info('name')
650 domid = int(get_info('domid'))
652 for vcpu in sxp.children(dom, 'vcpu'):
653 def vinfo(n, t):
654 return t(sxp.child_value(vcpu, n))
656 number = vinfo('number', int)
657 cpu = vinfo('cpu', int)
658 cpumap = format_cpumap(vinfo('cpumap', list))
659 online = vinfo('online', int)
660 cpu_time = vinfo('cpu_time', float)
661 running = vinfo('running', int)
662 blocked = vinfo('blocked', int)
664 if online:
665 c = str(cpu)
666 if running:
667 s = 'r'
668 else:
669 s = '-'
670 if blocked:
671 s += 'b'
672 else:
673 s += '-'
674 s += '-'
675 else:
676 c = "-"
677 s = "--p"
679 print format % locals()
681 def xm_reboot(args):
682 arg_check(args, "reboot", 1, 3)
683 from xen.xm import shutdown
684 shutdown.main(["shutdown", "-R"] + args)
686 def xm_shutdown(args):
687 arg_check(args, "shutdown", 1, 4)
688 from xen.xm import shutdown
689 shutdown.main(["shutdown"] + args)
691 def xm_pause(args):
692 arg_check(args, "pause", 1)
693 dom = args[0]
695 server.xend.domain.pause(dom)
697 def xm_unpause(args):
698 arg_check(args, "unpause", 1)
699 dom = args[0]
701 server.xend.domain.unpause(dom)
703 def xm_dump_core(args):
704 arg_check(args, "dump-core",1,3)
705 live = False
706 crash = False
707 import getopt
708 (options, params) = getopt.gnu_getopt(args, 'LC', ['live','crash'])
710 for (k, v) in options:
711 if k in ['-L', '--live']:
712 live = True
713 if k in ['-C', '--crash']:
714 crash = True
716 if len(params) == 0 or len(params) > 2:
717 err("invalid number of parameters")
718 usage("dump-core")
720 dom = params[0]
721 if len(params) == 2:
722 filename = os.path.abspath(params[1])
723 else:
724 filename = None
726 if not live:
727 server.xend.domain.pause(dom)
729 try:
730 print "dumping core of domain:%s ..." % str(dom)
731 server.xend.domain.dump(dom, filename, live, crash)
732 finally:
733 if not live:
734 server.xend.domain.unpause(dom)
736 if crash:
737 print "destroying domain:%s ..." % str(dom)
738 server.xend.domain.destroy(dom)
740 def xm_rename(args):
741 arg_check(args, "rename", 2)
743 server.xend.domain.setName(args[0], args[1])
745 def xm_importcommand(command, args):
746 cmd = __import__(command, globals(), locals(), 'xen.xm')
747 cmd.main([command] + args)
750 #############################################################
752 def xm_vcpu_pin(args):
753 arg_check(args, "vcpu-pin", 3)
755 def cpu_make_map(cpulist):
756 cpus = []
757 for c in cpulist.split(','):
758 if c.find('-') != -1:
759 (x,y) = c.split('-')
760 for i in range(int(x),int(y)+1):
761 cpus.append(int(i))
762 else:
763 cpus.append(int(c))
764 cpus.sort()
765 return cpus
767 dom = args[0]
768 vcpu = int(args[1])
769 cpumap = cpu_make_map(args[2])
771 server.xend.domain.pincpu(dom, vcpu, cpumap)
773 def xm_mem_max(args):
774 arg_check(args, "mem-max", 2)
776 dom = args[0]
777 mem = int_unit(args[1], 'm')
779 server.xend.domain.maxmem_set(dom, mem)
781 def xm_mem_set(args):
782 arg_check(args, "mem-set", 2)
784 dom = args[0]
785 mem_target = int_unit(args[1], 'm')
787 server.xend.domain.setMemoryTarget(dom, mem_target)
789 def xm_vcpu_set(args):
790 arg_check(args, "vcpu-set", 2)
792 server.xend.domain.setVCpuCount(args[0], int(args[1]))
795 def xm_destroy(args):
796 arg_check(args, "destroy", 1)
797 server.xend.domain.destroy(args[0])
800 def xm_domid(args):
801 arg_check(args, "domid", 1)
803 name = args[0]
805 dom = server.xend.domain(name)
806 print sxp.child_value(dom, 'domid')
808 def xm_domname(args):
809 arg_check(args, "domname", 1)
811 name = args[0]
813 dom = server.xend.domain(name)
814 print sxp.child_value(dom, 'name')
816 def xm_sched_sedf(args):
817 def ns_to_ms(val):
818 return float(val) * 0.000001
820 def ms_to_ns(val):
821 return (float(val) / 0.000001)
823 def print_sedf(info):
824 info['period'] = ns_to_ms(info['period'])
825 info['slice'] = ns_to_ms(info['slice'])
826 info['latency'] = ns_to_ms(info['latency'])
827 print( ("%(name)-32s %(domid)3d %(period)9.1f %(slice)9.1f" +
828 " %(latency)7.1f %(extratime)6d %(weight)6d") % info)
830 def domid_match(domid, info):
831 return domid is None or domid == info['name'] or \
832 domid == str(info['domid'])
834 # we want to just display current info if no parameters are passed
835 if len(args) == 0:
836 domid = None
837 else:
838 # we expect at least a domain id (name or number)
839 # and at most a domid up to 5 options with values
840 arg_check(args, "sched-sedf", 1, 11)
841 domid = args[0]
842 # drop domid from args since get_opt doesn't recognize it
843 args = args[1:]
845 opts = {}
846 try:
847 (options, params) = getopt.gnu_getopt(args, 'p:s:l:e:w:',
848 ['period=', 'slice=', 'latency=', 'extratime=', 'weight='])
849 except getopt.GetoptError, opterr:
850 err(opterr)
851 sys.exit(1)
853 # convert to nanoseconds if needed
854 for (k, v) in options:
855 if k in ['-p', '--period']:
856 opts['period'] = ms_to_ns(v)
857 elif k in ['-s', '--slice']:
858 opts['slice'] = ms_to_ns(v)
859 elif k in ['-l', '--latency']:
860 opts['latency'] = ms_to_ns(v)
861 elif k in ['-e', '--extratime']:
862 opts['extratime'] = v
863 elif k in ['-w', '--weight']:
864 opts['weight'] = v
866 doms = filter(lambda x : domid_match(domid, x),
867 [parse_doms_info(dom) for dom in getDomains("")])
869 # print header if we aren't setting any parameters
870 if len(opts.keys()) == 0:
871 print '%-33s %-2s %-4s %-4s %-7s %-5s %-6s' % \
872 ('Name','ID','Period(ms)', 'Slice(ms)', 'Lat(ms)',
873 'Extra','Weight')
875 for d in doms:
876 # fetch current values so as not to clobber them
877 try:
878 sedf_raw = server.xend.domain.cpu_sedf_get(d['domid'])
879 except xmlrpclib.Fault:
880 # domain does not support sched-sedf?
881 sedf_raw = {}
883 sedf_info = parse_sedf_info(sedf_raw)
884 sedf_info['name'] = d['name']
885 # update values in case of call to set
886 if len(opts.keys()) > 0:
887 for k in opts.keys():
888 sedf_info[k]=opts[k]
890 # send the update, converting user input
891 v = map(int, [sedf_info['period'], sedf_info['slice'],
892 sedf_info['latency'],sedf_info['extratime'],
893 sedf_info['weight']])
894 rv = server.xend.domain.cpu_sedf_set(d['domid'], *v)
895 if int(rv) != 0:
896 err("Failed to set sedf parameters (rv=%d)."%(rv))
898 # not setting values, display info
899 else:
900 print_sedf(sedf_info)
902 def xm_sched_credit(args):
903 """Get/Set options for Credit Scheduler."""
905 try:
906 opts, params = getopt.getopt(args, "d:w:c:",
907 ["domain=", "weight=", "cap="])
908 except getopt.GetoptError, opterr:
909 err(opterr)
910 usage('sched-credit')
911 sys.exit(1)
913 domain = None
914 weight = None
915 cap = None
917 for o, a in opts:
918 if o == "-d":
919 domain = a
920 elif o == "-w":
921 weight = int(a)
922 elif o == "-c":
923 cap = int(a);
925 if domain is None:
926 # place holder for system-wide scheduler parameters
927 err("No domain given.")
928 usage('sched-credit')
929 sys.exit(1)
931 if weight is None and cap is None:
932 print server.xend.domain.sched_credit_get(domain)
933 else:
934 result = server.xend.domain.sched_credit_set(domain, weight, cap)
935 if result != 0:
936 err(str(result))
938 def xm_info(args):
939 arg_check(args, "info", 0)
941 info = server.xend.node.info()
943 for x in info[1:]:
944 if len(x) < 2:
945 print "%-23s: (none)" % x[0]
946 else:
947 print "%-23s:" % x[0], x[1]
949 def xm_console(args):
950 arg_check(args, "console", 1)
952 dom = args[0]
953 info = server.xend.domain(dom)
954 domid = int(sxp.child_value(info, 'domid', '-1'))
955 if domid == -1:
956 raise Exception("Domain is not started")
957 console.execConsole(domid)
959 def xm_uptime(args):
960 short_mode = 0
962 try:
963 (options, params) = getopt.gnu_getopt(args, 's', ['short'])
964 except getopt.GetoptError, opterr:
965 err(opterr)
966 sys.exit(1)
968 for (k, v) in options:
969 if k in ['-s', '--short']:
970 short_mode = 1
972 doms = getDomains(params)
974 if short_mode == 0:
975 print 'Name ID Uptime'
977 for dom in doms:
978 d = parse_doms_info(dom)
979 if d['dom'] > 0:
980 uptime = int(round(d['up_time']))
981 else:
982 f=open('/proc/uptime', 'r')
983 upfile = f.read()
984 uptime = int(round(float(upfile.split(' ')[0])))
985 f.close()
987 days = int(uptime / 86400)
988 uptime -= (days * 86400)
989 hours = int(uptime / 3600)
990 uptime -= (hours * 3600)
991 minutes = int(uptime / 60)
992 uptime -= (minutes * 60)
993 seconds = uptime
995 upstring = ""
996 if days > 0:
997 upstring += str(days) + " day"
998 if days > 1:
999 upstring += "s"
1000 upstring += ", "
1001 upstring += '%(hours)2d:%(minutes)02d' % vars()
1003 if short_mode:
1004 now = datetime.datetime.now()
1005 upstring = now.strftime(" %H:%M:%S") + " up " + upstring
1006 upstring += ", " + d['name'] + " (" + str(d['dom']) + ")"
1007 else:
1008 upstring += ':%(seconds)02d' % vars()
1009 upstring = ("%(name)-32s %(dom)3d " % d) + upstring
1011 print upstring
1013 def xm_sysrq(args):
1014 arg_check(args, "sysrq", 2)
1015 dom = args[0]
1016 req = args[1]
1017 server.xend.domain.send_sysrq(dom, req)
1019 def xm_top(args):
1020 arg_check(args, "top", 0)
1022 os.execvp('xentop', ['xentop'])
1024 def xm_dmesg(args):
1025 arg_check(args, "dmesg", 0, 1)
1027 gopts = Opts(use="""[-c|--clear]
1029 Read Xen's message buffer (boot output, warning and error messages) or clear
1030 its contents if the [-c|--clear] flag is specified.
1031 """)
1033 gopts.opt('clear', short='c',
1034 fn=set_true, default=0,
1035 use="Clear the contents of the Xen message buffer.")
1036 # Work around for gopts
1037 myargs = args
1038 myargs.insert(0, 'dmesg')
1039 gopts.parse(myargs)
1041 if len(myargs) not in (1, 2):
1042 err('Invalid arguments: ' + str(myargs))
1043 usage('dmesg')
1044 sys.exit(1)
1046 if not gopts.vals.clear:
1047 print server.xend.node.dmesg.info()
1048 else:
1049 server.xend.node.dmesg.clear()
1051 def xm_log(args):
1052 arg_check(args, "log", 0)
1054 print server.xend.node.log()
1056 def xm_serve(args):
1057 arg_check(args, "serve", 0)
1059 from fcntl import fcntl, F_SETFL
1061 s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
1062 s.connect(XendClient.XML_RPC_SOCKET)
1063 fcntl(sys.stdin, F_SETFL, os.O_NONBLOCK)
1065 while True:
1066 iwtd, owtd, ewtd = select([sys.stdin, s], [], [])
1067 if s in iwtd:
1068 data = s.recv(4096)
1069 if len(data) > 0:
1070 sys.stdout.write(data)
1071 sys.stdout.flush()
1072 else:
1073 break
1074 if sys.stdin in iwtd:
1075 data = sys.stdin.read(4096)
1076 if len(data) > 0:
1077 s.sendall(data)
1078 else:
1079 break
1080 s.close()
1082 def parse_dev_info(info):
1083 def get_info(n, t, d):
1084 i = 0
1085 while i < len(info):
1086 if (info[i][0] == n):
1087 return t(info[i][1])
1088 i = i + 1
1089 return t(d)
1090 return {
1091 #common
1092 'backend-id' : get_info('backend-id', int, -1),
1093 'handle' : get_info('handle', int, 0),
1094 'state' : get_info('state', int, -1),
1095 'be-path' : get_info('backend', str, '??'),
1096 'event-ch' : get_info('event-channel',int, -1),
1097 #network specific
1098 'virtual-device' : get_info('virtual-device', str, '??'),
1099 'tx-ring-ref': get_info('tx-ring-ref', int, -1),
1100 'rx-ring-ref': get_info('rx-ring-ref', int, -1),
1101 'mac' : get_info('mac', str, '??'),
1102 #block-device specific
1103 'ring-ref' : get_info('ring-ref', int, -1),
1106 def arg_check_for_resource_list(args, name):
1107 use_long = 0
1108 try:
1109 (options, params) = getopt.gnu_getopt(args, 'l', ['long'])
1110 except getopt.GetoptError, opterr:
1111 err(opterr)
1112 sys.exit(1)
1114 for (k, v) in options:
1115 if k in ['-l', '--long']:
1116 use_long = 1
1118 if len(params) == 0:
1119 print 'No domain parameter given'
1120 usage(name)
1121 if len(params) > 1:
1122 print 'No multiple domain parameters allowed'
1123 usage(name)
1125 return (use_long, params)
1127 def xm_network_list(args):
1128 (use_long, params) = arg_check_for_resource_list(args, "network-list")
1130 dom = params[0]
1131 if use_long:
1132 devs = server.xend.domain.getDeviceSxprs(dom, 'vif')
1133 map(PrettyPrint.prettyprint, devs)
1134 else:
1135 hdr = 0
1136 for x in server.xend.domain.getDeviceSxprs(dom, 'vif'):
1137 if hdr == 0:
1138 print 'Idx BE MAC Addr. handle state evt-ch tx-/rx-ring-ref BE-path'
1139 hdr = 1
1140 ni = parse_dev_info(x[1])
1141 ni['idx'] = int(x[0])
1142 print ("%(idx)-3d "
1143 "%(backend-id)-3d"
1144 "%(mac)-17s "
1145 "%(handle)-3d "
1146 "%(state)-3d "
1147 "%(event-ch)-3d "
1148 "%(tx-ring-ref)-5d/%(rx-ring-ref)-5d "
1149 "%(be-path)-30s "
1150 % ni)
1152 def xm_block_list(args):
1153 (use_long, params) = arg_check_for_resource_list(args, "block-list")
1155 dom = params[0]
1156 if use_long:
1157 devs = server.xend.domain.getDeviceSxprs(dom, 'vbd')
1158 map(PrettyPrint.prettyprint, devs)
1159 else:
1160 hdr = 0
1161 for x in server.xend.domain.getDeviceSxprs(dom, 'vbd'):
1162 if hdr == 0:
1163 print 'Vdev BE handle state evt-ch ring-ref BE-path'
1164 hdr = 1
1165 ni = parse_dev_info(x[1])
1166 ni['idx'] = int(x[0])
1167 print ("%(idx)-3d "
1168 "%(backend-id)-3d "
1169 "%(handle)-3d "
1170 "%(state)-3d "
1171 "%(event-ch)-3d "
1172 "%(ring-ref)-5d "
1173 "%(be-path)-30s "
1174 % ni)
1176 def xm_vtpm_list(args):
1177 (use_long, params) = arg_check_for_resource_list(args, "vtpm-list")
1179 dom = params[0]
1180 if use_long:
1181 devs = server.xend.domain.getDeviceSxprs(dom, 'vtpm')
1182 map(PrettyPrint.prettyprint, devs)
1183 else:
1184 hdr = 0
1185 for x in server.xend.domain.getDeviceSxprs(dom, 'vtpm'):
1186 if hdr == 0:
1187 print 'Idx BE handle state evt-ch ring-ref BE-path'
1188 hdr = 1
1189 ni = parse_dev_info(x[1])
1190 ni['idx'] = int(x[0])
1191 print ("%(idx)-3d "
1192 "%(backend-id)-3d "
1193 "%(handle)-3d "
1194 "%(state)-3d "
1195 "%(event-ch)-3d "
1196 "%(ring-ref)-5d "
1197 "%(be-path)-30s "
1198 % ni)
1201 def parse_block_configuration(args):
1202 dom = args[0]
1204 if args[1].startswith('tap:'):
1205 cls = 'tap'
1206 else:
1207 cls = 'vbd'
1209 vbd = [cls,
1210 ['uname', args[1]],
1211 ['dev', args[2]],
1212 ['mode', args[3]]]
1213 if len(args) == 5:
1214 vbd.append(['backend', args[4]])
1216 # verify that policy permits attaching this resource
1217 if security.on():
1218 dominfo = server.xend.domain(dom)
1219 label = security.get_security_printlabel(dominfo)
1220 else:
1221 label = None
1222 security.res_security_check(args[1], label)
1224 return (dom, vbd)
1227 def xm_block_attach(args):
1228 arg_check(args, 'block-attach', 4, 5)
1230 (dom, vbd) = parse_block_configuration(args)
1231 server.xend.domain.device_create(dom, vbd)
1234 def xm_block_configure(args):
1235 arg_check(args, 'block-configure', 4, 5)
1237 (dom, vbd) = parse_block_configuration(args)
1238 server.xend.domain.device_configure(dom, vbd)
1241 def xm_network_attach(args):
1242 arg_check(args, 'network-attach', 1, 10000)
1244 dom = args[0]
1245 vif = ['vif']
1247 for a in args[1:]:
1248 vif.append(a.split("="))
1250 server.xend.domain.device_create(dom, vif)
1253 def detach(args, command, deviceClass):
1254 arg_check(args, command, 2)
1256 dom = args[0]
1257 dev = args[1]
1259 server.xend.domain.destroyDevice(dom, deviceClass, dev)
1262 def xm_block_detach(args):
1263 detach(args, 'block-detach', 'vbd')
1266 def xm_network_detach(args):
1267 detach(args, 'network-detach', 'vif')
1270 def xm_vnet_list(args):
1271 try:
1272 (options, params) = getopt.gnu_getopt(args, 'l', ['long'])
1273 except getopt.GetoptError, opterr:
1274 err(opterr)
1275 sys.exit(1)
1277 use_long = 0
1278 for (k, v) in options:
1279 if k in ['-l', '--long']:
1280 use_long = 1
1282 if params:
1283 use_long = 1
1284 vnets = params
1285 else:
1286 vnets = server.xend_vnets()
1288 for vnet in vnets:
1289 try:
1290 if use_long:
1291 info = server.xend_vnet(vnet)
1292 PrettyPrint.prettyprint(info)
1293 else:
1294 print vnet
1295 except Exception, ex:
1296 print vnet, ex
1298 def xm_vnet_create(args):
1299 arg_check(args, "vnet-create", 1)
1300 conf = args[0]
1301 if not os.access(conf, os.R_OK):
1302 print "File not found: %s" % conf
1303 sys.exit(1)
1305 server.xend_vnet_create(conf)
1307 def xm_vnet_delete(args):
1308 arg_check(args, "vnet-delete", 1)
1309 vnet = args[0]
1310 server.xend_vnet_delete(vnet)
1312 commands = {
1313 # console commands
1314 "console": xm_console,
1315 # xenstat commands
1316 "top": xm_top,
1317 # domain commands
1318 "destroy": xm_destroy,
1319 "domid": xm_domid,
1320 "domname": xm_domname,
1321 "dump-core": xm_dump_core,
1322 "reboot": xm_reboot,
1323 "rename": xm_rename,
1324 "restore": xm_restore,
1325 "save": xm_save,
1326 "shutdown": xm_shutdown,
1327 "sysrq": xm_sysrq,
1328 "uptime": xm_uptime,
1329 "list": xm_list,
1330 # memory commands
1331 "mem-max": xm_mem_max,
1332 "mem-set": xm_mem_set,
1333 # cpu commands
1334 "vcpu-pin": xm_vcpu_pin,
1335 "vcpu-list": xm_vcpu_list,
1336 "vcpu-set": xm_vcpu_set,
1337 # special
1338 "pause": xm_pause,
1339 "unpause": xm_unpause,
1340 # host commands
1341 "dmesg": xm_dmesg,
1342 "info": xm_info,
1343 "log": xm_log,
1344 "serve": xm_serve,
1345 # scheduler
1346 "sched-sedf": xm_sched_sedf,
1347 "sched-credit": xm_sched_credit,
1348 # block
1349 "block-attach": xm_block_attach,
1350 "block-detach": xm_block_detach,
1351 "block-list": xm_block_list,
1352 "block-configure": xm_block_configure,
1353 # network
1354 "network-attach": xm_network_attach,
1355 "network-detach": xm_network_detach,
1356 "network-list": xm_network_list,
1357 # vnet
1358 "vnet-list": xm_vnet_list,
1359 "vnet-create": xm_vnet_create,
1360 "vnet-delete": xm_vnet_delete,
1361 # vtpm
1362 "vtpm-list": xm_vtpm_list,
1365 ## The commands supported by a separate argument parser in xend.xm.
1366 IMPORTED_COMMANDS = [
1367 'create',
1368 'migrate',
1369 'labels',
1370 'addlabel',
1371 'cfgbootpolicy',
1372 'makepolicy',
1373 'loadpolicy',
1374 'dumppolicy'
1375 'rmlabel',
1376 'getlabel',
1377 'dry-run',
1378 'resources',
1381 for c in IMPORTED_COMMANDS:
1382 commands[c] = eval('lambda args: xm_importcommand("%s", args)' % c)
1384 aliases = {
1385 "balloon": "mem-set",
1386 "set-vcpus": "vcpu-set",
1387 "vif-list": "network-list",
1388 "vbd-create": "block-attach",
1389 "vbd-destroy": "block-detach",
1390 "vbd-list": "block-list",
1394 def xm_lookup_cmd(cmd):
1395 if commands.has_key(cmd):
1396 return commands[cmd]
1397 elif aliases.has_key(cmd):
1398 deprecated(cmd,aliases[cmd])
1399 return commands[aliases[cmd]]
1400 elif cmd == 'help':
1401 longHelp()
1402 sys.exit(0)
1403 else:
1404 # simulate getopt's prefix matching behaviour
1405 if len(cmd) > 1:
1406 same_prefix_cmds = [commands[c] for c in commands.keys() \
1407 if c[:len(cmd)] == cmd]
1408 # only execute if there is only 1 match
1409 if len(same_prefix_cmds) == 1:
1410 return same_prefix_cmds[0]
1412 err('Sub Command %s not found!' % cmd)
1413 usage()
1415 def deprecated(old,new):
1416 print >>sys.stderr, (
1417 "Command %s is deprecated. Please use xm %s instead." % (old, new))
1419 def main(argv=sys.argv):
1420 if len(argv) < 2:
1421 usage()
1423 # intercept --help and output our own help
1424 if '--help' in argv[1:]:
1425 if '--help' == argv[1]:
1426 longHelp()
1427 else:
1428 usage(argv[1])
1429 sys.exit(0)
1431 cmd = xm_lookup_cmd(argv[1])
1433 # strip off prog name and subcmd
1434 args = argv[2:]
1435 if cmd:
1436 try:
1437 rc = cmd(args)
1438 if rc:
1439 usage()
1440 except socket.error, ex:
1441 if os.geteuid() != 0:
1442 err("Most commands need root access. Please try again as root.")
1443 else:
1444 err("Unable to connect to xend: %s. Is xend running?" % ex[1])
1445 sys.exit(1)
1446 except KeyboardInterrupt:
1447 print "Interrupted."
1448 sys.exit(1)
1449 except IOError, ex:
1450 if os.geteuid() != 0:
1451 err("Most commands need root access. Please try again as root.")
1452 else:
1453 err("Unable to connect to xend: %s." % ex[1])
1454 sys.exit(1)
1455 except SystemExit:
1456 sys.exit(1)
1457 except xmlrpclib.Fault, ex:
1458 if ex.faultCode == XendClient.ERROR_INVALID_DOMAIN:
1459 err("Domain '%s' does not exist." % ex.faultString)
1460 else:
1461 err(ex.faultString)
1462 usage(argv[1])
1463 sys.exit(1)
1464 except xmlrpclib.ProtocolError, ex:
1465 if ex.errcode == -1:
1466 print >>sys.stderr, (
1467 "Xend has probably crashed! Invalid or missing HTTP "
1468 "status code.")
1469 else:
1470 print >>sys.stderr, (
1471 "Xend has probably crashed! ProtocolError(%d, %s)." %
1472 (ex.errcode, ex.errmsg))
1473 sys.exit(1)
1474 except (ValueError, OverflowError):
1475 err("Invalid argument.")
1476 usage(argv[1])
1477 except OptionError, e:
1478 err(str(e))
1479 usage(argv[1])
1480 print e.usage()
1481 except:
1482 print "Unexpected error:", sys.exc_info()[0]
1483 print
1484 print "Please report to xen-devel@lists.xensource.com"
1485 raise
1487 else:
1488 usage()
1490 if __name__ == "__main__":
1491 main()