ia64/xen-unstable

view tools/python/xen/xm/main.py @ 14430:edccebeea4a3

Added a new Xen-API call VM.send_sysrq, and use that to implement xm sysrq
through Xen-API.

Signed-off-by: Tom Wilkie <tom.wilkie@gmail.com>
author Ewan Mellor <ewan@xensource.com>
date Thu Mar 15 21:59:34 2007 +0000 (2007-03-15)
parents 1c94d9fcb7ef
children cd8d2a4d46e4
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 atexit
25 import cmd
26 import os
27 import pprint
28 import readline
29 import shlex
30 import sys
31 import re
32 import getopt
33 import socket
34 import traceback
35 import xmlrpclib
36 import traceback
37 import time
38 import datetime
39 from select import select
40 import xml.dom.minidom
42 import warnings
43 warnings.filterwarnings('ignore', category=FutureWarning)
45 from xen.xend import PrettyPrint
46 from xen.xend import sxp
47 from xen.xend import XendClient
48 from xen.xend.XendConstants import *
50 from xen.xm.opts import OptionError, Opts, wrap, set_true
51 from xen.xm import console
52 from xen.util import security
53 from xen.util.xmlrpclib2 import ServerProxy
55 import XenAPI
57 # getopt.gnu_getopt is better, but only exists in Python 2.3+. Use
58 # getopt.getopt if gnu_getopt is not available. This will mean that options
59 # may only be specified before positional arguments.
60 if not hasattr(getopt, 'gnu_getopt'):
61 getopt.gnu_getopt = getopt.getopt
63 XM_CONFIG_FILE_ENVVAR = 'XM_CONFIG_FILE'
64 XM_CONFIG_FILE_DEFAULT = '/etc/xen/xm-config.xml'
66 # Supported types of server
67 SERVER_LEGACY_XMLRPC = 'LegacyXMLRPC'
68 SERVER_XEN_API = 'Xen-API'
70 # General help message
72 USAGE_HELP = "Usage: xm <subcommand> [args]\n\n" \
73 "Control, list, and manipulate Xen guest instances.\n"
75 USAGE_FOOTER = '<Domain> can either be the Domain Name or Id.\n' \
76 'For more help on \'xm\' see the xm(1) man page.\n' \
77 'For more help on \'xm create\' see the xmdomain.cfg(5) '\
78 ' man page.\n'
80 # Help strings are indexed by subcommand name in this way:
81 # 'subcommand': (argstring, description)
83 SUBCOMMAND_HELP = {
84 # common commands
86 'shell' : ('', 'Launch an interactive shell.'),
88 'console' : ('[-q|--quiet] <Domain>',
89 'Attach to <Domain>\'s console.'),
90 'create' : ('<ConfigFile> [options] [vars]',
91 'Create a domain based on <ConfigFile>.'),
92 'destroy' : ('<Domain>',
93 'Terminate a domain immediately.'),
94 'help' : ('', 'Display this message.'),
95 'list' : ('[options] [Domain, ...]',
96 'List information about all/some domains.'),
97 'mem-max' : ('<Domain> <Mem>',
98 'Set the maximum amount reservation for a domain.'),
99 'mem-set' : ('<Domain> <Mem>',
100 'Set the current memory usage for a domain.'),
101 'migrate' : ('<Domain> <Host>',
102 'Migrate a domain to another machine.'),
103 'pause' : ('<Domain>', 'Pause execution of a domain.'),
104 'reboot' : ('<Domain> [-wa]', 'Reboot a domain.'),
105 'restore' : ('<CheckpointFile> [-p]',
106 'Restore a domain from a saved state.'),
107 'save' : ('[-c] <Domain> <CheckpointFile>',
108 'Save a domain state to restore later.'),
109 'shutdown' : ('<Domain> [-waRH]', 'Shutdown a domain.'),
110 'top' : ('', 'Monitor a host and the domains in real time.'),
111 'unpause' : ('<Domain>', 'Unpause a paused domain.'),
112 'uptime' : ('[-s] <Domain>', 'Print uptime for a domain.'),
114 # Life cycle xm commands
115 'new' : ('<ConfigFile> [options] [vars]',
116 'Adds a domain to Xend domain management'),
117 'delete' : ('<DomainName>',
118 'Remove a domain from Xend domain management.'),
119 'start' : ('<DomainName>', 'Start a Xend managed domain'),
120 'resume' : ('<DomainName>', 'Resume a Xend managed domain'),
121 'suspend' : ('<DomainName>', 'Suspend a Xend managed domain'),
123 # less used commands
125 'dmesg' : ('[-c|--clear]',
126 'Read and/or clear Xend\'s message buffer.'),
127 'domid' : ('<DomainName>', 'Convert a domain name to domain id.'),
128 'domname' : ('<DomId>', 'Convert a domain id to domain name.'),
129 'dump-core' : ('[-L|--live] [-C|--crash] <Domain> [Filename]',
130 'Dump core for a specific domain.'),
131 'info' : ('', 'Get information about Xen host.'),
132 'log' : ('', 'Print Xend log'),
133 'rename' : ('<Domain> <NewDomainName>', 'Rename a domain.'),
134 'sched-sedf' : ('<Domain> [options]', 'Get/set EDF parameters.'),
135 'sched-credit': ('[-d <Domain> [-w[=WEIGHT]|-c[=CAP]]]',
136 'Get/set credit scheduler parameters.'),
137 'sysrq' : ('<Domain> <letter>', 'Send a sysrq to a domain.'),
138 'debug-keys' : ('<Keys>', 'Send debug keys to Xen.'),
139 'trigger' : ('<Domain> <nmi|reset|init> [<VCPU>]',
140 'Send a trigger to a domain.'),
141 'vcpu-list' : ('[<Domain>]',
142 'List the VCPUs for a domain or all domains.'),
143 'vcpu-pin' : ('<Domain> <VCPU> <CPUs|all>',
144 'Set which CPUs a VCPU can use.'),
145 'vcpu-set' : ('<Domain> <vCPUs>',
146 'Set the number of active VCPUs for allowed for the'
147 ' domain.'),
149 # device commands
151 'block-attach' : ('<Domain> <BackDev> <FrontDev> <Mode> [BackDomain]',
152 'Create a new virtual block device.'),
153 'block-configure': ('<Domain> <BackDev> <FrontDev> <Mode> [BackDomain]',
154 'Change block device configuration'),
155 'block-detach' : ('<Domain> <DevId> [-f|--force]',
156 'Destroy a domain\'s virtual block device.'),
157 'block-list' : ('<Domain> [--long]',
158 'List virtual block devices for a domain.'),
159 'network-attach': ('<Domain> [type=<type>] [mac=<mac>] [bridge=<bridge>] '
160 '[ip=<ip>] [script=<script>] [backend=<BackDomain>] '
161 '[vifname=<name>] [rate=<rate>] [model=<model>]',
162 'Create a new virtual network device.'),
163 'network-detach': ('<Domain> <DevId> [-f|--force]',
164 'Destroy a domain\'s virtual network device.'),
165 'network-list' : ('<Domain> [--long]',
166 'List virtual network interfaces for a domain.'),
167 'vnet-create' : ('<ConfigFile>','Create a vnet from ConfigFile.'),
168 'vnet-delete' : ('<VnetId>', 'Delete a Vnet.'),
169 'vnet-list' : ('[-l|--long]', 'List Vnets.'),
170 'vtpm-list' : ('<Domain> [--long]', 'List virtual TPM devices.'),
172 # security
174 'addlabel' : ('<label> {dom <ConfigFile>|res <resource>} [<policy>]',
175 'Add security label to domain.'),
176 'rmlabel' : ('{dom <ConfigFile>|res <Resource>}',
177 'Remove a security label from domain.'),
178 'getlabel' : ('{dom <ConfigFile>|res <Resource>}',
179 'Show security label for domain or resource.'),
180 'dry-run' : ('<ConfigFile>',
181 'Test if a domain can access its resources.'),
182 'resources' : ('', 'Show info for each labeled resource.'),
183 'cfgbootpolicy' : ('<policy> [boot-title]',
184 'Add policy to boot configuration.'),
185 'dumppolicy' : ('', 'Print hypervisor ACM state information.'),
186 'loadpolicy' : ('<policy.bin>', 'Load binary policy into hypervisor.'),
187 'makepolicy' : ('<policy>', 'Build policy and create .bin/.map '
188 'files.'),
189 'labels' : ('[policy] [type=dom|res|any]',
190 'List <type> labels for (active) policy.'),
191 'serve' : ('', 'Proxy Xend XMLRPC over stdio.'),
192 }
194 SUBCOMMAND_OPTIONS = {
195 'sched-sedf': (
196 ('-p [MS]', '--period[=MS]', 'Relative deadline(ms)'),
197 ('-s [MS]', '--slice[=MS]' ,
198 'Worst-case execution time(ms). (slice < period)'),
199 ('-l [MS]', '--latency[=MS]',
200 'Scaled period (ms) when domain performs heavy I/O'),
201 ('-e [FLAG]', '--extra[=FLAG]',
202 'Flag (0 or 1) controls if domain can run in extra time.'),
203 ('-w [FLOAT]', '--weight[=FLOAT]',
204 'CPU Period/slice (do not set with --period/--slice)'),
205 ),
206 'sched-credit': (
207 ('-d DOMAIN', '--domain=DOMAIN', 'Domain to modify'),
208 ('-w WEIGHT', '--weight=WEIGHT', 'Weight (int)'),
209 ('-c CAP', '--cap=CAP', 'Cap (int)'),
210 ),
211 'list': (
212 ('-l', '--long', 'Output all VM details in SXP'),
213 ('', '--label', 'Include security labels'),
214 ('', '--state=<state>', 'Select only VMs with the specified state'),
215 ),
216 'console': (
217 ('-q', '--quiet', 'Do not print an error message if the domain does not exist'),
218 ),
219 'dmesg': (
220 ('-c', '--clear', 'Clear dmesg buffer'),
221 ),
222 'vnet-list': (
223 ('-l', '--long', 'List Vnets as SXP'),
224 ),
225 'network-list': (
226 ('-l', '--long', 'List resources as SXP'),
227 ),
228 'dump-core': (
229 ('-L', '--live', 'Dump core without pausing the domain'),
230 ('-C', '--crash', 'Crash domain after dumping core'),
231 ),
232 'start': (
233 ('-p', '--paused', 'Do not unpause domain after starting it'),
234 ),
235 'resume': (
236 ('-p', '--paused', 'Do not unpause domain after resuming it'),
237 ),
238 'save': (
239 ('-c', '--checkpoint', 'Leave domain running after creating snapshot'),
240 ),
241 'restore': (
242 ('-p', '--paused', 'Do not unpause domain after restoring it'),
243 ),
244 }
246 common_commands = [
247 "console",
248 "create",
249 "new",
250 "delete",
251 "destroy",
252 "dump-core",
253 "help",
254 "list",
255 "mem-set",
256 "migrate",
257 "pause",
258 "reboot",
259 "restore",
260 "resume",
261 "save",
262 "shell",
263 "shutdown",
264 "start",
265 "suspend",
266 "top",
267 "unpause",
268 "uptime",
269 "vcpu-set",
270 ]
272 domain_commands = [
273 "console",
274 "create",
275 "new",
276 "delete",
277 "destroy",
278 "domid",
279 "domname",
280 "dump-core",
281 "list",
282 "mem-max",
283 "mem-set",
284 "migrate",
285 "pause",
286 "reboot",
287 "rename",
288 "restore",
289 "resume",
290 "save",
291 "shutdown",
292 "start",
293 "suspend",
294 "sysrq",
295 "trigger",
296 "top",
297 "unpause",
298 "uptime",
299 "vcpu-list",
300 "vcpu-pin",
301 "vcpu-set",
302 ]
304 host_commands = [
305 "debug-keys",
306 "dmesg",
307 "info",
308 "log",
309 "serve",
310 ]
312 scheduler_commands = [
313 "sched-credit",
314 "sched-sedf",
315 ]
317 device_commands = [
318 "block-attach",
319 "block-detach",
320 "block-list",
321 "block-configure",
322 "network-attach",
323 "network-detach",
324 "network-list",
325 "vtpm-list",
326 ]
328 vnet_commands = [
329 "vnet-list",
330 "vnet-create",
331 "vnet-delete",
332 ]
334 acm_commands = [
335 "labels",
336 "addlabel",
337 "rmlabel",
338 "getlabel",
339 "dry-run",
340 "resources",
341 "makepolicy",
342 "loadpolicy",
343 "cfgbootpolicy",
344 "dumppolicy",
345 ]
347 all_commands = (domain_commands + host_commands + scheduler_commands +
348 device_commands + vnet_commands + acm_commands + ['shell'])
351 ##
352 # Configuration File Parsing
353 ##
355 xmConfigFile = os.getenv(XM_CONFIG_FILE_ENVVAR, XM_CONFIG_FILE_DEFAULT)
356 config = None
357 if os.path.isfile(xmConfigFile):
358 try:
359 config = xml.dom.minidom.parse(xmConfigFile)
360 except:
361 print >>sys.stderr, ('Ignoring invalid configuration file %s.' %
362 xmConfigFile)
364 def parseServer():
365 if config:
366 server = config.getElementsByTagName('server')
367 if server:
368 st = server[0].getAttribute('type')
369 if st != SERVER_XEN_API and st != SERVER_LEGACY_XMLRPC:
370 print >>sys.stderr, ('Invalid server type %s; using %s.' %
371 (st, SERVER_LEGACY_XMLRPC))
372 st = SERVER_LEGACY_XMLRPC
373 return (st, server[0].getAttribute('uri'))
375 return SERVER_LEGACY_XMLRPC, XendClient.uri
377 def parseAuthentication():
378 server = config.getElementsByTagName('server')[0]
379 return (server.getAttribute('username'),
380 server.getAttribute('password'))
382 serverType, serverURI = parseServer()
383 server = None
386 ####################################################################
387 #
388 # Help/usage printing functions
389 #
390 ####################################################################
392 def cmdHelp(cmd):
393 """Print help for a specific subcommand."""
395 for fc in SUBCOMMAND_HELP.keys():
396 if fc[:len(cmd)] == cmd:
397 cmd = fc
398 break
400 try:
401 args, desc = SUBCOMMAND_HELP[cmd]
402 except KeyError:
403 shortHelp()
404 return
406 print 'Usage: xm %s %s' % (cmd, args)
407 print
408 print desc
410 try:
411 # If options help message is defined, print this.
412 for shortopt, longopt, desc in SUBCOMMAND_OPTIONS[cmd]:
413 if shortopt and longopt:
414 optdesc = '%s, %s' % (shortopt, longopt)
415 elif shortopt:
416 optdesc = shortopt
417 elif longopt:
418 optdesc = longopt
420 wrapped_desc = wrap(desc, 43)
421 print ' %-30s %-43s' % (optdesc, wrapped_desc[0])
422 for line in wrapped_desc[1:]:
423 print ' ' * 33 + line
424 print
425 except KeyError:
426 # if the command is an external module, we grab usage help
427 # from the module itself.
428 if cmd in IMPORTED_COMMANDS:
429 try:
430 cmd_module = __import__(cmd, globals(), locals(), 'xen.xm')
431 cmd_usage = getattr(cmd_module, "help", None)
432 if cmd_usage:
433 print cmd_usage()
434 except ImportError:
435 pass
437 def shortHelp():
438 """Print out generic help when xm is called without subcommand."""
440 print USAGE_HELP
441 print 'Common \'xm\' commands:\n'
443 for command in common_commands:
444 try:
445 args, desc = SUBCOMMAND_HELP[command]
446 except KeyError:
447 continue
448 wrapped_desc = wrap(desc, 50)
449 print ' %-20s %-50s' % (command, wrapped_desc[0])
450 for line in wrapped_desc[1:]:
451 print ' ' * 22 + line
453 print
454 print USAGE_FOOTER
455 print 'For a complete list of subcommands run \'xm help\'.'
457 def longHelp():
458 """Print out full help when xm is called with xm --help or xm help"""
460 print USAGE_HELP
461 print 'xm full list of subcommands:\n'
463 for command in all_commands:
464 try:
465 args, desc = SUBCOMMAND_HELP[command]
466 except KeyError:
467 continue
469 wrapped_desc = wrap(desc, 50)
470 print ' %-20s %-50s' % (command, wrapped_desc[0])
471 for line in wrapped_desc[1:]:
472 print ' ' * 22 + line
474 print
475 print USAGE_FOOTER
477 def _usage(cmd):
478 """ Print help usage information """
479 if cmd:
480 cmdHelp(cmd)
481 else:
482 shortHelp()
484 def usage(cmd = None):
485 """ Print help usage information and exits """
486 _usage(cmd)
487 sys.exit(1)
490 ####################################################################
491 #
492 # Utility functions
493 #
494 ####################################################################
496 def arg_check(args, name, lo, hi = -1):
497 n = len([i for i in args if i != '--'])
499 if hi == -1:
500 if n != lo:
501 err("'xm %s' requires %d argument%s.\n" % (name, lo,
502 lo == 1 and '' or 's'))
503 usage(name)
504 else:
505 if n < lo or n > hi:
506 err("'xm %s' requires between %d and %d arguments.\n" %
507 (name, lo, hi))
508 usage(name)
511 def unit(c):
512 if not c.isalpha():
513 return 0
514 base = 1
515 if c == 'G' or c == 'g': base = 1024 * 1024 * 1024
516 elif c == 'M' or c == 'm': base = 1024 * 1024
517 elif c == 'K' or c == 'k': base = 1024
518 else:
519 print 'ignoring unknown unit'
520 return base
522 def int_unit(str, dest):
523 base = unit(str[-1])
524 if not base:
525 return int(str)
527 value = int(str[:-1])
528 dst_base = unit(dest)
529 if dst_base == 0:
530 dst_base = 1
531 if dst_base > base:
532 return value / (dst_base / base)
533 else:
534 return value * (base / dst_base)
536 def err(msg):
537 print >>sys.stderr, "Error:", msg
540 def get_single_vm(dom):
541 uuids = server.xenapi.VM.get_by_name_label(dom)
542 n = len(uuids)
543 if n == 1:
544 return uuids[0]
545 else:
546 dominfo = server.xend.domain(dom, False)
547 return dominfo['uuid']
549 ##
550 #
551 # Xen-API Shell
552 #
553 ##
555 class Shell(cmd.Cmd):
556 def __init__(self):
557 cmd.Cmd.__init__(self)
558 self.prompt = "xm> "
559 if serverType == SERVER_XEN_API:
560 res = server.xenapi._UNSUPPORTED_list_all_methods()
561 for f in res:
562 setattr(Shell, 'do_' + f + ' ', self.default)
564 def preloop(self):
565 cmd.Cmd.preloop(self)
566 readline.set_completer_delims(' ')
568 def default(self, line):
569 words = shlex.split(line)
570 if len(words) > 0 and words[0] == 'xm':
571 words = words[1:]
572 if len(words) > 0:
573 cmd = xm_lookup_cmd(words[0])
574 if cmd:
575 _run_cmd(cmd, words[0], words[1:])
576 elif serverType == SERVER_XEN_API:
577 ok, res = _run_cmd(lambda x: server.xenapi_request(words[0],
578 tuple(x)),
579 words[0], words[1:])
580 if ok and res is not None and res != '':
581 pprint.pprint(res)
582 else:
583 print '*** Unknown command: %s' % words[0]
584 return False
586 def completedefault(self, text, line, begidx, endidx):
587 words = shlex.split(line[:begidx])
588 clas, func = words[0].split('.')
589 if len(words) > 1 or \
590 func.startswith('get_by_') or \
591 func == 'get_all':
592 return []
593 uuids = server.xenapi_request('%s.get_all' % clas, ())
594 return [u + " " for u in uuids if u.startswith(text)]
596 def emptyline(self):
597 pass
599 def do_EOF(self, line):
600 print
601 sys.exit(0)
603 def do_help(self, line):
604 _usage(line)
607 def xm_shell(args):
608 Shell().cmdloop('The Xen Master. Type "help" for a list of functions.')
611 #########################################################################
612 #
613 # Main xm functions
614 #
615 #########################################################################
617 def xm_save(args):
618 arg_check(args, "save", 2, 3)
620 try:
621 (options, params) = getopt.gnu_getopt(args, 'c', ['checkpoint'])
622 except getopt.GetoptError, opterr:
623 err(opterr)
624 sys.exit(1)
626 checkpoint = False
627 for (k, v) in options:
628 if k in ['-c', '--checkpoint']:
629 checkpoint = True
631 if len(params) != 2:
632 err("Wrong number of parameters")
633 usage('save')
634 sys.exit(1)
636 try:
637 dominfo = parse_doms_info(server.xend.domain(params[0]))
638 except xmlrpclib.Fault, ex:
639 raise ex
641 domid = dominfo['domid']
642 savefile = os.path.abspath(params[1])
644 if not os.access(os.path.dirname(savefile), os.W_OK):
645 err("xm save: Unable to create file %s" % savefile)
646 sys.exit(1)
648 server.xend.domain.save(domid, savefile, checkpoint)
650 def xm_restore(args):
651 arg_check(args, "restore", 1, 2)
653 try:
654 (options, params) = getopt.gnu_getopt(args, 'p', ['paused'])
655 except getopt.GetoptError, opterr:
656 err(opterr)
657 usage('restore')
659 paused = False
660 for (k, v) in options:
661 if k in ['-p', '--paused']:
662 paused = True
664 if len(params) != 1:
665 err("Wrong number of parameters")
666 usage('restore')
668 savefile = os.path.abspath(params[0])
670 if not os.access(savefile, os.R_OK):
671 err("xm restore: Unable to read file %s" % savefile)
672 sys.exit(1)
674 server.xend.domain.restore(savefile, paused)
677 def getDomains(domain_names, state, full = 0):
678 if domain_names:
679 return [server.xend.domain(dom, full) for dom in domain_names]
680 else:
681 return server.xend.domains_with_state(True, state, full)
684 def xm_list(args):
685 use_long = 0
686 show_vcpus = 0
687 show_labels = 0
688 state = 'all'
689 try:
690 (options, params) = getopt.gnu_getopt(args, 'lv',
691 ['long','vcpus','label',
692 'state='])
693 except getopt.GetoptError, opterr:
694 err(opterr)
695 usage('list')
697 for (k, v) in options:
698 if k in ['-l', '--long']:
699 use_long = 1
700 if k in ['-v', '--vcpus']:
701 show_vcpus = 1
702 if k in ['--label']:
703 show_labels = 1
704 if k in ['--state']:
705 state = v
707 if state != 'all' and len(params) > 0:
708 raise OptionError(
709 "You may specify either a state or a particular VM, but not both")
711 if show_vcpus:
712 print >>sys.stderr, (
713 "xm list -v is deprecated. Please use xm vcpu-list.")
714 xm_vcpu_list(params)
715 return
717 doms = getDomains(params, state, use_long)
719 if use_long:
720 map(PrettyPrint.prettyprint, doms)
721 elif show_labels:
722 xm_label_list(doms)
723 else:
724 xm_brief_list(doms)
727 def parse_doms_info(info):
728 def get_info(n, t, d):
729 return t(sxp.child_value(info, n, d))
731 def get_status(n, t, d):
732 return DOM_STATES[t(sxp.child_value(info, n, d))]
734 start_time = get_info('start_time', float, -1)
735 if start_time == -1:
736 up_time = float(-1)
737 else:
738 up_time = time.time() - start_time
740 return {
741 'domid' : get_info('domid', str, ''),
742 'name' : get_info('name', str, '??'),
743 'mem' : get_info('memory_dynamic_min', int, 0),
744 'state' : get_info('state', str, ''),
745 'cpu_time' : get_info('cpu_time', float, 0.0),
746 # VCPUs is the number online when the VM is up, or the number
747 # configured otherwise.
748 'vcpus' : get_info('online_vcpus', int,
749 get_info('vcpus', int, 0)),
750 'up_time' : up_time,
751 'seclabel' : security.get_security_printlabel(info),
752 }
754 def check_sched_type(sched):
755 if serverType == SERVER_XEN_API:
756 current = server.xenapi.host.get_sched_policy(server.xenapi.session.get_this_host())
757 else:
758 current = 'unknown'
759 for x in server.xend.node.info()[1:]:
760 if len(x) > 1 and x[0] == 'xen_scheduler':
761 current = x[1]
762 break
763 if sched != current:
764 err("Xen is running with the %s scheduler" % current)
765 sys.exit(1)
767 def parse_sedf_info(info):
768 def get_info(n, t, d):
769 return t(sxp.child_value(info, n, d))
771 return {
772 'domid' : get_info('domid', int, -1),
773 'period' : get_info('period', int, -1),
774 'slice' : get_info('slice', int, -1),
775 'latency' : get_info('latency', int, -1),
776 'extratime': get_info('extratime', int, -1),
777 'weight' : get_info('weight', int, -1),
778 }
780 def domid_match(domid, info):
781 return domid is None or domid == info['name'] or \
782 domid == str(info['domid'])
784 def xm_brief_list(doms):
785 print '%-40s %3s %5s %5s %10s %9s' % \
786 ('Name', 'ID', 'Mem', 'VCPUs', 'State', 'Time(s)')
788 format = "%(name)-40s %(domid)3s %(mem)5d %(vcpus)5d %(state)10s " \
789 "%(cpu_time)8.1f"
791 for dom in doms:
792 d = parse_doms_info(dom)
793 print format % d
795 def xm_label_list(doms):
796 print '%-32s %3s %5s %5s %5s %9s %-8s' % \
797 ('Name', 'ID', 'Mem', 'VCPUs', 'State', 'Time(s)', 'Label')
799 output = []
800 format = '%(name)-32s %(domid)3s %(mem)5d %(vcpus)5d %(state)10s ' \
801 '%(cpu_time)8.1f %(seclabel)9s'
803 for dom in doms:
804 d = parse_doms_info(dom)
805 if security.active_policy not in ['INACTIVE', 'NULL', 'DEFAULT']:
806 if not d['seclabel']:
807 d['seclabel'] = 'ERROR'
808 elif security.active_policy in ['DEFAULT']:
809 d['seclabel'] = 'DEFAULT'
810 else:
811 d['seclabel'] = 'INACTIVE'
812 output.append((format % d, d['seclabel']))
814 #sort by labels
815 output.sort(lambda x,y: cmp( x[1].lower(), y[1].lower()))
816 for line, label in output:
817 print line
820 def xm_vcpu_list(args):
822 if args:
823 dominfo = map(server.xend.domain.getVCPUInfo, args)
824 else:
825 doms = server.xend.domains(False)
826 dominfo = map(server.xend.domain.getVCPUInfo, doms)
828 print '%-32s %3s %5s %5s %5s %9s %s' % \
829 ('Name', 'ID', 'VCPU', 'CPU', 'State', 'Time(s)', 'CPU Affinity')
831 format = '%(name)-32s %(domid)3d %(number)5d %(c)5s %(s)5s ' \
832 ' %(cpu_time)8.1f %(cpumap)s'
834 for dom in dominfo:
835 def get_info(n):
836 return sxp.child_value(dom, n)
838 #
839 # convert a list of integers into a list of pairs indicating
840 # continuous sequences in the list:
841 #
842 # [0,1,2,3] -> [(0,3)]
843 # [1,2,4,5] -> [(1,2),(4,5)]
844 # [0] -> [(0,0)]
845 # [0,1,4,6,7] -> [(0,1),(4,4),(6,7)]
846 #
847 def list_to_rangepairs(cmap):
848 cmap.sort()
849 pairs = []
850 x = y = 0
851 for i in range(0,len(cmap)):
852 try:
853 if ((cmap[y+1] - cmap[i]) > 1):
854 pairs.append((cmap[x],cmap[y]))
855 x = y = i+1
856 else:
857 y = y + 1
858 # if we go off the end, then just add x to y
859 except IndexError:
860 pairs.append((cmap[x],cmap[y]))
862 return pairs
864 #
865 # Convert pairs to range string, e.g: [(1,2),(3,3),(5,7)] -> 1-2,3,5-7
866 #
867 def format_pairs(pairs):
868 if not pairs:
869 return "no cpus"
870 out = ""
871 for f,s in pairs:
872 if (f==s):
873 out += '%d'%f
874 else:
875 out += '%d-%d'%(f,s)
876 out += ','
877 # trim trailing ','
878 return out[:-1]
880 def format_cpumap(cpumap):
881 cpumap = map(lambda x: int(x), cpumap)
882 cpumap.sort()
884 for x in server.xend.node.info()[1:]:
885 if len(x) > 1 and x[0] == 'nr_cpus':
886 nr_cpus = int(x[1])
887 # normalize cpumap by modulus nr_cpus, and drop duplicates
888 cpumap = dict.fromkeys(
889 map(lambda x: x % nr_cpus, cpumap)).keys()
890 if len(cpumap) == nr_cpus:
891 return "any cpu"
892 break
894 return format_pairs(list_to_rangepairs(cpumap))
896 name = get_info('name')
897 domid = int(get_info('domid'))
899 for vcpu in sxp.children(dom, 'vcpu'):
900 def vinfo(n, t):
901 return t(sxp.child_value(vcpu, n))
903 number = vinfo('number', int)
904 cpu = vinfo('cpu', int)
905 cpumap = format_cpumap(vinfo('cpumap', list))
906 online = vinfo('online', int)
907 cpu_time = vinfo('cpu_time', float)
908 running = vinfo('running', int)
909 blocked = vinfo('blocked', int)
911 if online:
912 c = str(cpu)
913 if running:
914 s = 'r'
915 else:
916 s = '-'
917 if blocked:
918 s += 'b'
919 else:
920 s += '-'
921 s += '-'
922 else:
923 c = "-"
924 s = "--p"
926 print format % locals()
928 def xm_start(args):
929 arg_check(args, "start", 1, 2)
931 try:
932 (options, params) = getopt.gnu_getopt(args, 'p', ['paused'])
933 except getopt.GetoptError, opterr:
934 err(opterr)
935 usage('start')
937 paused = False
938 for (k, v) in options:
939 if k in ['-p', '--paused']:
940 paused = True
942 if len(params) != 1:
943 err("Wrong number of parameters")
944 usage('start')
946 dom = params[0]
947 if serverType == SERVER_XEN_API:
948 server.xenapi.VM.start(get_single_vm(dom), paused)
949 else:
950 server.xend.domain.start(dom, paused)
952 def xm_delete(args):
953 arg_check(args, "delete", 1)
954 dom = args[0]
955 if serverType == SERVER_XEN_API:
956 server.xenapi.VM.destroy(get_single_vm(dom))
957 else:
958 server.xend.domain.delete(dom)
960 def xm_suspend(args):
961 arg_check(args, "suspend", 1)
962 dom = args[0]
963 if serverType == SERVER_XEN_API:
964 server.xenapi.VM.suspend(get_single_vm(dom))
965 else:
966 server.xend.domain.suspend(dom)
968 def xm_resume(args):
969 arg_check(args, "resume", 1, 2)
971 try:
972 (options, params) = getopt.gnu_getopt(args, 'p', ['paused'])
973 except getopt.GetoptError, opterr:
974 err(opterr)
975 usage('resume')
977 paused = False
978 for (k, v) in options:
979 if k in ['-p', '--paused']:
980 paused = True
982 if len(params) != 1:
983 err("Wrong number of parameters")
984 usage('resume')
986 dom = params[0]
987 if serverType == SERVER_XEN_API:
988 server.xenapi.VM.resume(get_single_vm(dom), paused)
989 else:
990 server.xend.domain.resume(dom, paused)
992 def xm_reboot(args):
993 arg_check(args, "reboot", 1, 3)
994 from xen.xm import shutdown
995 shutdown.main(["shutdown", "-R"] + args)
997 def xm_shutdown(args):
998 arg_check(args, "shutdown", 1, 4)
999 from xen.xm import shutdown
1000 shutdown.main(["shutdown"] + args)
1002 def xm_pause(args):
1003 arg_check(args, "pause", 1)
1004 dom = args[0]
1006 if serverType == SERVER_XEN_API:
1007 server.xenapi.VM.pause(get_single_vm(dom))
1008 else:
1009 server.xend.domain.pause(dom)
1011 def xm_unpause(args):
1012 arg_check(args, "unpause", 1)
1013 dom = args[0]
1015 if serverType == SERVER_XEN_API:
1016 server.xenapi.VM.unpause(get_single_vm(dom))
1017 else:
1018 server.xend.domain.unpause(dom)
1020 def xm_dump_core(args):
1021 live = False
1022 crash = False
1023 try:
1024 (options, params) = getopt.gnu_getopt(args, 'LC', ['live','crash'])
1025 for (k, v) in options:
1026 if k in ('-L', '--live'):
1027 live = True
1028 if k in ('-C', '--crash'):
1029 crash = True
1031 if len(params) not in (1, 2):
1032 raise OptionError("Expects 1 or 2 argument(s)")
1033 except getopt.GetoptError, e:
1034 raise OptionError(str(e))
1036 dom = params[0]
1037 if len(params) == 2:
1038 filename = os.path.abspath(params[1])
1039 else:
1040 filename = None
1042 if not live:
1043 server.xend.domain.pause(dom)
1045 try:
1046 print "Dumping core of domain: %s ..." % str(dom)
1047 server.xend.domain.dump(dom, filename, live, crash)
1048 finally:
1049 if not live:
1050 server.xend.domain.unpause(dom)
1052 if crash:
1053 print "Destroying domain: %s ..." % str(dom)
1054 server.xend.domain.destroy(dom)
1056 def xm_rename(args):
1057 arg_check(args, "rename", 2)
1059 if serverType == SERVER_XEN_API:
1060 server.xenapi.VM.set_name_label(get_single_vm(args[0]), args[1])
1061 else:
1062 server.xend.domain.setName(args[0], args[1])
1064 def xm_importcommand(command, args):
1065 cmd = __import__(command, globals(), locals(), 'xen.xm')
1066 cmd.main([command] + args)
1069 #############################################################
1071 def xm_vcpu_pin(args):
1072 arg_check(args, "vcpu-pin", 3)
1074 def cpu_make_map(cpulist):
1075 cpus = []
1076 for c in cpulist.split(','):
1077 if c.find('-') != -1:
1078 (x,y) = c.split('-')
1079 for i in range(int(x),int(y)+1):
1080 cpus.append(int(i))
1081 else:
1082 # remove this element from the list
1083 if c[0] == '^':
1084 cpus = [x for x in cpus if x != int(c[1:])]
1085 else:
1086 cpus.append(int(c))
1087 cpus.sort()
1088 return cpus
1090 dom = args[0]
1091 vcpu = args[1]
1092 if args[2] == 'all':
1093 cpumap = cpu_make_map('0-63')
1094 else:
1095 cpumap = cpu_make_map(args[2])
1097 server.xend.domain.pincpu(dom, vcpu, cpumap)
1099 def xm_mem_max(args):
1100 arg_check(args, "mem-max", 2)
1102 dom = args[0]
1104 if serverType == SERVER_XEN_API:
1105 mem = int_unit(args[1], 'k') * 1024
1106 server.xenapi.VM.set_memory_static_max(get_single_vm(dom), mem)
1107 else:
1108 mem = int_unit(args[1], 'm')
1109 server.xend.domain.maxmem_set(dom, mem)
1111 def xm_mem_set(args):
1112 arg_check(args, "mem-set", 2)
1114 dom = args[0]
1116 if serverType == SERVER_XEN_API:
1117 mem_target = int_unit(args[1], 'k') * 1024
1118 server.xenapi.VM.set_memory_dynamic_max(get_single_vm(dom), mem_target)
1119 server.xenapi.VM.set_memory_dynamic_min(get_single_vm(dom), mem_target)
1120 else:
1121 mem_target = int_unit(args[1], 'm')
1122 server.xend.domain.setMemoryTarget(dom, mem_target)
1124 def xm_vcpu_set(args):
1125 arg_check(args, "vcpu-set", 2)
1127 dom = args[0]
1128 vcpus = int(args[1])
1130 if serverType == SERVER_XEN_API:
1131 server.xenapi.VM.set_vcpus_live(get_single_vm(dom), vcpus)
1132 else:
1133 server.xend.domain.setVCpuCount(dom, vcpus)
1135 def xm_destroy(args):
1136 arg_check(args, "destroy", 1)
1138 dom = args[0]
1140 if serverType == SERVER_XEN_API:
1141 server.xenapi.VM.hard_shutdown(get_single_vm(dom))
1142 else:
1143 server.xend.domain.destroy(dom)
1145 def xm_domid(args):
1146 arg_check(args, "domid", 1)
1148 name = args[0]
1150 if serverType == SERVER_XEN_API:
1151 print server.xenapi.VM.get_domid(get_single_vm(name))
1152 else:
1153 dom = server.xend.domain(name)
1154 print sxp.child_value(dom, 'domid')
1156 def xm_domname(args):
1157 arg_check(args, "domname", 1)
1159 name = args[0]
1161 if serverType == SERVER_XEN_API:
1162 print server.xenapi.VM.get_name_label(get_single_vm(name))
1163 else:
1164 dom = server.xend.domain(name)
1165 print sxp.child_value(dom, 'name')
1167 def xm_sched_sedf(args):
1168 def ns_to_ms(val):
1169 return float(val) * 0.000001
1171 def ms_to_ns(val):
1172 return (float(val) / 0.000001)
1174 def print_sedf(info):
1175 info['period'] = ns_to_ms(info['period'])
1176 info['slice'] = ns_to_ms(info['slice'])
1177 info['latency'] = ns_to_ms(info['latency'])
1178 print( ("%(name)-32s %(domid)3d %(period)9.1f %(slice)9.1f" +
1179 " %(latency)7.1f %(extratime)6d %(weight)6d") % info)
1181 check_sched_type('sedf')
1183 # we want to just display current info if no parameters are passed
1184 if len(args) == 0:
1185 domid = None
1186 else:
1187 # we expect at least a domain id (name or number)
1188 # and at most a domid up to 5 options with values
1189 arg_check(args, "sched-sedf", 1, 11)
1190 domid = args[0]
1191 # drop domid from args since get_opt doesn't recognize it
1192 args = args[1:]
1194 opts = {}
1195 try:
1196 (options, params) = getopt.gnu_getopt(args, 'p:s:l:e:w:',
1197 ['period=', 'slice=', 'latency=', 'extratime=', 'weight='])
1198 except getopt.GetoptError, opterr:
1199 err(opterr)
1200 usage('sched-sedf')
1202 # convert to nanoseconds if needed
1203 for (k, v) in options:
1204 if k in ['-p', '--period']:
1205 opts['period'] = ms_to_ns(v)
1206 elif k in ['-s', '--slice']:
1207 opts['slice'] = ms_to_ns(v)
1208 elif k in ['-l', '--latency']:
1209 opts['latency'] = ms_to_ns(v)
1210 elif k in ['-e', '--extratime']:
1211 opts['extratime'] = v
1212 elif k in ['-w', '--weight']:
1213 opts['weight'] = v
1215 doms = filter(lambda x : domid_match(domid, x),
1216 [parse_doms_info(dom)
1217 for dom in getDomains(None, 'running')])
1218 if domid is not None and doms == []:
1219 err("Domain '%s' does not exist." % domid)
1220 usage('sched-sedf')
1222 # print header if we aren't setting any parameters
1223 if len(opts.keys()) == 0:
1224 print '%-33s %-2s %-4s %-4s %-7s %-5s %-6s' % \
1225 ('Name','ID','Period(ms)', 'Slice(ms)', 'Lat(ms)',
1226 'Extra','Weight')
1228 for d in doms:
1229 # fetch current values so as not to clobber them
1230 try:
1231 sedf_raw = server.xend.domain.cpu_sedf_get(d['domid'])
1232 except xmlrpclib.Fault:
1233 # domain does not support sched-sedf?
1234 sedf_raw = {}
1236 sedf_info = parse_sedf_info(sedf_raw)
1237 sedf_info['name'] = d['name']
1238 # update values in case of call to set
1239 if len(opts.keys()) > 0:
1240 for k in opts.keys():
1241 sedf_info[k]=opts[k]
1243 # send the update, converting user input
1244 v = map(int, [sedf_info['period'], sedf_info['slice'],
1245 sedf_info['latency'],sedf_info['extratime'],
1246 sedf_info['weight']])
1247 rv = server.xend.domain.cpu_sedf_set(d['domid'], *v)
1248 if int(rv) != 0:
1249 err("Failed to set sedf parameters (rv=%d)."%(rv))
1251 # not setting values, display info
1252 else:
1253 print_sedf(sedf_info)
1255 def xm_sched_credit(args):
1256 """Get/Set options for Credit Scheduler."""
1258 check_sched_type('credit')
1260 try:
1261 opts, params = getopt.getopt(args, "d:w:c:",
1262 ["domain=", "weight=", "cap="])
1263 except getopt.GetoptError, opterr:
1264 err(opterr)
1265 usage('sched-credit')
1267 domid = None
1268 weight = None
1269 cap = None
1271 for o, a in opts:
1272 if o == "-d":
1273 domid = a
1274 elif o == "-w":
1275 weight = int(a)
1276 elif o == "-c":
1277 cap = int(a);
1279 doms = filter(lambda x : domid_match(domid, x),
1280 [parse_doms_info(dom)
1281 for dom in getDomains(None, 'running')])
1283 if weight is None and cap is None:
1284 if domid is not None and doms == []:
1285 err("Domain '%s' does not exist." % domid)
1286 usage('sched-credit')
1287 # print header if we aren't setting any parameters
1288 print '%-33s %-2s %-6s %-4s' % ('Name','ID','Weight','Cap')
1290 for d in doms:
1291 try:
1292 info = server.xend.domain.sched_credit_get(d['domid'])
1293 except xmlrpclib.Fault:
1294 # domain does not support sched-credit?
1295 info = {'weight': -1, 'cap': -1}
1297 info['name'] = d['name']
1298 info['domid'] = int(d['domid'])
1299 print( ("%(name)-32s %(domid)3d %(weight)6d %(cap)4d") % info)
1300 else:
1301 if domid is None:
1302 # place holder for system-wide scheduler parameters
1303 err("No domain given.")
1304 usage('sched-credit')
1306 result = server.xend.domain.sched_credit_set(domid, weight, cap)
1307 if result != 0:
1308 err(str(result))
1310 def xm_info(args):
1311 arg_check(args, "info", 0)
1313 if serverType == SERVER_XEN_API:
1315 # Need to fake out old style xm info as people rely on parsing it
1317 host_record = server.xenapi.host.get_record(
1318 server.xenapi.session.get_this_host())
1320 host_cpu_records = map(server.xenapi.host_cpu.get_record, host_record["host_CPUs"])
1322 host_metrics_record = server.xenapi.host_metrics.get_record(host_record["metrics"])
1324 info = {
1325 "host": host_record["name_label"],
1326 "release": host_record["software_version"]["release"],
1327 "version": host_record["software_version"]["version"],
1328 "machine": host_record["software_version"]["machine"],
1329 "nr_cpus": len(host_record["host_CPUs"]),
1330 "nr_nodes": host_record["cpu_configuration"]["nr_nodes"],
1331 "sockets_per_node": host_record["cpu_configuration"]["sockets_per_node"],
1332 "cores_per_socket": host_record["cpu_configuration"]["cores_per_socket"],
1333 "threads_per_core": host_record["cpu_configuration"]["threads_per_core"],
1334 "cpu_mhz": sum([int(host_cpu_record["speed"]) for host_cpu_record in host_cpu_records])
1335 / len(host_cpu_records),
1336 "hw_caps": host_cpu_records[0]["features"],
1337 "total_memory": int(host_metrics_record["memory_total"])/1024/1024,
1338 "free_memory": int(host_metrics_record["memory_free"])/1024/1024,
1339 "xen_major": host_record["software_version"]["xen_major"],
1340 "xen_minor": host_record["software_version"]["xen_minor"],
1341 "xen_extra": host_record["software_version"]["xen_extra"],
1342 "xen_caps": " ".join(host_record["capabilities"]),
1343 "xen_scheduler": host_record["sched_policy"],
1344 "xen_pagesize": host_record["other_config"]["xen_pagesize"],
1345 "platform_params": host_record["other_config"]["platform_params"],
1346 "xen_changeset": host_record["software_version"]["xen_changeset"],
1347 "cc_compiler": host_record["software_version"]["cc_compiler"],
1348 "cc_compile_by": host_record["software_version"]["cc_compile_by"],
1349 "cc_compile_domain": host_record["software_version"]["cc_compile_domain"],
1350 "cc_compile_date": host_record["software_version"]["cc_compile_date"],
1351 "xend_config_format":host_record["software_version"]["xend_config_format"]
1354 sorted = info.items()
1355 sorted.sort(lambda (x1,y1), (x2,y2): -cmp(x1,x2))
1357 for (k, v) in sorted:
1358 print "%-23s:" % k, v
1359 else:
1360 info = server.xend.node.info()
1361 for x in info[1:]:
1362 if len(x) < 2:
1363 print "%-23s: (none)" % x[0]
1364 else:
1365 print "%-23s:" % x[0], x[1]
1367 def xm_console(args):
1368 arg_check(args, "console", 1, 2)
1370 quiet = False;
1372 try:
1373 (options, params) = getopt.gnu_getopt(args, 'q', ['quiet'])
1374 except getopt.GetoptError, opterr:
1375 err(opterr)
1376 usage('console')
1378 for (k, v) in options:
1379 if k in ['-q', '--quiet']:
1380 quiet = True
1381 else:
1382 assert False
1384 if len(params) != 1:
1385 err('No domain given')
1386 usage('console')
1388 dom = params[0]
1390 try:
1391 if serverType == SERVER_XEN_API:
1392 domid = int(server.xenapi.VM.get_domid(get_single_vm(dom)))
1393 else:
1394 info = server.xend.domain(dom)
1395 domid = int(sxp.child_value(info, 'domid', '-1'))
1396 except:
1397 if quiet:
1398 sys.exit(1)
1399 else:
1400 raise
1402 if domid == -1:
1403 if quiet:
1404 sys.exit(1)
1405 else:
1406 raise xmlrpclib.Fault(0, "Domain '%s' is not started" % dom)
1408 console.execConsole(domid)
1411 def xm_uptime(args):
1412 short_mode = 0
1414 try:
1415 (options, params) = getopt.gnu_getopt(args, 's', ['short'])
1416 except getopt.GetoptError, opterr:
1417 err(opterr)
1418 usage('uptime')
1420 for (k, v) in options:
1421 if k in ['-s', '--short']:
1422 short_mode = 1
1424 doms = getDomains(params, 'running')
1426 if short_mode == 0:
1427 print 'Name ID Uptime'
1429 for dom in doms:
1430 d = parse_doms_info(dom)
1431 if int(d['domid']) > 0:
1432 uptime = int(round(d['up_time']))
1433 else:
1434 f=open('/proc/uptime', 'r')
1435 upfile = f.read()
1436 uptime = int(round(float(upfile.split(' ')[0])))
1437 f.close()
1439 days = int(uptime / 86400)
1440 uptime -= (days * 86400)
1441 hours = int(uptime / 3600)
1442 uptime -= (hours * 3600)
1443 minutes = int(uptime / 60)
1444 uptime -= (minutes * 60)
1445 seconds = uptime
1447 upstring = ""
1448 if days > 0:
1449 upstring += str(days) + " day"
1450 if days > 1:
1451 upstring += "s"
1452 upstring += ", "
1453 upstring += '%(hours)2d:%(minutes)02d' % vars()
1455 if short_mode:
1456 now = datetime.datetime.now()
1457 upstring = now.strftime(" %H:%M:%S") + " up " + upstring
1458 upstring += ", " + d['name'] + " (" + d['domid'] + ")"
1459 else:
1460 upstring += ':%(seconds)02d' % vars()
1461 upstring = ("%(name)-32s %(domid)3s " % d) + upstring
1463 print upstring
1465 def xm_sysrq(args):
1466 arg_check(args, "sysrq", 2)
1467 dom = args[0]
1468 req = args[1]
1469 if serverType == SERVER_XEN_API:
1470 server.xenapi.VM.send_sysrq(get_single_vm(dom), req)
1471 else:
1472 server.xend.domain.send_sysrq(dom, req)
1474 def xm_trigger(args):
1475 vcpu = 0
1477 arg_check(args, "trigger", 2, 3)
1478 dom = args[0]
1479 trigger = args[1]
1480 if len(args) == 3:
1481 vcpu = int(args[2])
1483 server.xend.domain.send_trigger(dom, trigger, vcpu)
1485 def xm_debug_keys(args):
1486 arg_check(args, "debug-keys", 1)
1487 server.xend.node.send_debug_keys(str(args[0]))
1489 def xm_top(args):
1490 arg_check(args, "top", 0)
1492 os.execvp('xentop', ['xentop'])
1494 def xm_dmesg(args):
1495 arg_check(args, "dmesg", 0, 1)
1497 try:
1498 (options, params) = getopt.gnu_getopt(args, 'c', ['clear'])
1499 except getopt.GetoptError, opterr:
1500 err(opterr)
1501 usage('dmesg')
1503 use_clear = 0
1504 for (k, v) in options:
1505 if k in ['-c', '--clear']:
1506 use_clear = 1
1508 if len(params) :
1509 err("No parameter required")
1510 usage('dmesg')
1512 if serverType == SERVER_XEN_API:
1513 if not use_clear:
1514 print server.xenapi.host.dmesg(
1515 server.xenapi.session.get_this_host(),0)
1516 else:
1517 server.xenapi.host.dmesg(
1518 server.xenapi.session.get_this_host(),1)
1519 else:
1520 if not use_clear:
1521 print server.xend.node.dmesg.info()
1522 else:
1523 server.xend.node.dmesg.clear()
1525 def xm_log(args):
1526 arg_check(args, "log", 0)
1528 if serverType == SERVER_XEN_API:
1529 print server.xenapi.host.get_log(
1530 server.xenapi.session.get_this_host())
1531 else:
1532 print server.xend.node.log()
1534 def xm_serve(args):
1535 if serverType == SERVER_XEN_API:
1536 print "Not supported with XenAPI"
1537 sys.exit(-1)
1539 arg_check(args, "serve", 0)
1541 from fcntl import fcntl, F_SETFL
1543 s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
1544 s.connect(XendClient.XML_RPC_SOCKET)
1545 fcntl(sys.stdin, F_SETFL, os.O_NONBLOCK)
1547 while True:
1548 iwtd, owtd, ewtd = select([sys.stdin, s], [], [])
1549 if s in iwtd:
1550 data = s.recv(4096)
1551 if len(data) > 0:
1552 sys.stdout.write(data)
1553 sys.stdout.flush()
1554 else:
1555 break
1556 if sys.stdin in iwtd:
1557 data = sys.stdin.read(4096)
1558 if len(data) > 0:
1559 s.sendall(data)
1560 else:
1561 break
1562 s.close()
1564 def parse_dev_info(info):
1565 def get_info(n, t, d):
1566 i = 0
1567 while i < len(info):
1568 if (info[i][0] == n):
1569 return t(info[i][1])
1570 i = i + 1
1571 return t(d)
1572 return {
1573 #common
1574 'backend-id' : get_info('backend-id', int, -1),
1575 'handle' : get_info('handle', int, 0),
1576 'state' : get_info('state', int, -1),
1577 'be-path' : get_info('backend', str, '??'),
1578 'event-ch' : get_info('event-channel',int, -1),
1579 #network specific
1580 'virtual-device' : get_info('virtual-device', str, '??'),
1581 'tx-ring-ref': get_info('tx-ring-ref', int, -1),
1582 'rx-ring-ref': get_info('rx-ring-ref', int, -1),
1583 'mac' : get_info('mac', str, '??'),
1584 #block-device specific
1585 'ring-ref' : get_info('ring-ref', int, -1),
1588 def arg_check_for_resource_list(args, name):
1589 use_long = 0
1590 try:
1591 (options, params) = getopt.gnu_getopt(args, 'l', ['long'])
1592 except getopt.GetoptError, opterr:
1593 err(opterr)
1594 sys.exit(1)
1596 for (k, v) in options:
1597 if k in ['-l', '--long']:
1598 use_long = 1
1600 if len(params) == 0:
1601 print 'No domain parameter given'
1602 usage(name)
1603 if len(params) > 1:
1604 print 'No multiple domain parameters allowed'
1605 usage(name)
1607 return (use_long, params)
1609 def xm_network_list(args):
1610 (use_long, params) = arg_check_for_resource_list(args, "network-list")
1612 dom = params[0]
1613 if use_long:
1614 devs = server.xend.domain.getDeviceSxprs(dom, 'vif')
1615 map(PrettyPrint.prettyprint, devs)
1616 else:
1617 hdr = 0
1618 for x in server.xend.domain.getDeviceSxprs(dom, 'vif'):
1619 if hdr == 0:
1620 print 'Idx BE MAC Addr. handle state evt-ch tx-/rx-ring-ref BE-path'
1621 hdr = 1
1622 ni = parse_dev_info(x[1])
1623 ni['idx'] = int(x[0])
1624 print ("%(idx)-3d "
1625 "%(backend-id)-3d"
1626 "%(mac)-17s "
1627 "%(handle)-3d "
1628 "%(state)-3d "
1629 "%(event-ch)-3d "
1630 "%(tx-ring-ref)-5d/%(rx-ring-ref)-5d "
1631 "%(be-path)-30s "
1632 % ni)
1634 def xm_block_list(args):
1635 (use_long, params) = arg_check_for_resource_list(args, "block-list")
1637 dom = params[0]
1638 if use_long:
1639 devs = server.xend.domain.getDeviceSxprs(dom, 'vbd')
1640 map(PrettyPrint.prettyprint, devs)
1641 else:
1642 hdr = 0
1643 for x in server.xend.domain.getDeviceSxprs(dom, 'vbd'):
1644 if hdr == 0:
1645 print 'Vdev BE handle state evt-ch ring-ref BE-path'
1646 hdr = 1
1647 ni = parse_dev_info(x[1])
1648 ni['idx'] = int(x[0])
1649 print ("%(idx)-3d "
1650 "%(backend-id)-3d "
1651 "%(handle)-3d "
1652 "%(state)-3d "
1653 "%(event-ch)-3d "
1654 "%(ring-ref)-5d "
1655 "%(be-path)-30s "
1656 % ni)
1658 def xm_vtpm_list(args):
1659 (use_long, params) = arg_check_for_resource_list(args, "vtpm-list")
1661 dom = params[0]
1662 if use_long:
1663 devs = server.xend.domain.getDeviceSxprs(dom, 'vtpm')
1664 map(PrettyPrint.prettyprint, devs)
1665 else:
1666 hdr = 0
1667 for x in server.xend.domain.getDeviceSxprs(dom, 'vtpm'):
1668 if hdr == 0:
1669 print 'Idx BE handle state evt-ch ring-ref BE-path'
1670 hdr = 1
1671 ni = parse_dev_info(x[1])
1672 ni['idx'] = int(x[0])
1673 print ("%(idx)-3d "
1674 "%(backend-id)-3d "
1675 "%(handle)-3d "
1676 "%(state)-3d "
1677 "%(event-ch)-3d "
1678 "%(ring-ref)-5d "
1679 "%(be-path)-30s "
1680 % ni)
1683 def parse_block_configuration(args):
1684 dom = args[0]
1686 if args[1].startswith('tap:'):
1687 cls = 'tap'
1688 else:
1689 cls = 'vbd'
1691 vbd = [cls,
1692 ['uname', args[1]],
1693 ['dev', args[2]],
1694 ['mode', args[3]]]
1695 if len(args) == 5:
1696 vbd.append(['backend', args[4]])
1698 # verify that policy permits attaching this resource
1699 if security.on():
1700 dominfo = server.xend.domain(dom)
1701 label = security.get_security_printlabel(dominfo)
1702 else:
1703 label = None
1704 security.res_security_check(args[1], label)
1706 return (dom, vbd)
1709 def xm_block_attach(args):
1710 arg_check(args, 'block-attach', 4, 5)
1712 (dom, vbd) = parse_block_configuration(args)
1713 server.xend.domain.device_create(dom, vbd)
1716 def xm_block_configure(args):
1717 arg_check(args, 'block-configure', 4, 5)
1719 (dom, vbd) = parse_block_configuration(args)
1720 server.xend.domain.device_configure(dom, vbd)
1723 def xm_network_attach(args):
1724 arg_check(args, 'network-attach', 1, 10)
1726 dom = args[0]
1727 vif = ['vif']
1728 vif_params = ['type', 'mac', 'bridge', 'ip', 'script', \
1729 'backend', 'vifname', 'rate', 'model']
1731 for a in args[1:]:
1732 vif_param = a.split("=")
1733 if len(vif_param) != 2 or vif_param[1] == '' or \
1734 vif_param[0] not in vif_params:
1735 err("Invalid argument: %s" % a)
1736 usage('network-attach')
1737 vif.append(vif_param)
1739 server.xend.domain.device_create(dom, vif)
1742 def detach(args, command, deviceClass):
1743 arg_check(args, command, 2, 3)
1745 dom = args[0]
1746 dev = args[1]
1747 try:
1748 force = args[2]
1749 if (force != "--force") and (force != "-f"):
1750 print "Ignoring option %s"%(force)
1751 force = None
1752 except IndexError:
1753 force = None
1755 server.xend.domain.destroyDevice(dom, deviceClass, dev, force)
1758 def xm_block_detach(args):
1759 try:
1760 detach(args, 'block-detach', 'vbd')
1761 return
1762 except:
1763 pass
1764 detach(args, 'block-detach', 'tap')
1767 def xm_network_detach(args):
1768 detach(args, 'network-detach', 'vif')
1771 def xm_vnet_list(args):
1772 try:
1773 (options, params) = getopt.gnu_getopt(args, 'l', ['long'])
1774 except getopt.GetoptError, opterr:
1775 err(opterr)
1776 usage('vnet-list')
1778 use_long = 0
1779 for (k, v) in options:
1780 if k in ['-l', '--long']:
1781 use_long = 1
1783 if params:
1784 use_long = 1
1785 vnets = params
1786 else:
1787 vnets = server.xend_vnets()
1789 for vnet in vnets:
1790 try:
1791 if use_long:
1792 info = server.xend_vnet(vnet)
1793 PrettyPrint.prettyprint(info)
1794 else:
1795 print vnet
1796 except Exception, ex:
1797 print vnet, ex
1799 def xm_vnet_create(args):
1800 arg_check(args, "vnet-create", 1)
1801 conf = args[0]
1802 if not os.access(conf, os.R_OK):
1803 print "File not found: %s" % conf
1804 sys.exit(1)
1806 server.xend_vnet_create(conf)
1808 def xm_vnet_delete(args):
1809 arg_check(args, "vnet-delete", 1)
1810 vnet = args[0]
1811 server.xend_vnet_delete(vnet)
1813 commands = {
1814 "shell": xm_shell,
1815 # console commands
1816 "console": xm_console,
1817 # xenstat commands
1818 "top": xm_top,
1819 # domain commands
1820 "delete": xm_delete,
1821 "destroy": xm_destroy,
1822 "domid": xm_domid,
1823 "domname": xm_domname,
1824 "dump-core": xm_dump_core,
1825 "reboot": xm_reboot,
1826 "rename": xm_rename,
1827 "restore": xm_restore,
1828 "resume": xm_resume,
1829 "save": xm_save,
1830 "shutdown": xm_shutdown,
1831 "start": xm_start,
1832 "sysrq": xm_sysrq,
1833 "trigger": xm_trigger,
1834 "uptime": xm_uptime,
1835 "suspend": xm_suspend,
1836 "list": xm_list,
1837 # memory commands
1838 "mem-max": xm_mem_max,
1839 "mem-set": xm_mem_set,
1840 # cpu commands
1841 "vcpu-pin": xm_vcpu_pin,
1842 "vcpu-list": xm_vcpu_list,
1843 "vcpu-set": xm_vcpu_set,
1844 # special
1845 "pause": xm_pause,
1846 "unpause": xm_unpause,
1847 # host commands
1848 "debug-keys": xm_debug_keys,
1849 "dmesg": xm_dmesg,
1850 "info": xm_info,
1851 "log": xm_log,
1852 "serve": xm_serve,
1853 # scheduler
1854 "sched-sedf": xm_sched_sedf,
1855 "sched-credit": xm_sched_credit,
1856 # block
1857 "block-attach": xm_block_attach,
1858 "block-detach": xm_block_detach,
1859 "block-list": xm_block_list,
1860 "block-configure": xm_block_configure,
1861 # network
1862 "network-attach": xm_network_attach,
1863 "network-detach": xm_network_detach,
1864 "network-list": xm_network_list,
1865 # vnet
1866 "vnet-list": xm_vnet_list,
1867 "vnet-create": xm_vnet_create,
1868 "vnet-delete": xm_vnet_delete,
1869 # vtpm
1870 "vtpm-list": xm_vtpm_list,
1873 ## The commands supported by a separate argument parser in xend.xm.
1874 IMPORTED_COMMANDS = [
1875 'create',
1876 'new',
1877 'migrate',
1878 'labels',
1879 'cfgbootpolicy',
1880 'makepolicy',
1881 'loadpolicy',
1882 'dumppolicy',
1883 'addlabel',
1884 'rmlabel',
1885 'getlabel',
1886 'dry-run',
1887 'resources',
1890 for c in IMPORTED_COMMANDS:
1891 commands[c] = eval('lambda args: xm_importcommand("%s", args)' % c)
1893 aliases = {
1894 "balloon": "mem-set",
1895 "set-vcpus": "vcpu-set",
1896 "vif-list": "network-list",
1897 "vbd-create": "block-attach",
1898 "vbd-destroy": "block-detach",
1899 "vbd-list": "block-list",
1903 def xm_lookup_cmd(cmd):
1904 if commands.has_key(cmd):
1905 return commands[cmd]
1906 elif aliases.has_key(cmd):
1907 deprecated(cmd,aliases[cmd])
1908 return commands[aliases[cmd]]
1909 elif cmd == 'help':
1910 longHelp()
1911 sys.exit(0)
1912 else:
1913 # simulate getopt's prefix matching behaviour
1914 if len(cmd) > 1:
1915 same_prefix_cmds = [commands[c] for c in commands.keys() \
1916 if c[:len(cmd)] == cmd]
1917 # only execute if there is only 1 match
1918 if len(same_prefix_cmds) == 1:
1919 return same_prefix_cmds[0]
1920 return None
1922 def deprecated(old,new):
1923 print >>sys.stderr, (
1924 "Command %s is deprecated. Please use xm %s instead." % (old, new))
1926 def main(argv=sys.argv):
1927 if len(argv) < 2:
1928 usage()
1930 # intercept --help(-h) and output our own help
1931 for help in ['--help', '-h']:
1932 if help in argv[1:]:
1933 if help == argv[1]:
1934 longHelp()
1935 sys.exit(0)
1936 else:
1937 usage(argv[1])
1939 cmd_name = argv[1]
1940 cmd = xm_lookup_cmd(cmd_name)
1941 if cmd:
1942 # strip off prog name and subcmd
1943 args = argv[2:]
1944 _, rc = _run_cmd(cmd, cmd_name, args)
1945 sys.exit(rc)
1946 else:
1947 err('Subcommand %s not found!' % cmd_name)
1948 usage()
1950 def _run_cmd(cmd, cmd_name, args):
1951 global server
1953 try:
1954 if server is None:
1955 if serverType == SERVER_XEN_API:
1956 server = XenAPI.Session(serverURI)
1957 username, password = parseAuthentication()
1958 server.login_with_password(username, password)
1959 def logout():
1960 try:
1961 server.xenapi.session.logout()
1962 except:
1963 pass
1964 atexit.register(logout)
1965 else:
1966 server = ServerProxy(serverURI)
1968 return True, cmd(args)
1969 except socket.error, ex:
1970 if os.geteuid() != 0:
1971 err("Most commands need root access. Please try again as root.")
1972 else:
1973 err("Unable to connect to xend: %s. Is xend running?" % ex[1])
1974 except KeyboardInterrupt:
1975 print "Interrupted."
1976 return True, ''
1977 except IOError, ex:
1978 if os.geteuid() != 0:
1979 err("Most commands need root access. Please try again as root.")
1980 else:
1981 err("Unable to connect to xend: %s." % ex[1])
1982 except SystemExit, code:
1983 return code == 0, code
1984 except XenAPI.Failure, exn:
1985 for line in [''] + wrap(str(exn), 80) + ['']:
1986 print >>sys.stderr, line
1987 except xmlrpclib.Fault, ex:
1988 if ex.faultCode == XendClient.ERROR_INVALID_DOMAIN:
1989 err("Domain '%s' does not exist." % ex.faultString)
1990 else:
1991 err(ex.faultString)
1992 _usage(cmd_name)
1993 except xmlrpclib.ProtocolError, ex:
1994 if ex.errcode == -1:
1995 print >>sys.stderr, (
1996 "Xend has probably crashed! Invalid or missing HTTP "
1997 "status code.")
1998 else:
1999 print >>sys.stderr, (
2000 "Xend has probably crashed! ProtocolError(%d, %s)." %
2001 (ex.errcode, ex.errmsg))
2002 except (ValueError, OverflowError):
2003 err("Invalid argument.")
2004 _usage(cmd_name)
2005 except OptionError, e:
2006 err(str(e))
2007 _usage(cmd_name)
2008 print e.usage
2009 except security.ACMError, e:
2010 err(str(e))
2011 except:
2012 print "Unexpected error:", sys.exc_info()[0]
2013 print
2014 print "Please report to xen-devel@lists.xensource.com"
2015 raise
2017 return False, 1
2019 if __name__ == "__main__":
2020 main()