direct-io.hg

view tools/python/xen/xm/main.py @ 14449:e2f302488983

Add VBD.runtime_properties dictionary, and use that to implement xm block-list
through the Xen-API. Implement xm block-attach and xm block-detach also.

Signed-off-by: Tom Wilkie <tom.wilkie@gmail.com>
author Ewan Mellor <ewan@xensource.com>
date Tue Mar 20 11:45:44 2007 +0000 (2007-03-20)
parents cfb265b93b2d
children d86957cea8b8
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 time
37 import datetime
38 from select import select
39 import xml.dom.minidom
41 import warnings
42 warnings.filterwarnings('ignore', category=FutureWarning)
44 from xen.xend import PrettyPrint
45 from xen.xend import sxp
46 from xen.xend import XendClient
47 from xen.xend.XendConstants import *
49 from xen.xm.opts import OptionError, Opts, wrap, set_true
50 from xen.xm import console
51 from xen.util.xmlrpclib2 import ServerProxy
53 import XenAPI
56 # getopt.gnu_getopt is better, but only exists in Python 2.3+. Use
57 # getopt.getopt if gnu_getopt is not available. This will mean that options
58 # may only be specified before positional arguments.
59 if not hasattr(getopt, 'gnu_getopt'):
60 getopt.gnu_getopt = getopt.getopt
62 XM_CONFIG_FILE_ENVVAR = 'XM_CONFIG_FILE'
63 XM_CONFIG_FILE_DEFAULT = '/etc/xen/xm-config.xml'
65 # Supported types of server
66 SERVER_LEGACY_XMLRPC = 'LegacyXMLRPC'
67 SERVER_XEN_API = 'Xen-API'
69 # General help message
71 USAGE_HELP = "Usage: xm <subcommand> [args]\n\n" \
72 "Control, list, and manipulate Xen guest instances.\n"
74 USAGE_FOOTER = '<Domain> can either be the Domain Name or Id.\n' \
75 'For more help on \'xm\' see the xm(1) man page.\n' \
76 'For more help on \'xm create\' see the xmdomain.cfg(5) '\
77 ' man page.\n'
79 # Help strings are indexed by subcommand name in this way:
80 # 'subcommand': (argstring, description)
82 SUBCOMMAND_HELP = {
83 # common commands
85 'shell' : ('', 'Launch an interactive shell.'),
87 'console' : ('[-q|--quiet] <Domain>',
88 'Attach to <Domain>\'s console.'),
89 'create' : ('<ConfigFile> [options] [vars]',
90 'Create a domain based on <ConfigFile>.'),
91 'destroy' : ('<Domain>',
92 'Terminate a domain immediately.'),
93 'help' : ('', 'Display this message.'),
94 'list' : ('[options] [Domain, ...]',
95 'List information about all/some domains.'),
96 'mem-max' : ('<Domain> <Mem>',
97 'Set the maximum amount reservation for a domain.'),
98 'mem-set' : ('<Domain> <Mem>',
99 'Set the current memory usage for a domain.'),
100 'migrate' : ('<Domain> <Host>',
101 'Migrate a domain to another machine.'),
102 'pause' : ('<Domain>', 'Pause execution of a domain.'),
103 'reboot' : ('<Domain> [-wa]', 'Reboot a domain.'),
104 'restore' : ('<CheckpointFile> [-p]',
105 'Restore a domain from a saved state.'),
106 'save' : ('[-c] <Domain> <CheckpointFile>',
107 'Save a domain state to restore later.'),
108 'shutdown' : ('<Domain> [-waRH]', 'Shutdown a domain.'),
109 'top' : ('', 'Monitor a host and the domains in real time.'),
110 'unpause' : ('<Domain>', 'Unpause a paused domain.'),
111 'uptime' : ('[-s] <Domain>', 'Print uptime for a domain.'),
113 # Life cycle xm commands
114 'new' : ('<ConfigFile> [options] [vars]',
115 'Adds a domain to Xend domain management'),
116 'delete' : ('<DomainName>',
117 'Remove a domain from Xend domain management.'),
118 'start' : ('<DomainName>', 'Start a Xend managed domain'),
119 'resume' : ('<DomainName>', 'Resume a Xend managed domain'),
120 'suspend' : ('<DomainName>', 'Suspend a Xend managed domain'),
122 # less used commands
124 'dmesg' : ('[-c|--clear]',
125 'Read and/or clear Xend\'s message buffer.'),
126 'domid' : ('<DomainName>', 'Convert a domain name to domain id.'),
127 'domname' : ('<DomId>', 'Convert a domain id to domain name.'),
128 'dump-core' : ('[-L|--live] [-C|--crash] <Domain> [Filename]',
129 'Dump core for a specific domain.'),
130 'info' : ('', 'Get information about Xen host.'),
131 'log' : ('', 'Print Xend log'),
132 'rename' : ('<Domain> <NewDomainName>', 'Rename a domain.'),
133 'sched-sedf' : ('<Domain> [options]', 'Get/set EDF parameters.'),
134 'sched-credit': ('[-d <Domain> [-w[=WEIGHT]|-c[=CAP]]]',
135 'Get/set credit scheduler parameters.'),
136 'sysrq' : ('<Domain> <letter>', 'Send a sysrq to a domain.'),
137 'debug-keys' : ('<Keys>', 'Send debug keys to Xen.'),
138 'trigger' : ('<Domain> <nmi|reset|init> [<VCPU>]',
139 'Send a trigger to a domain.'),
140 'vcpu-list' : ('[<Domain>]',
141 'List the VCPUs for a domain or all domains.'),
142 'vcpu-pin' : ('<Domain> <VCPU> <CPUs|all>',
143 'Set which CPUs a VCPU can use.'),
144 'vcpu-set' : ('<Domain> <vCPUs>',
145 'Set the number of active VCPUs for allowed for the'
146 ' domain.'),
148 # device commands
150 'block-attach' : ('<Domain> <BackDev> <FrontDev> <Mode> [BackDomain]',
151 'Create a new virtual block device.'),
152 'block-configure': ('<Domain> <BackDev> <FrontDev> <Mode> [BackDomain]',
153 'Change block device configuration'),
154 'block-detach' : ('<Domain> <DevId> [-f|--force]',
155 'Destroy a domain\'s virtual block device.'),
156 'block-list' : ('<Domain> [--long]',
157 'List virtual block devices for a domain.'),
158 'network-attach': ('<Domain> [type=<type>] [mac=<mac>] [bridge=<bridge>] '
159 '[ip=<ip>] [script=<script>] [backend=<BackDomain>] '
160 '[vifname=<name>] [rate=<rate>] [model=<model>]',
161 'Create a new virtual network device.'),
162 'network-detach': ('<Domain> <DevId> [-f|--force]',
163 'Destroy a domain\'s virtual network device.'),
164 'network-list' : ('<Domain> [--long]',
165 'List virtual network interfaces for a domain.'),
166 'vnet-create' : ('<ConfigFile>','Create a vnet from ConfigFile.'),
167 'vnet-delete' : ('<VnetId>', 'Delete a Vnet.'),
168 'vnet-list' : ('[-l|--long]', 'List Vnets.'),
169 'vtpm-list' : ('<Domain> [--long]', 'List virtual TPM devices.'),
171 # security
173 'addlabel' : ('<label> {dom <ConfigFile>|res <resource>} [<policy>]',
174 'Add security label to domain.'),
175 'rmlabel' : ('{dom <ConfigFile>|res <Resource>}',
176 'Remove a security label from domain.'),
177 'getlabel' : ('{dom <ConfigFile>|res <Resource>}',
178 'Show security label for domain or resource.'),
179 'dry-run' : ('<ConfigFile>',
180 'Test if a domain can access its resources.'),
181 'resources' : ('', 'Show info for each labeled resource.'),
182 'cfgbootpolicy' : ('<policy> [boot-title]',
183 'Add policy to boot configuration.'),
184 'dumppolicy' : ('', 'Print hypervisor ACM state information.'),
185 'loadpolicy' : ('<policy.bin>', 'Load binary policy into hypervisor.'),
186 'makepolicy' : ('<policy>', 'Build policy and create .bin/.map '
187 'files.'),
188 'labels' : ('[policy] [type=dom|res|any]',
189 'List <type> labels for (active) policy.'),
190 'serve' : ('', 'Proxy Xend XMLRPC over stdio.'),
191 }
193 SUBCOMMAND_OPTIONS = {
194 'sched-sedf': (
195 ('-p [MS]', '--period[=MS]', 'Relative deadline(ms)'),
196 ('-s [MS]', '--slice[=MS]' ,
197 'Worst-case execution time(ms). (slice < period)'),
198 ('-l [MS]', '--latency[=MS]',
199 'Scaled period (ms) when domain performs heavy I/O'),
200 ('-e [FLAG]', '--extra[=FLAG]',
201 'Flag (0 or 1) controls if domain can run in extra time.'),
202 ('-w [FLOAT]', '--weight[=FLOAT]',
203 'CPU Period/slice (do not set with --period/--slice)'),
204 ),
205 'sched-credit': (
206 ('-d DOMAIN', '--domain=DOMAIN', 'Domain to modify'),
207 ('-w WEIGHT', '--weight=WEIGHT', 'Weight (int)'),
208 ('-c CAP', '--cap=CAP', 'Cap (int)'),
209 ),
210 'list': (
211 ('-l', '--long', 'Output all VM details in SXP'),
212 ('', '--label', 'Include security labels'),
213 ('', '--state=<state>', 'Select only VMs with the specified state'),
214 ),
215 'console': (
216 ('-q', '--quiet', 'Do not print an error message if the domain does not exist'),
217 ),
218 'dmesg': (
219 ('-c', '--clear', 'Clear dmesg buffer'),
220 ),
221 'vnet-list': (
222 ('-l', '--long', 'List Vnets as SXP'),
223 ),
224 'network-list': (
225 ('-l', '--long', 'List resources as SXP'),
226 ),
227 'dump-core': (
228 ('-L', '--live', 'Dump core without pausing the domain'),
229 ('-C', '--crash', 'Crash domain after dumping core'),
230 ),
231 'start': (
232 ('-p', '--paused', 'Do not unpause domain after starting it'),
233 ),
234 'resume': (
235 ('-p', '--paused', 'Do not unpause domain after resuming it'),
236 ),
237 'save': (
238 ('-c', '--checkpoint', 'Leave domain running after creating snapshot'),
239 ),
240 'restore': (
241 ('-p', '--paused', 'Do not unpause domain after restoring it'),
242 ),
243 }
245 common_commands = [
246 "console",
247 "create",
248 "new",
249 "delete",
250 "destroy",
251 "dump-core",
252 "help",
253 "list",
254 "mem-set",
255 "migrate",
256 "pause",
257 "reboot",
258 "restore",
259 "resume",
260 "save",
261 "shell",
262 "shutdown",
263 "start",
264 "suspend",
265 "top",
266 "unpause",
267 "uptime",
268 "vcpu-set",
269 ]
271 domain_commands = [
272 "console",
273 "create",
274 "new",
275 "delete",
276 "destroy",
277 "domid",
278 "domname",
279 "dump-core",
280 "list",
281 "mem-max",
282 "mem-set",
283 "migrate",
284 "pause",
285 "reboot",
286 "rename",
287 "restore",
288 "resume",
289 "save",
290 "shutdown",
291 "start",
292 "suspend",
293 "sysrq",
294 "trigger",
295 "top",
296 "unpause",
297 "uptime",
298 "vcpu-list",
299 "vcpu-pin",
300 "vcpu-set",
301 ]
303 host_commands = [
304 "debug-keys",
305 "dmesg",
306 "info",
307 "log",
308 "serve",
309 ]
311 scheduler_commands = [
312 "sched-credit",
313 "sched-sedf",
314 ]
316 device_commands = [
317 "block-attach",
318 "block-detach",
319 "block-list",
320 "block-configure",
321 "network-attach",
322 "network-detach",
323 "network-list",
324 "vtpm-list",
325 ]
327 vnet_commands = [
328 "vnet-list",
329 "vnet-create",
330 "vnet-delete",
331 ]
333 acm_commands = [
334 "labels",
335 "addlabel",
336 "rmlabel",
337 "getlabel",
338 "dry-run",
339 "resources",
340 "makepolicy",
341 "loadpolicy",
342 "cfgbootpolicy",
343 "dumppolicy",
344 ]
346 all_commands = (domain_commands + host_commands + scheduler_commands +
347 device_commands + vnet_commands + acm_commands + ['shell'])
350 ##
351 # Configuration File Parsing
352 ##
354 xmConfigFile = os.getenv(XM_CONFIG_FILE_ENVVAR, XM_CONFIG_FILE_DEFAULT)
355 config = None
356 if os.path.isfile(xmConfigFile):
357 try:
358 config = xml.dom.minidom.parse(xmConfigFile)
359 except:
360 print >>sys.stderr, ('Ignoring invalid configuration file %s.' %
361 xmConfigFile)
363 def parseServer():
364 if config:
365 server = config.getElementsByTagName('server')
366 if server:
367 st = server[0].getAttribute('type')
368 if st != SERVER_XEN_API and st != SERVER_LEGACY_XMLRPC:
369 print >>sys.stderr, ('Invalid server type %s; using %s.' %
370 (st, SERVER_LEGACY_XMLRPC))
371 st = SERVER_LEGACY_XMLRPC
372 return (st, server[0].getAttribute('uri'))
374 return SERVER_LEGACY_XMLRPC, XendClient.uri
376 def parseAuthentication():
377 server = config.getElementsByTagName('server')[0]
378 return (server.getAttribute('username'),
379 server.getAttribute('password'))
381 serverType, serverURI = parseServer()
382 server = None
385 ####################################################################
386 #
387 # Help/usage printing functions
388 #
389 ####################################################################
391 def cmdHelp(cmd):
392 """Print help for a specific subcommand."""
394 for fc in SUBCOMMAND_HELP.keys():
395 if fc[:len(cmd)] == cmd:
396 cmd = fc
397 break
399 try:
400 args, desc = SUBCOMMAND_HELP[cmd]
401 except KeyError:
402 shortHelp()
403 return
405 print 'Usage: xm %s %s' % (cmd, args)
406 print
407 print desc
409 try:
410 # If options help message is defined, print this.
411 for shortopt, longopt, desc in SUBCOMMAND_OPTIONS[cmd]:
412 if shortopt and longopt:
413 optdesc = '%s, %s' % (shortopt, longopt)
414 elif shortopt:
415 optdesc = shortopt
416 elif longopt:
417 optdesc = longopt
419 wrapped_desc = wrap(desc, 43)
420 print ' %-30s %-43s' % (optdesc, wrapped_desc[0])
421 for line in wrapped_desc[1:]:
422 print ' ' * 33 + line
423 print
424 except KeyError:
425 # if the command is an external module, we grab usage help
426 # from the module itself.
427 if cmd in IMPORTED_COMMANDS:
428 try:
429 cmd_module = __import__(cmd, globals(), locals(), 'xen.xm')
430 cmd_usage = getattr(cmd_module, "help", None)
431 if cmd_usage:
432 print cmd_usage()
433 except ImportError:
434 pass
436 def shortHelp():
437 """Print out generic help when xm is called without subcommand."""
439 print USAGE_HELP
440 print 'Common \'xm\' commands:\n'
442 for command in common_commands:
443 try:
444 args, desc = SUBCOMMAND_HELP[command]
445 except KeyError:
446 continue
447 wrapped_desc = wrap(desc, 50)
448 print ' %-20s %-50s' % (command, wrapped_desc[0])
449 for line in wrapped_desc[1:]:
450 print ' ' * 22 + line
452 print
453 print USAGE_FOOTER
454 print 'For a complete list of subcommands run \'xm help\'.'
456 def longHelp():
457 """Print out full help when xm is called with xm --help or xm help"""
459 print USAGE_HELP
460 print 'xm full list of subcommands:\n'
462 for command in all_commands:
463 try:
464 args, desc = SUBCOMMAND_HELP[command]
465 except KeyError:
466 continue
468 wrapped_desc = wrap(desc, 50)
469 print ' %-20s %-50s' % (command, wrapped_desc[0])
470 for line in wrapped_desc[1:]:
471 print ' ' * 22 + line
473 print
474 print USAGE_FOOTER
476 def _usage(cmd):
477 """ Print help usage information """
478 if cmd:
479 cmdHelp(cmd)
480 else:
481 shortHelp()
483 def usage(cmd = None):
484 """ Print help usage information and exits """
485 _usage(cmd)
486 sys.exit(1)
489 ####################################################################
490 #
491 # Utility functions
492 #
493 ####################################################################
495 def get_default_SR():
496 return [sr_ref
497 for sr_ref in server.xenapi.SR.get_all()
498 if server.xenapi.SR.get_type(sr_ref) == "local"][0]
500 def map2sxp(m):
501 return [[k, m[k]] for k in m.keys()]
503 def arg_check(args, name, lo, hi = -1):
504 n = len([i for i in args if i != '--'])
506 if hi == -1:
507 if n != lo:
508 err("'xm %s' requires %d argument%s.\n" % (name, lo,
509 lo == 1 and '' or 's'))
510 usage(name)
511 else:
512 if n < lo or n > hi:
513 err("'xm %s' requires between %d and %d arguments.\n" %
514 (name, lo, hi))
515 usage(name)
518 def unit(c):
519 if not c.isalpha():
520 return 0
521 base = 1
522 if c == 'G' or c == 'g': base = 1024 * 1024 * 1024
523 elif c == 'M' or c == 'm': base = 1024 * 1024
524 elif c == 'K' or c == 'k': base = 1024
525 else:
526 print 'ignoring unknown unit'
527 return base
529 def int_unit(str, dest):
530 base = unit(str[-1])
531 if not base:
532 return int(str)
534 value = int(str[:-1])
535 dst_base = unit(dest)
536 if dst_base == 0:
537 dst_base = 1
538 if dst_base > base:
539 return value / (dst_base / base)
540 else:
541 return value * (base / dst_base)
543 def err(msg):
544 print >>sys.stderr, "Error:", msg
547 def get_single_vm(dom):
548 uuids = server.xenapi.VM.get_by_name_label(dom)
549 n = len(uuids)
550 if n == 1:
551 return uuids[0]
552 else:
553 dominfo = server.xend.domain(dom, False)
554 return dominfo['uuid']
556 ##
557 #
558 # Xen-API Shell
559 #
560 ##
562 class Shell(cmd.Cmd):
563 def __init__(self):
564 cmd.Cmd.__init__(self)
565 self.prompt = "xm> "
566 if serverType == SERVER_XEN_API:
567 res = server.xenapi._UNSUPPORTED_list_all_methods()
568 for f in res:
569 setattr(Shell, 'do_' + f + ' ', self.default)
571 def preloop(self):
572 cmd.Cmd.preloop(self)
573 readline.set_completer_delims(' ')
575 def default(self, line):
576 words = shlex.split(line)
577 if len(words) > 0 and words[0] == 'xm':
578 words = words[1:]
579 if len(words) > 0:
580 cmd = xm_lookup_cmd(words[0])
581 if cmd:
582 _run_cmd(cmd, words[0], words[1:])
583 elif serverType == SERVER_XEN_API:
584 ok, res = _run_cmd(lambda x: server.xenapi_request(words[0],
585 tuple(x)),
586 words[0], words[1:])
587 if ok and res is not None and res != '':
588 pprint.pprint(res)
589 else:
590 print '*** Unknown command: %s' % words[0]
591 return False
593 def completedefault(self, text, line, begidx, endidx):
594 words = shlex.split(line[:begidx])
595 clas, func = words[0].split('.')
596 if len(words) > 1 or \
597 func.startswith('get_by_') or \
598 func == 'get_all':
599 return []
600 uuids = server.xenapi_request('%s.get_all' % clas, ())
601 return [u + " " for u in uuids if u.startswith(text)]
603 def emptyline(self):
604 pass
606 def do_EOF(self, line):
607 print
608 sys.exit(0)
610 def do_help(self, line):
611 _usage(line)
614 def xm_shell(args):
615 Shell().cmdloop('The Xen Master. Type "help" for a list of functions.')
618 #########################################################################
619 #
620 # Main xm functions
621 #
622 #########################################################################
624 def xm_save(args):
625 arg_check(args, "save", 2, 3)
627 try:
628 (options, params) = getopt.gnu_getopt(args, 'c', ['checkpoint'])
629 except getopt.GetoptError, opterr:
630 err(opterr)
631 sys.exit(1)
633 checkpoint = False
634 for (k, v) in options:
635 if k in ['-c', '--checkpoint']:
636 checkpoint = True
638 if len(params) != 2:
639 err("Wrong number of parameters")
640 usage('save')
641 sys.exit(1)
643 try:
644 dominfo = parse_doms_info(server.xend.domain(params[0]))
645 except xmlrpclib.Fault, ex:
646 raise ex
648 domid = dominfo['domid']
649 savefile = os.path.abspath(params[1])
651 if not os.access(os.path.dirname(savefile), os.W_OK):
652 err("xm save: Unable to create file %s" % savefile)
653 sys.exit(1)
655 server.xend.domain.save(domid, savefile, checkpoint)
657 def xm_restore(args):
658 arg_check(args, "restore", 1, 2)
660 try:
661 (options, params) = getopt.gnu_getopt(args, 'p', ['paused'])
662 except getopt.GetoptError, opterr:
663 err(opterr)
664 usage('restore')
666 paused = False
667 for (k, v) in options:
668 if k in ['-p', '--paused']:
669 paused = True
671 if len(params) != 1:
672 err("Wrong number of parameters")
673 usage('restore')
675 savefile = os.path.abspath(params[0])
677 if not os.access(savefile, os.R_OK):
678 err("xm restore: Unable to read file %s" % savefile)
679 sys.exit(1)
681 server.xend.domain.restore(savefile, paused)
684 def getDomains(domain_names, state, full = 0):
685 if serverType == SERVER_XEN_API:
686 doms_sxp = []
687 doms_dict = []
688 dom_refs = server.xenapi.VM.get_all()
689 for dom_ref in dom_refs:
690 dom_rec = server.xenapi.VM.get_record(dom_ref)
691 dom_metrics_ref = server.xenapi.VM.get_metrics(dom_ref)
692 dom_metrics = server.xenapi.VM_metrics.get_record(dom_metrics_ref)
693 dom_rec.update({'name': dom_rec['name_label'],
694 'memory_actual': int(dom_metrics['memory_actual'])/1024,
695 'vcpus': dom_metrics['vcpus_number'],
696 'state': '-----',
697 'cpu_time': dom_metrics['vcpus_utilisation']})
699 doms_sxp.append(['domain'] + map2sxp(dom_rec))
700 doms_dict.append(dom_rec)
702 if domain_names:
703 doms = [['domain'] + map2sxp(dom) for dom in doms_dict
704 if dom["name"] in domain_names]
706 if len(doms) > 0:
707 return doms
708 else:
709 print "Error: no domains named '%s'" % domain_names
710 sys.exit(-1)
711 else:
712 return doms_sxp
713 else:
714 if domain_names:
715 return [server.xend.domain(dom, full) for dom in domain_names]
716 else:
717 return server.xend.domains_with_state(True, state, full)
720 def xm_list(args):
721 use_long = 0
722 show_vcpus = 0
723 show_labels = 0
724 state = 'all'
725 try:
726 (options, params) = getopt.gnu_getopt(args, 'lv',
727 ['long','vcpus','label',
728 'state='])
729 except getopt.GetoptError, opterr:
730 err(opterr)
731 usage('list')
733 for (k, v) in options:
734 if k in ['-l', '--long']:
735 use_long = 1
736 if k in ['-v', '--vcpus']:
737 show_vcpus = 1
738 if k in ['--label']:
739 show_labels = 1
740 if k in ['--state']:
741 state = v
743 if state != 'all' and len(params) > 0:
744 raise OptionError(
745 "You may specify either a state or a particular VM, but not both")
747 if show_vcpus:
748 print >>sys.stderr, (
749 "xm list -v is deprecated. Please use xm vcpu-list.")
750 xm_vcpu_list(params)
751 return
753 doms = getDomains(params, state, use_long)
755 if use_long:
756 map(PrettyPrint.prettyprint, doms)
757 elif show_labels:
758 xm_label_list(doms)
759 else:
760 xm_brief_list(doms)
763 def parse_doms_info(info):
764 def get_info(n, t, d):
765 return t(sxp.child_value(info, n, d))
767 def get_status(n, t, d):
768 return DOM_STATES[t(sxp.child_value(info, n, d))]
770 start_time = get_info('start_time', float, -1)
771 if start_time == -1:
772 up_time = float(-1)
773 else:
774 up_time = time.time() - start_time
776 parsed_info = {
777 'domid' : get_info('domid', str, ''),
778 'name' : get_info('name', str, '??'),
779 'state' : get_info('state', str, ''),
781 # VCPUs is the number online when the VM is up, or the number
782 # configured otherwise.
783 'vcpus' : get_info('online_vcpus', int,
784 get_info('vcpus', int, 0)),
785 'up_time' : up_time
786 }
788 # We're not supporting security stuff just yet via XenAPI
790 if serverType != SERVER_XEN_API:
791 from xen.util import security
792 parsed_info['seclabel'] = security.get_security_printlabel(info)
793 else:
794 parsed_info['seclabel'] = ""
796 if serverType == SERVER_XEN_API:
797 parsed_info['mem'] = get_info('memory_actual', int, 0) / 1024
798 cpu_times = get_info('cpu_time', lambda x : (x), 0.0)
799 if sum(cpu_times.values()) > 0:
800 parsed_info['cpu_time'] = sum(cpu_times.values()) / float(len(cpu_times.values()))
801 else:
802 parsed_info['cpu_time'] = 0
803 else:
804 parsed_info['mem'] = get_info('memory', int,0)
805 parsed_info['cpu_time'] = get_info('cpu_time', float, 0.0)
807 return parsed_info
809 def check_sched_type(sched):
810 if serverType == SERVER_XEN_API:
811 current = server.xenapi.host.get_sched_policy(server.xenapi.session.get_this_host())
812 else:
813 current = 'unknown'
814 for x in server.xend.node.info()[1:]:
815 if len(x) > 1 and x[0] == 'xen_scheduler':
816 current = x[1]
817 break
818 if sched != current:
819 err("Xen is running with the %s scheduler" % current)
820 sys.exit(1)
822 def parse_sedf_info(info):
823 def get_info(n, t, d):
824 return t(sxp.child_value(info, n, d))
826 return {
827 'domid' : get_info('domid', int, -1),
828 'period' : get_info('period', int, -1),
829 'slice' : get_info('slice', int, -1),
830 'latency' : get_info('latency', int, -1),
831 'extratime': get_info('extratime', int, -1),
832 'weight' : get_info('weight', int, -1),
833 }
835 def domid_match(domid, info):
836 return domid is None or domid == info['name'] or \
837 domid == str(info['domid'])
839 def xm_brief_list(doms):
840 print '%-40s %3s %5s %5s %10s %9s' % \
841 ('Name', 'ID', 'Mem', 'VCPUs', 'State', 'Time(s)')
843 format = "%(name)-40s %(domid)3s %(mem)5d %(vcpus)5d %(state)10s " \
844 "%(cpu_time)8.1f"
846 for dom in doms:
847 d = parse_doms_info(dom)
848 print format % d
850 def xm_label_list(doms):
851 print '%-32s %3s %5s %5s %5s %9s %-8s' % \
852 ('Name', 'ID', 'Mem', 'VCPUs', 'State', 'Time(s)', 'Label')
854 output = []
855 format = '%(name)-32s %(domid)3s %(mem)5d %(vcpus)5d %(state)10s ' \
856 '%(cpu_time)8.1f %(seclabel)9s'
858 if serverType != SERVER_XEN_API:
859 from xen.util import security
861 for dom in doms:
862 d = parse_doms_info(dom)
864 if security.active_policy not in ['INACTIVE', 'NULL', 'DEFAULT']:
865 if not d['seclabel']:
866 d['seclabel'] = 'ERROR'
867 elif security.active_policy in ['DEFAULT']:
868 d['seclabel'] = 'DEFAULT'
869 else:
870 d['seclabel'] = 'INACTIVE'
872 output.append((format % d, d['seclabel']))
874 #sort by labels
875 output.sort(lambda x,y: cmp( x[1].lower(), y[1].lower()))
876 for line, label in output:
877 print line
880 def xm_vcpu_list(args):
881 if args:
882 dominfo = map(server.xend.domain.getVCPUInfo, args)
883 else:
884 doms = server.xend.domains(False)
885 dominfo = map(server.xend.domain.getVCPUInfo, doms)
887 print '%-32s %3s %5s %5s %5s %9s %s' % \
888 ('Name', 'ID', 'VCPU', 'CPU', 'State', 'Time(s)', 'CPU Affinity')
890 format = '%(name)-32s %(domid)3d %(number)5d %(c)5s %(s)5s ' \
891 ' %(cpu_time)8.1f %(cpumap)s'
893 for dom in dominfo:
894 def get_info(n):
895 return sxp.child_value(dom, n)
897 #
898 # convert a list of integers into a list of pairs indicating
899 # continuous sequences in the list:
900 #
901 # [0,1,2,3] -> [(0,3)]
902 # [1,2,4,5] -> [(1,2),(4,5)]
903 # [0] -> [(0,0)]
904 # [0,1,4,6,7] -> [(0,1),(4,4),(6,7)]
905 #
906 def list_to_rangepairs(cmap):
907 cmap.sort()
908 pairs = []
909 x = y = 0
910 for i in range(0,len(cmap)):
911 try:
912 if ((cmap[y+1] - cmap[i]) > 1):
913 pairs.append((cmap[x],cmap[y]))
914 x = y = i+1
915 else:
916 y = y + 1
917 # if we go off the end, then just add x to y
918 except IndexError:
919 pairs.append((cmap[x],cmap[y]))
921 return pairs
923 #
924 # Convert pairs to range string, e.g: [(1,2),(3,3),(5,7)] -> 1-2,3,5-7
925 #
926 def format_pairs(pairs):
927 if not pairs:
928 return "no cpus"
929 out = ""
930 for f,s in pairs:
931 if (f==s):
932 out += '%d'%f
933 else:
934 out += '%d-%d'%(f,s)
935 out += ','
936 # trim trailing ','
937 return out[:-1]
939 def format_cpumap(cpumap):
940 cpumap = map(lambda x: int(x), cpumap)
941 cpumap.sort()
943 for x in server.xend.node.info()[1:]:
944 if len(x) > 1 and x[0] == 'nr_cpus':
945 nr_cpus = int(x[1])
946 # normalize cpumap by modulus nr_cpus, and drop duplicates
947 cpumap = dict.fromkeys(
948 map(lambda x: x % nr_cpus, cpumap)).keys()
949 if len(cpumap) == nr_cpus:
950 return "any cpu"
951 break
953 return format_pairs(list_to_rangepairs(cpumap))
955 name = get_info('name')
956 domid = int(get_info('domid'))
958 for vcpu in sxp.children(dom, 'vcpu'):
959 def vinfo(n, t):
960 return t(sxp.child_value(vcpu, n))
962 number = vinfo('number', int)
963 cpu = vinfo('cpu', int)
964 cpumap = format_cpumap(vinfo('cpumap', list))
965 online = vinfo('online', int)
966 cpu_time = vinfo('cpu_time', float)
967 running = vinfo('running', int)
968 blocked = vinfo('blocked', int)
970 if online:
971 c = str(cpu)
972 if running:
973 s = 'r'
974 else:
975 s = '-'
976 if blocked:
977 s += 'b'
978 else:
979 s += '-'
980 s += '-'
981 else:
982 c = "-"
983 s = "--p"
985 print format % locals()
987 def xm_start(args):
988 arg_check(args, "start", 1, 2)
990 try:
991 (options, params) = getopt.gnu_getopt(args, 'p', ['paused'])
992 except getopt.GetoptError, opterr:
993 err(opterr)
994 usage('start')
996 paused = False
997 for (k, v) in options:
998 if k in ['-p', '--paused']:
999 paused = True
1001 if len(params) != 1:
1002 err("Wrong number of parameters")
1003 usage('start')
1005 dom = params[0]
1006 if serverType == SERVER_XEN_API:
1007 server.xenapi.VM.start(get_single_vm(dom), paused)
1008 else:
1009 server.xend.domain.start(dom, paused)
1011 def xm_delete(args):
1012 arg_check(args, "delete", 1)
1013 dom = args[0]
1014 if serverType == SERVER_XEN_API:
1015 server.xenapi.VM.destroy(get_single_vm(dom))
1016 else:
1017 server.xend.domain.delete(dom)
1019 def xm_suspend(args):
1020 arg_check(args, "suspend", 1)
1021 dom = args[0]
1022 if serverType == SERVER_XEN_API:
1023 server.xenapi.VM.suspend(get_single_vm(dom))
1024 else:
1025 server.xend.domain.suspend(dom)
1027 def xm_resume(args):
1028 arg_check(args, "resume", 1, 2)
1030 try:
1031 (options, params) = getopt.gnu_getopt(args, 'p', ['paused'])
1032 except getopt.GetoptError, opterr:
1033 err(opterr)
1034 usage('resume')
1036 paused = False
1037 for (k, v) in options:
1038 if k in ['-p', '--paused']:
1039 paused = True
1041 if len(params) != 1:
1042 err("Wrong number of parameters")
1043 usage('resume')
1045 dom = params[0]
1046 if serverType == SERVER_XEN_API:
1047 server.xenapi.VM.resume(get_single_vm(dom), paused)
1048 else:
1049 server.xend.domain.resume(dom, paused)
1051 def xm_reboot(args):
1052 arg_check(args, "reboot", 1, 3)
1053 from xen.xm import shutdown
1054 shutdown.main(["shutdown", "-R"] + args)
1056 def xm_shutdown(args):
1057 arg_check(args, "shutdown", 1, 4)
1058 from xen.xm import shutdown
1059 shutdown.main(["shutdown"] + args)
1061 def xm_pause(args):
1062 arg_check(args, "pause", 1)
1063 dom = args[0]
1065 if serverType == SERVER_XEN_API:
1066 server.xenapi.VM.pause(get_single_vm(dom))
1067 else:
1068 server.xend.domain.pause(dom)
1070 def xm_unpause(args):
1071 arg_check(args, "unpause", 1)
1072 dom = args[0]
1074 if serverType == SERVER_XEN_API:
1075 server.xenapi.VM.unpause(get_single_vm(dom))
1076 else:
1077 server.xend.domain.unpause(dom)
1079 def xm_dump_core(args):
1080 live = False
1081 crash = False
1082 try:
1083 (options, params) = getopt.gnu_getopt(args, 'LC', ['live','crash'])
1084 for (k, v) in options:
1085 if k in ('-L', '--live'):
1086 live = True
1087 if k in ('-C', '--crash'):
1088 crash = True
1090 if len(params) not in (1, 2):
1091 raise OptionError("Expects 1 or 2 argument(s)")
1092 except getopt.GetoptError, e:
1093 raise OptionError(str(e))
1095 dom = params[0]
1096 if len(params) == 2:
1097 filename = os.path.abspath(params[1])
1098 else:
1099 filename = None
1101 if not live:
1102 server.xend.domain.pause(dom)
1104 try:
1105 print "Dumping core of domain: %s ..." % str(dom)
1106 server.xend.domain.dump(dom, filename, live, crash)
1107 finally:
1108 if not live:
1109 server.xend.domain.unpause(dom)
1111 if crash:
1112 print "Destroying domain: %s ..." % str(dom)
1113 server.xend.domain.destroy(dom)
1115 def xm_rename(args):
1116 arg_check(args, "rename", 2)
1118 if serverType == SERVER_XEN_API:
1119 server.xenapi.VM.set_name_label(get_single_vm(args[0]), args[1])
1120 else:
1121 server.xend.domain.setName(args[0], args[1])
1123 def xm_importcommand(command, args):
1124 cmd = __import__(command, globals(), locals(), 'xen.xm')
1125 cmd.main([command] + args)
1128 #############################################################
1130 def xm_vcpu_pin(args):
1131 arg_check(args, "vcpu-pin", 3)
1133 def cpu_make_map(cpulist):
1134 cpus = []
1135 for c in cpulist.split(','):
1136 if c.find('-') != -1:
1137 (x,y) = c.split('-')
1138 for i in range(int(x),int(y)+1):
1139 cpus.append(int(i))
1140 else:
1141 # remove this element from the list
1142 if c[0] == '^':
1143 cpus = [x for x in cpus if x != int(c[1:])]
1144 else:
1145 cpus.append(int(c))
1146 cpus.sort()
1147 return cpus
1149 dom = args[0]
1150 vcpu = args[1]
1151 if args[2] == 'all':
1152 cpumap = cpu_make_map('0-63')
1153 else:
1154 cpumap = cpu_make_map(args[2])
1156 server.xend.domain.pincpu(dom, vcpu, cpumap)
1158 def xm_mem_max(args):
1159 arg_check(args, "mem-max", 2)
1161 dom = args[0]
1163 if serverType == SERVER_XEN_API:
1164 mem = int_unit(args[1], 'k') * 1024
1165 server.xenapi.VM.set_memory_static_max(get_single_vm(dom), mem)
1166 else:
1167 mem = int_unit(args[1], 'm')
1168 server.xend.domain.maxmem_set(dom, mem)
1170 def xm_mem_set(args):
1171 arg_check(args, "mem-set", 2)
1173 dom = args[0]
1175 if serverType == SERVER_XEN_API:
1176 mem_target = int_unit(args[1], 'm') * 1024 * 1024
1177 server.xenapi.VM.set_memory_dynamic_max(get_single_vm(dom), mem_target)
1178 server.xenapi.VM.set_memory_dynamic_min(get_single_vm(dom), mem_target)
1179 else:
1180 mem_target = int_unit(args[1], 'm')
1181 server.xend.domain.setMemoryTarget(dom, mem_target)
1183 def xm_vcpu_set(args):
1184 arg_check(args, "vcpu-set", 2)
1186 dom = args[0]
1187 vcpus = int(args[1])
1189 if serverType == SERVER_XEN_API:
1190 server.xenapi.VM.set_vcpus_live(get_single_vm(dom), vcpus)
1191 else:
1192 server.xend.domain.setVCpuCount(dom, vcpus)
1194 def xm_destroy(args):
1195 arg_check(args, "destroy", 1)
1197 dom = args[0]
1199 if serverType == SERVER_XEN_API:
1200 server.xenapi.VM.hard_shutdown(get_single_vm(dom))
1201 else:
1202 server.xend.domain.destroy(dom)
1204 def xm_domid(args):
1205 arg_check(args, "domid", 1)
1207 name = args[0]
1209 if serverType == SERVER_XEN_API:
1210 print server.xenapi.VM.get_domid(get_single_vm(name))
1211 else:
1212 dom = server.xend.domain(name)
1213 print sxp.child_value(dom, 'domid')
1215 def xm_domname(args):
1216 arg_check(args, "domname", 1)
1218 name = args[0]
1220 if serverType == SERVER_XEN_API:
1221 print server.xenapi.VM.get_name_label(get_single_vm(name))
1222 else:
1223 dom = server.xend.domain(name)
1224 print sxp.child_value(dom, 'name')
1226 def xm_sched_sedf(args):
1227 def ns_to_ms(val):
1228 return float(val) * 0.000001
1230 def ms_to_ns(val):
1231 return (float(val) / 0.000001)
1233 def print_sedf(info):
1234 info['period'] = ns_to_ms(info['period'])
1235 info['slice'] = ns_to_ms(info['slice'])
1236 info['latency'] = ns_to_ms(info['latency'])
1237 print( ("%(name)-32s %(domid)3d %(period)9.1f %(slice)9.1f" +
1238 " %(latency)7.1f %(extratime)6d %(weight)6d") % info)
1240 check_sched_type('sedf')
1242 # we want to just display current info if no parameters are passed
1243 if len(args) == 0:
1244 domid = None
1245 else:
1246 # we expect at least a domain id (name or number)
1247 # and at most a domid up to 5 options with values
1248 arg_check(args, "sched-sedf", 1, 11)
1249 domid = args[0]
1250 # drop domid from args since get_opt doesn't recognize it
1251 args = args[1:]
1253 opts = {}
1254 try:
1255 (options, params) = getopt.gnu_getopt(args, 'p:s:l:e:w:',
1256 ['period=', 'slice=', 'latency=', 'extratime=', 'weight='])
1257 except getopt.GetoptError, opterr:
1258 err(opterr)
1259 usage('sched-sedf')
1261 # convert to nanoseconds if needed
1262 for (k, v) in options:
1263 if k in ['-p', '--period']:
1264 opts['period'] = ms_to_ns(v)
1265 elif k in ['-s', '--slice']:
1266 opts['slice'] = ms_to_ns(v)
1267 elif k in ['-l', '--latency']:
1268 opts['latency'] = ms_to_ns(v)
1269 elif k in ['-e', '--extratime']:
1270 opts['extratime'] = v
1271 elif k in ['-w', '--weight']:
1272 opts['weight'] = v
1274 doms = filter(lambda x : domid_match(domid, x),
1275 [parse_doms_info(dom)
1276 for dom in getDomains(None, 'running')])
1277 if domid is not None and doms == []:
1278 err("Domain '%s' does not exist." % domid)
1279 usage('sched-sedf')
1281 # print header if we aren't setting any parameters
1282 if len(opts.keys()) == 0:
1283 print '%-33s %-2s %-4s %-4s %-7s %-5s %-6s' % \
1284 ('Name','ID','Period(ms)', 'Slice(ms)', 'Lat(ms)',
1285 'Extra','Weight')
1287 for d in doms:
1288 # fetch current values so as not to clobber them
1289 try:
1290 sedf_raw = server.xend.domain.cpu_sedf_get(d['domid'])
1291 except xmlrpclib.Fault:
1292 # domain does not support sched-sedf?
1293 sedf_raw = {}
1295 sedf_info = parse_sedf_info(sedf_raw)
1296 sedf_info['name'] = d['name']
1297 # update values in case of call to set
1298 if len(opts.keys()) > 0:
1299 for k in opts.keys():
1300 sedf_info[k]=opts[k]
1302 # send the update, converting user input
1303 v = map(int, [sedf_info['period'], sedf_info['slice'],
1304 sedf_info['latency'],sedf_info['extratime'],
1305 sedf_info['weight']])
1306 rv = server.xend.domain.cpu_sedf_set(d['domid'], *v)
1307 if int(rv) != 0:
1308 err("Failed to set sedf parameters (rv=%d)."%(rv))
1310 # not setting values, display info
1311 else:
1312 print_sedf(sedf_info)
1314 def xm_sched_credit(args):
1315 """Get/Set options for Credit Scheduler."""
1317 check_sched_type('credit')
1319 try:
1320 opts, params = getopt.getopt(args, "d:w:c:",
1321 ["domain=", "weight=", "cap="])
1322 except getopt.GetoptError, opterr:
1323 err(opterr)
1324 usage('sched-credit')
1326 domid = None
1327 weight = None
1328 cap = None
1330 for o, a in opts:
1331 if o == "-d":
1332 domid = a
1333 elif o == "-w":
1334 weight = int(a)
1335 elif o == "-c":
1336 cap = int(a);
1338 doms = filter(lambda x : domid_match(domid, x),
1339 [parse_doms_info(dom)
1340 for dom in getDomains(None, 'running')])
1342 if weight is None and cap is None:
1343 if domid is not None and doms == []:
1344 err("Domain '%s' does not exist." % domid)
1345 usage('sched-credit')
1346 # print header if we aren't setting any parameters
1347 print '%-33s %-2s %-6s %-4s' % ('Name','ID','Weight','Cap')
1349 for d in doms:
1350 try:
1351 info = server.xend.domain.sched_credit_get(d['domid'])
1352 except xmlrpclib.Fault:
1353 # domain does not support sched-credit?
1354 info = {'weight': -1, 'cap': -1}
1356 info['name'] = d['name']
1357 info['domid'] = int(d['domid'])
1358 print( ("%(name)-32s %(domid)3d %(weight)6d %(cap)4d") % info)
1359 else:
1360 if domid is None:
1361 # place holder for system-wide scheduler parameters
1362 err("No domain given.")
1363 usage('sched-credit')
1365 result = server.xend.domain.sched_credit_set(domid, weight, cap)
1366 if result != 0:
1367 err(str(result))
1369 def xm_info(args):
1370 arg_check(args, "info", 0)
1372 if serverType == SERVER_XEN_API:
1374 # Need to fake out old style xm info as people rely on parsing it
1376 host_record = server.xenapi.host.get_record(
1377 server.xenapi.session.get_this_host())
1379 host_cpu_records = map(server.xenapi.host_cpu.get_record, host_record["host_CPUs"])
1381 host_metrics_record = server.xenapi.host_metrics.get_record(host_record["metrics"])
1383 info = {
1384 "host": host_record["name_label"],
1385 "release": host_record["software_version"]["release"],
1386 "version": host_record["software_version"]["version"],
1387 "machine": host_record["software_version"]["machine"],
1388 "nr_cpus": len(host_record["host_CPUs"]),
1389 "nr_nodes": host_record["cpu_configuration"]["nr_nodes"],
1390 "sockets_per_node": host_record["cpu_configuration"]["sockets_per_node"],
1391 "cores_per_socket": host_record["cpu_configuration"]["cores_per_socket"],
1392 "threads_per_core": host_record["cpu_configuration"]["threads_per_core"],
1393 "cpu_mhz": sum([int(host_cpu_record["speed"]) for host_cpu_record in host_cpu_records])
1394 / len(host_cpu_records),
1395 "hw_caps": host_cpu_records[0]["features"],
1396 "total_memory": int(host_metrics_record["memory_total"])/1024/1024,
1397 "free_memory": int(host_metrics_record["memory_free"])/1024/1024,
1398 "xen_major": host_record["software_version"]["xen_major"],
1399 "xen_minor": host_record["software_version"]["xen_minor"],
1400 "xen_extra": host_record["software_version"]["xen_extra"],
1401 "xen_caps": " ".join(host_record["capabilities"]),
1402 "xen_scheduler": host_record["sched_policy"],
1403 "xen_pagesize": host_record["other_config"]["xen_pagesize"],
1404 "platform_params": host_record["other_config"]["platform_params"],
1405 "xen_changeset": host_record["software_version"]["xen_changeset"],
1406 "cc_compiler": host_record["software_version"]["cc_compiler"],
1407 "cc_compile_by": host_record["software_version"]["cc_compile_by"],
1408 "cc_compile_domain": host_record["software_version"]["cc_compile_domain"],
1409 "cc_compile_date": host_record["software_version"]["cc_compile_date"],
1410 "xend_config_format":host_record["software_version"]["xend_config_format"]
1413 sorted = info.items()
1414 sorted.sort(lambda (x1,y1), (x2,y2): -cmp(x1,x2))
1416 for (k, v) in sorted:
1417 print "%-23s:" % k, v
1418 else:
1419 info = server.xend.node.info()
1420 for x in info[1:]:
1421 if len(x) < 2:
1422 print "%-23s: (none)" % x[0]
1423 else:
1424 print "%-23s:" % x[0], x[1]
1426 def xm_console(args):
1427 arg_check(args, "console", 1, 2)
1429 quiet = False;
1431 try:
1432 (options, params) = getopt.gnu_getopt(args, 'q', ['quiet'])
1433 except getopt.GetoptError, opterr:
1434 err(opterr)
1435 usage('console')
1437 for (k, v) in options:
1438 if k in ['-q', '--quiet']:
1439 quiet = True
1440 else:
1441 assert False
1443 if len(params) != 1:
1444 err('No domain given')
1445 usage('console')
1447 dom = params[0]
1449 try:
1450 if serverType == SERVER_XEN_API:
1451 domid = int(server.xenapi.VM.get_domid(get_single_vm(dom)))
1452 else:
1453 info = server.xend.domain(dom)
1454 domid = int(sxp.child_value(info, 'domid', '-1'))
1455 except:
1456 if quiet:
1457 sys.exit(1)
1458 else:
1459 raise
1461 if domid == -1:
1462 if quiet:
1463 sys.exit(1)
1464 else:
1465 raise xmlrpclib.Fault(0, "Domain '%s' is not started" % dom)
1467 console.execConsole(domid)
1470 def xm_uptime(args):
1471 short_mode = 0
1473 try:
1474 (options, params) = getopt.gnu_getopt(args, 's', ['short'])
1475 except getopt.GetoptError, opterr:
1476 err(opterr)
1477 usage('uptime')
1479 for (k, v) in options:
1480 if k in ['-s', '--short']:
1481 short_mode = 1
1483 doms = getDomains(params, 'running')
1485 if short_mode == 0:
1486 print 'Name ID Uptime'
1488 for dom in doms:
1489 d = parse_doms_info(dom)
1490 if int(d['domid']) > 0:
1491 uptime = int(round(d['up_time']))
1492 else:
1493 f=open('/proc/uptime', 'r')
1494 upfile = f.read()
1495 uptime = int(round(float(upfile.split(' ')[0])))
1496 f.close()
1498 days = int(uptime / 86400)
1499 uptime -= (days * 86400)
1500 hours = int(uptime / 3600)
1501 uptime -= (hours * 3600)
1502 minutes = int(uptime / 60)
1503 uptime -= (minutes * 60)
1504 seconds = uptime
1506 upstring = ""
1507 if days > 0:
1508 upstring += str(days) + " day"
1509 if days > 1:
1510 upstring += "s"
1511 upstring += ", "
1512 upstring += '%(hours)2d:%(minutes)02d' % vars()
1514 if short_mode:
1515 now = datetime.datetime.now()
1516 upstring = now.strftime(" %H:%M:%S") + " up " + upstring
1517 upstring += ", " + d['name'] + " (" + d['domid'] + ")"
1518 else:
1519 upstring += ':%(seconds)02d' % vars()
1520 upstring = ("%(name)-32s %(domid)3s " % d) + upstring
1522 print upstring
1524 def xm_sysrq(args):
1525 arg_check(args, "sysrq", 2)
1526 dom = args[0]
1527 req = args[1]
1528 if serverType == SERVER_XEN_API:
1529 server.xenapi.VM.send_sysrq(get_single_vm(dom), req)
1530 else:
1531 server.xend.domain.send_sysrq(dom, req)
1533 def xm_trigger(args):
1534 vcpu = 0
1536 arg_check(args, "trigger", 2, 3)
1537 dom = args[0]
1538 trigger = args[1]
1539 if len(args) == 3:
1540 vcpu = int(args[2])
1542 server.xend.domain.send_trigger(dom, trigger, vcpu)
1544 def xm_debug_keys(args):
1545 arg_check(args, "debug-keys", 1)
1546 server.xend.node.send_debug_keys(str(args[0]))
1548 def xm_top(args):
1549 arg_check(args, "top", 0)
1551 os.execvp('xentop', ['xentop'])
1553 def xm_dmesg(args):
1554 arg_check(args, "dmesg", 0, 1)
1556 try:
1557 (options, params) = getopt.gnu_getopt(args, 'c', ['clear'])
1558 except getopt.GetoptError, opterr:
1559 err(opterr)
1560 usage('dmesg')
1562 use_clear = 0
1563 for (k, v) in options:
1564 if k in ['-c', '--clear']:
1565 use_clear = 1
1567 if len(params) :
1568 err("No parameter required")
1569 usage('dmesg')
1571 if serverType == SERVER_XEN_API:
1572 if not use_clear:
1573 print server.xenapi.host.dmesg(
1574 server.xenapi.session.get_this_host(),0)
1575 else:
1576 server.xenapi.host.dmesg(
1577 server.xenapi.session.get_this_host(),1)
1578 else:
1579 if not use_clear:
1580 print server.xend.node.dmesg.info()
1581 else:
1582 server.xend.node.dmesg.clear()
1584 def xm_log(args):
1585 arg_check(args, "log", 0)
1587 if serverType == SERVER_XEN_API:
1588 print server.xenapi.host.get_log(
1589 server.xenapi.session.get_this_host())
1590 else:
1591 print server.xend.node.log()
1593 def xm_serve(args):
1594 if serverType == SERVER_XEN_API:
1595 print "Not supported with XenAPI"
1596 sys.exit(-1)
1598 arg_check(args, "serve", 0)
1600 from fcntl import fcntl, F_SETFL
1602 s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
1603 s.connect(XendClient.XML_RPC_SOCKET)
1604 fcntl(sys.stdin, F_SETFL, os.O_NONBLOCK)
1606 while True:
1607 iwtd, owtd, ewtd = select([sys.stdin, s], [], [])
1608 if s in iwtd:
1609 data = s.recv(4096)
1610 if len(data) > 0:
1611 sys.stdout.write(data)
1612 sys.stdout.flush()
1613 else:
1614 break
1615 if sys.stdin in iwtd:
1616 data = sys.stdin.read(4096)
1617 if len(data) > 0:
1618 s.sendall(data)
1619 else:
1620 break
1621 s.close()
1623 def parse_dev_info(info):
1624 def get_info(n, t, d):
1625 i = 0
1626 while i < len(info):
1627 if (info[i][0] == n):
1628 return t(info[i][1])
1629 i = i + 1
1630 return t(d)
1631 return {
1632 #common
1633 'backend-id' : get_info('backend-id', int, -1),
1634 'handle' : get_info('handle', int, 0),
1635 'state' : get_info('state', int, -1),
1636 'be-path' : get_info('backend', str, '??'),
1637 'event-ch' : get_info('event-channel',int, -1),
1638 #network specific
1639 'virtual-device' : get_info('virtual-device', str, '??'),
1640 'tx-ring-ref': get_info('tx-ring-ref', int, -1),
1641 'rx-ring-ref': get_info('rx-ring-ref', int, -1),
1642 'mac' : get_info('mac', str, '??'),
1643 #block-device specific
1644 'ring-ref' : get_info('ring-ref', int, -1),
1647 def arg_check_for_resource_list(args, name):
1648 use_long = 0
1649 try:
1650 (options, params) = getopt.gnu_getopt(args, 'l', ['long'])
1651 except getopt.GetoptError, opterr:
1652 err(opterr)
1653 sys.exit(1)
1655 for (k, v) in options:
1656 if k in ['-l', '--long']:
1657 use_long = 1
1659 if len(params) == 0:
1660 print 'No domain parameter given'
1661 usage(name)
1662 if len(params) > 1:
1663 print 'No multiple domain parameters allowed'
1664 usage(name)
1666 return (use_long, params)
1668 def xm_network_list(args):
1669 (use_long, params) = arg_check_for_resource_list(args, "network-list")
1671 dom = params[0]
1672 if use_long:
1673 devs = server.xend.domain.getDeviceSxprs(dom, 'vif')
1674 map(PrettyPrint.prettyprint, devs)
1675 else:
1676 hdr = 0
1677 for x in server.xend.domain.getDeviceSxprs(dom, 'vif'):
1678 if hdr == 0:
1679 print 'Idx BE MAC Addr. handle state evt-ch tx-/rx-ring-ref BE-path'
1680 hdr = 1
1681 ni = parse_dev_info(x[1])
1682 ni['idx'] = int(x[0])
1683 print ("%(idx)-3d "
1684 "%(backend-id)-3d"
1685 "%(mac)-17s "
1686 "%(handle)-3d "
1687 "%(state)-3d "
1688 "%(event-ch)-3d "
1689 "%(tx-ring-ref)-5d/%(rx-ring-ref)-5d "
1690 "%(be-path)-30s "
1691 % ni)
1693 def xm_block_list(args):
1694 (use_long, params) = arg_check_for_resource_list(args, "block-list")
1696 dom = params[0]
1698 if serverType == SERVER_XEN_API:
1699 vbd_refs = server.xenapi.VM.get_VBDs(get_single_vm(dom))
1700 vbd_properties = \
1701 map(server.xenapi.VBD.get_runtime_properties, vbd_refs)
1702 devs = map(lambda x: [x['virtual-device'], map2sxp(x)], vbd_properties)
1703 else:
1704 devs = server.xend.domain.getDeviceSxprs(dom, 'vbd')
1706 if use_long:
1707 map(PrettyPrint.prettyprint, devs)
1708 else:
1709 hdr = 0
1710 for x in devs:
1711 if hdr == 0:
1712 print 'Vdev BE handle state evt-ch ring-ref BE-path'
1713 hdr = 1
1714 ni = parse_dev_info(x[1])
1715 ni['idx'] = int(x[0])
1716 print ("%(idx)-3d "
1717 "%(backend-id)-3d "
1718 "%(handle)-3d "
1719 "%(state)-3d "
1720 "%(event-ch)-3d "
1721 "%(ring-ref)-5d "
1722 "%(be-path)-30s "
1723 % ni)
1725 def xm_vtpm_list(args):
1726 (use_long, params) = arg_check_for_resource_list(args, "vtpm-list")
1728 dom = params[0]
1729 if use_long:
1730 devs = server.xend.domain.getDeviceSxprs(dom, 'vtpm')
1731 map(PrettyPrint.prettyprint, devs)
1732 else:
1733 hdr = 0
1734 for x in server.xend.domain.getDeviceSxprs(dom, 'vtpm'):
1735 if hdr == 0:
1736 print 'Idx BE handle state evt-ch ring-ref BE-path'
1737 hdr = 1
1738 ni = parse_dev_info(x[1])
1739 ni['idx'] = int(x[0])
1740 print ("%(idx)-3d "
1741 "%(backend-id)-3d "
1742 "%(handle)-3d "
1743 "%(state)-3d "
1744 "%(event-ch)-3d "
1745 "%(ring-ref)-5d "
1746 "%(be-path)-30s "
1747 % ni)
1750 def parse_block_configuration(args):
1751 dom = args[0]
1753 if args[1].startswith('tap:'):
1754 cls = 'tap'
1755 else:
1756 cls = 'vbd'
1758 vbd = [cls,
1759 ['uname', args[1]],
1760 ['dev', args[2]],
1761 ['mode', args[3]]]
1762 if len(args) == 5:
1763 vbd.append(['backend', args[4]])
1765 if serverType != SERVER_XEN_API:
1766 # verify that policy permits attaching this resource
1767 from xen.util import security
1769 if security.on():
1770 dominfo = server.xend.domain(dom)
1771 label = security.get_security_printlabel(dominfo)
1772 else:
1773 label = None
1775 security.res_security_check(args[1], label)
1777 return (dom, vbd)
1780 def xm_block_attach(args):
1781 arg_check(args, 'block-attach', 4, 5)
1783 if serverType == SERVER_XEN_API:
1784 dom = args[0]
1785 uname = args[1]
1786 dev = args[2]
1787 mode = args[3]
1789 # First create new VDI
1790 vdi_record = {
1791 "name_label": "vdi" + str(uname.__hash__()),
1792 "name_description": "",
1793 "SR": get_default_SR(),
1794 "virtual_size": 0,
1795 "sector_size": 512,
1796 "type": "system",
1797 "sharable": False,
1798 "read_only": mode!="w",
1799 "other_config": {"location": uname}
1802 vdi_ref = server.xenapi.VDI.create(vdi_record)
1804 # Now create new VBD
1806 vbd_record = {
1807 "VM": get_single_vm(dom),
1808 "VDI": vdi_ref,
1809 "device": dev,
1810 "bootable": True,
1811 "mode": mode=="w" and "RW" or "RO",
1812 "type": "Disk",
1813 "qos_algorithm_type": "",
1814 "qos_algorithm_params": {}
1817 server.xenapi.VBD.create(vbd_record)
1819 else:
1820 (dom, vbd) = parse_block_configuration(args)
1821 server.xend.domain.device_create(dom, vbd)
1824 def xm_block_configure(args):
1825 arg_check(args, 'block-configure', 4, 5)
1827 (dom, vbd) = parse_block_configuration(args)
1828 server.xend.domain.device_configure(dom, vbd)
1831 def xm_network_attach(args):
1832 arg_check(args, 'network-attach', 1, 10)
1834 dom = args[0]
1835 vif = ['vif']
1836 vif_params = ['type', 'mac', 'bridge', 'ip', 'script', \
1837 'backend', 'vifname', 'rate', 'model']
1839 for a in args[1:]:
1840 vif_param = a.split("=")
1841 if len(vif_param) != 2 or vif_param[1] == '' or \
1842 vif_param[0] not in vif_params:
1843 err("Invalid argument: %s" % a)
1844 usage('network-attach')
1845 vif.append(vif_param)
1847 server.xend.domain.device_create(dom, vif)
1850 def detach(args, command, deviceClass):
1851 arg_check(args, command, 2, 3)
1853 dom = args[0]
1854 dev = args[1]
1855 try:
1856 force = args[2]
1857 if (force != "--force") and (force != "-f"):
1858 print "Ignoring option %s"%(force)
1859 force = None
1860 except IndexError:
1861 force = None
1863 server.xend.domain.destroyDevice(dom, deviceClass, dev, force)
1866 def xm_block_detach(args):
1867 if serverType == SERVER_XEN_API:
1868 arg_check(args, "xm_block_detach", 2, 3)
1869 dom = args[0]
1870 dev = args[1]
1871 vbd_refs = server.xenapi.VM.get_VBDs(get_single_vm(dom))
1872 vbd_refs = [vbd_ref for vbd_ref in vbd_refs
1873 if server.xenapi.VBD.get_device(vbd_ref) == dev]
1874 if len(vbd_refs) > 0:
1875 vbd_ref = vbd_refs[0]
1876 vdi_ref = server.xenapi.VBD.get_VDI(vbd_ref)
1878 server.xenapi.VBD.destroy(vbd_ref)
1880 if len(server.xenapi.VDI.get_VBDs(vdi_ref)) <= 0:
1881 server.xenapi.VDI.destroy(vdi_ref)
1882 else:
1883 print "Cannot find device '%s' in domain '%s'" % (dev,dom)
1884 else:
1885 try:
1886 detach(args, 'block-detach', 'vbd')
1887 return
1888 except:
1889 pass
1890 detach(args, 'block-detach', 'tap')
1892 def xm_network_detach(args):
1893 detach(args, 'network-detach', 'vif')
1896 def xm_vnet_list(args):
1897 try:
1898 (options, params) = getopt.gnu_getopt(args, 'l', ['long'])
1899 except getopt.GetoptError, opterr:
1900 err(opterr)
1901 usage('vnet-list')
1903 use_long = 0
1904 for (k, v) in options:
1905 if k in ['-l', '--long']:
1906 use_long = 1
1908 if params:
1909 use_long = 1
1910 vnets = params
1911 else:
1912 vnets = server.xend_vnets()
1914 for vnet in vnets:
1915 try:
1916 if use_long:
1917 info = server.xend_vnet(vnet)
1918 PrettyPrint.prettyprint(info)
1919 else:
1920 print vnet
1921 except Exception, ex:
1922 print vnet, ex
1924 def xm_vnet_create(args):
1925 arg_check(args, "vnet-create", 1)
1926 conf = args[0]
1927 if not os.access(conf, os.R_OK):
1928 print "File not found: %s" % conf
1929 sys.exit(1)
1931 server.xend_vnet_create(conf)
1933 def xm_vnet_delete(args):
1934 arg_check(args, "vnet-delete", 1)
1935 vnet = args[0]
1936 server.xend_vnet_delete(vnet)
1938 commands = {
1939 "shell": xm_shell,
1940 # console commands
1941 "console": xm_console,
1942 # xenstat commands
1943 "top": xm_top,
1944 # domain commands
1945 "delete": xm_delete,
1946 "destroy": xm_destroy,
1947 "domid": xm_domid,
1948 "domname": xm_domname,
1949 "dump-core": xm_dump_core,
1950 "reboot": xm_reboot,
1951 "rename": xm_rename,
1952 "restore": xm_restore,
1953 "resume": xm_resume,
1954 "save": xm_save,
1955 "shutdown": xm_shutdown,
1956 "start": xm_start,
1957 "sysrq": xm_sysrq,
1958 "trigger": xm_trigger,
1959 "uptime": xm_uptime,
1960 "suspend": xm_suspend,
1961 "list": xm_list,
1962 # memory commands
1963 "mem-max": xm_mem_max,
1964 "mem-set": xm_mem_set,
1965 # cpu commands
1966 "vcpu-pin": xm_vcpu_pin,
1967 "vcpu-list": xm_vcpu_list,
1968 "vcpu-set": xm_vcpu_set,
1969 # special
1970 "pause": xm_pause,
1971 "unpause": xm_unpause,
1972 # host commands
1973 "debug-keys": xm_debug_keys,
1974 "dmesg": xm_dmesg,
1975 "info": xm_info,
1976 "log": xm_log,
1977 "serve": xm_serve,
1978 # scheduler
1979 "sched-sedf": xm_sched_sedf,
1980 "sched-credit": xm_sched_credit,
1981 # block
1982 "block-attach": xm_block_attach,
1983 "block-detach": xm_block_detach,
1984 "block-list": xm_block_list,
1985 "block-configure": xm_block_configure,
1986 # network
1987 "network-attach": xm_network_attach,
1988 "network-detach": xm_network_detach,
1989 "network-list": xm_network_list,
1990 # vnet
1991 "vnet-list": xm_vnet_list,
1992 "vnet-create": xm_vnet_create,
1993 "vnet-delete": xm_vnet_delete,
1994 # vtpm
1995 "vtpm-list": xm_vtpm_list,
1998 ## The commands supported by a separate argument parser in xend.xm.
1999 IMPORTED_COMMANDS = [
2000 'create',
2001 'new',
2002 'migrate',
2003 'labels',
2004 'cfgbootpolicy',
2005 'makepolicy',
2006 'loadpolicy',
2007 'dumppolicy',
2008 'addlabel',
2009 'rmlabel',
2010 'getlabel',
2011 'dry-run',
2012 'resources',
2015 for c in IMPORTED_COMMANDS:
2016 commands[c] = eval('lambda args: xm_importcommand("%s", args)' % c)
2018 aliases = {
2019 "balloon": "mem-set",
2020 "set-vcpus": "vcpu-set",
2021 "vif-list": "network-list",
2022 "vbd-create": "block-attach",
2023 "vbd-destroy": "block-detach",
2024 "vbd-list": "block-list",
2028 def xm_lookup_cmd(cmd):
2029 if commands.has_key(cmd):
2030 return commands[cmd]
2031 elif aliases.has_key(cmd):
2032 deprecated(cmd,aliases[cmd])
2033 return commands[aliases[cmd]]
2034 elif cmd == 'help':
2035 longHelp()
2036 sys.exit(0)
2037 else:
2038 # simulate getopt's prefix matching behaviour
2039 if len(cmd) > 1:
2040 same_prefix_cmds = [commands[c] for c in commands.keys() \
2041 if c[:len(cmd)] == cmd]
2042 # only execute if there is only 1 match
2043 if len(same_prefix_cmds) == 1:
2044 return same_prefix_cmds[0]
2045 return None
2047 def deprecated(old,new):
2048 print >>sys.stderr, (
2049 "Command %s is deprecated. Please use xm %s instead." % (old, new))
2051 def main(argv=sys.argv):
2052 if len(argv) < 2:
2053 usage()
2055 # intercept --help(-h) and output our own help
2056 for help in ['--help', '-h']:
2057 if help in argv[1:]:
2058 if help == argv[1]:
2059 longHelp()
2060 sys.exit(0)
2061 else:
2062 usage(argv[1])
2064 cmd_name = argv[1]
2065 cmd = xm_lookup_cmd(cmd_name)
2066 if cmd:
2067 # strip off prog name and subcmd
2068 args = argv[2:]
2069 _, rc = _run_cmd(cmd, cmd_name, args)
2070 sys.exit(rc)
2071 else:
2072 err('Subcommand %s not found!' % cmd_name)
2073 usage()
2075 def _run_cmd(cmd, cmd_name, args):
2076 global server
2078 try:
2079 if server is None:
2080 if serverType == SERVER_XEN_API:
2081 server = XenAPI.Session(serverURI)
2082 username, password = parseAuthentication()
2083 server.login_with_password(username, password)
2084 def logout():
2085 try:
2086 server.xenapi.session.logout()
2087 except:
2088 pass
2089 atexit.register(logout)
2090 else:
2091 server = ServerProxy(serverURI)
2093 return True, cmd(args)
2094 except socket.error, ex:
2095 if os.geteuid() != 0:
2096 err("Most commands need root access. Please try again as root.")
2097 else:
2098 err("Unable to connect to xend: %s. Is xend running?" % ex[1])
2099 except KeyboardInterrupt:
2100 print "Interrupted."
2101 return True, ''
2102 except IOError, ex:
2103 if os.geteuid() != 0:
2104 err("Most commands need root access. Please try again as root.")
2105 else:
2106 err("Unable to connect to xend: %s." % ex[1])
2107 except SystemExit, code:
2108 return code == 0, code
2109 except XenAPI.Failure, exn:
2110 for line in [''] + wrap(str(exn), 80) + ['']:
2111 print >>sys.stderr, line
2112 except xmlrpclib.Fault, ex:
2113 if ex.faultCode == XendClient.ERROR_INVALID_DOMAIN:
2114 err("Domain '%s' does not exist." % ex.faultString)
2115 else:
2116 err(ex.faultString)
2117 _usage(cmd_name)
2118 except xmlrpclib.ProtocolError, ex:
2119 if ex.errcode == -1:
2120 print >>sys.stderr, (
2121 "Xend has probably crashed! Invalid or missing HTTP "
2122 "status code.")
2123 else:
2124 print >>sys.stderr, (
2125 "Xend has probably crashed! ProtocolError(%d, %s)." %
2126 (ex.errcode, ex.errmsg))
2127 except (ValueError, OverflowError):
2128 err("Invalid argument.")
2129 _usage(cmd_name)
2130 except OptionError, e:
2131 err(str(e))
2132 _usage(cmd_name)
2133 print e.usage
2134 except Exception, e:
2135 if serverType != SERVER_XEN_API:
2136 from xen.util import security
2137 if isinstance(e, security.ACMError):
2138 err(str(e))
2139 return False, 1
2140 else:
2141 print "Unexpected error:", sys.exc_info()[0]
2142 print
2143 print "Please report to xen-devel@lists.xensource.com"
2144 raise
2146 return False, 1
2148 if __name__ == "__main__":
2149 main()