ia64/xen-unstable

view tools/python/xen/xm/main.py @ 17675:8dce20be0bd5

Fix showing of CPU Affinity by xm vcpu-list
Signed-off-by: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon May 19 09:46:02 2008 +0100 (2008-05-19)
parents 1c6008fc4d9a
children 672c09aad49d
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 shlex
29 import sys
30 import re
31 import getopt
32 import socket
33 import traceback
34 import xmlrpclib
35 import time
36 import datetime
37 from select import select
38 import xml.dom.minidom
39 from xen.util.blkif import blkdev_name_to_number
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.xmlrpcclient import ServerProxy
52 import xen.util.xsm.xsm as security
53 from xen.util.xsm.xsm import XSMError
54 from xen.util.acmpolicy import ACM_LABEL_UNLABELED_DISPLAY
56 import XenAPI
58 import inspect
59 from xen.xend import XendOptions
60 xoptions = XendOptions.instance()
62 # getopt.gnu_getopt is better, but only exists in Python 2.3+. Use
63 # getopt.getopt if gnu_getopt is not available. This will mean that options
64 # may only be specified before positional arguments.
65 if not hasattr(getopt, 'gnu_getopt'):
66 getopt.gnu_getopt = getopt.getopt
68 XM_CONFIG_FILE_ENVVAR = 'XM_CONFIG_FILE'
69 XM_CONFIG_FILE_DEFAULT = '/etc/xen/xm-config.xml'
71 # Supported types of server
72 SERVER_LEGACY_XMLRPC = 'LegacyXMLRPC'
73 SERVER_XEN_API = 'Xen-API'
75 # General help message
77 USAGE_HELP = "Usage: xm <subcommand> [args]\n\n" \
78 "Control, list, and manipulate Xen guest instances.\n"
80 USAGE_FOOTER = '<Domain> can either be the Domain Name or Id.\n' \
81 'For more help on \'xm\' see the xm(1) man page.\n' \
82 'For more help on \'xm create\' see the xmdomain.cfg(5) '\
83 ' man page.\n'
85 # Help strings are indexed by subcommand name in this way:
86 # 'subcommand': (argstring, description)
88 SUBCOMMAND_HELP = {
89 # common commands
91 'shell' : ('', 'Launch an interactive shell.'),
93 'console' : ('[-q|--quiet] <Domain>',
94 'Attach to <Domain>\'s console.'),
95 'create' : ('<ConfigFile> [options] [vars]',
96 'Create a domain based on <ConfigFile>.'),
97 'destroy' : ('<Domain>',
98 'Terminate a domain immediately.'),
99 'help' : ('', 'Display this message.'),
100 'list' : ('[options] [Domain, ...]',
101 'List information about all/some domains.'),
102 'mem-max' : ('<Domain> <Mem>',
103 'Set the maximum amount reservation for a domain.'),
104 'mem-set' : ('<Domain> <Mem>',
105 'Set the current memory usage for a domain.'),
106 'migrate' : ('<Domain> <Host>',
107 'Migrate a domain to another machine.'),
108 'pause' : ('<Domain>', 'Pause execution of a domain.'),
109 'reboot' : ('<Domain> [-wa]', 'Reboot a domain.'),
110 'reset' : ('<Domain>', 'Reset a domain.'),
111 'restore' : ('<CheckpointFile> [-p]',
112 'Restore a domain from a saved state.'),
113 'save' : ('[-c] <Domain> <CheckpointFile>',
114 'Save a domain state to restore later.'),
115 'shutdown' : ('<Domain> [-waRH]', 'Shutdown a domain.'),
116 'top' : ('', 'Monitor a host and the domains in real time.'),
117 'unpause' : ('<Domain>', 'Unpause a paused domain.'),
118 'uptime' : ('[-s] [Domain, ...]',
119 'Print uptime for all/some domains.'),
121 # Life cycle xm commands
122 'new' : ('<ConfigFile> [options] [vars]',
123 'Adds a domain to Xend domain management'),
124 'delete' : ('<DomainName>',
125 'Remove a domain from Xend domain management.'),
126 'start' : ('<DomainName>', 'Start a Xend managed domain'),
127 'resume' : ('<DomainName>', 'Resume a Xend managed domain'),
128 'suspend' : ('<DomainName>', 'Suspend a Xend managed domain'),
130 # less used commands
132 'dmesg' : ('[-c|--clear]',
133 'Read and/or clear Xend\'s message buffer.'),
134 'domid' : ('<DomainName>', 'Convert a domain name to domain id.'),
135 'domname' : ('<DomId>', 'Convert a domain id to domain name.'),
136 'dump-core' : ('[-L|--live] [-C|--crash] [-R|--reset] <Domain> [Filename]',
137 'Dump core for a specific domain.'),
138 'info' : ('[-c|--config]', 'Get information about Xen host.'),
139 'log' : ('', 'Print Xend log'),
140 'rename' : ('<Domain> <NewDomainName>', 'Rename a domain.'),
141 'sched-sedf' : ('<Domain> [options]', 'Get/set EDF parameters.'),
142 'sched-credit': ('[-d <Domain> [-w[=WEIGHT]|-c[=CAP]]]',
143 'Get/set credit scheduler parameters.'),
144 'sysrq' : ('<Domain> <letter>', 'Send a sysrq to a domain.'),
145 'debug-keys' : ('<Keys>', 'Send debug keys to Xen.'),
146 'trigger' : ('<Domain> <nmi|reset|init> [<VCPU>]',
147 'Send a trigger to a domain.'),
148 'vcpu-list' : ('[Domain, ...]',
149 'List the VCPUs for all/some domains.'),
150 'vcpu-pin' : ('<Domain> <VCPU|all> <CPUs|all>',
151 'Set which CPUs a VCPU can use.'),
152 'vcpu-set' : ('<Domain> <vCPUs>',
153 'Set the number of active VCPUs for allowed for the'
154 ' domain.'),
156 # device commands
158 'block-attach' : ('<Domain> <BackDev> <FrontDev> <Mode> [BackDomain]',
159 'Create a new virtual block device.'),
160 'block-configure': ('<Domain> <BackDev> <FrontDev> <Mode> [BackDomain]',
161 'Change block device configuration'),
162 'block-detach' : ('<Domain> <DevId> [-f|--force]',
163 'Destroy a domain\'s virtual block device.'),
164 'block-list' : ('<Domain> [--long]',
165 'List virtual block devices for a domain.'),
166 'network-attach': ('<Domain> [type=<type>] [mac=<mac>] [bridge=<bridge>] '
167 '[ip=<ip>] [script=<script>] [backend=<BackDomain>] '
168 '[vifname=<name>] [rate=<rate>] [model=<model>]'
169 '[accel=<accel>]',
170 'Create a new virtual network device.'),
171 'network-detach': ('<Domain> <DevId> [-f|--force]',
172 'Destroy a domain\'s virtual network device.'),
173 'network-list' : ('<Domain> [--long]',
174 'List virtual network interfaces for a domain.'),
175 'vnet-create' : ('<ConfigFile>','Create a vnet from ConfigFile.'),
176 'vnet-delete' : ('<VnetId>', 'Delete a Vnet.'),
177 'vnet-list' : ('[-l|--long]', 'List Vnets.'),
178 'vtpm-list' : ('<Domain> [--long]', 'List virtual TPM devices.'),
179 'pci-attach' : ('<Domain> <domain:bus:slot.func> [virtual slot]',
180 'Insert a new pass-through pci device.'),
181 'pci-detach' : ('<Domain> <domain:bus:slot.func>',
182 'Remove a domain\'s pass-through pci device.'),
183 'pci-list' : ('<Domain>',
184 'List pass-through pci devices for a domain.'),
186 # security
188 'addlabel' : ('<label> {dom <ConfigFile>|res <resource>|mgt <managed domain>}\n'
189 ' [<policy>]',
190 'Add security label to domain.'),
191 'rmlabel' : ('{dom <ConfigFile>|res <Resource>|mgt<managed domain>}',
192 'Remove a security label from domain.'),
193 'getlabel' : ('{dom <ConfigFile>|res <Resource>|mgt <managed domain>}',
194 'Show security label for domain or resource.'),
195 'dry-run' : ('<ConfigFile>',
196 'Test if a domain can access its resources.'),
197 'resources' : ('', 'Show info for each labeled resource.'),
198 'dumppolicy' : ('', 'Print hypervisor ACM state information.'),
199 'setpolicy' : ('<policytype> <policyfile> [options]',
200 'Set the policy of the system.'),
201 'resetpolicy' : ('',
202 'Set the policy of the system to the default policy.'),
203 'getpolicy' : ('[options]', 'Get the policy of the system.'),
204 'labels' : ('[policy] [type=dom|res|any]',
205 'List <type> labels for (active) policy.'),
206 'serve' : ('', 'Proxy Xend XMLRPC over stdio.'),
207 }
209 SUBCOMMAND_OPTIONS = {
210 'sched-sedf': (
211 ('-p [MS]', '--period[=MS]', 'Relative deadline(ms)'),
212 ('-s [MS]', '--slice[=MS]' ,
213 'Worst-case execution time(ms). (slice < period)'),
214 ('-l [MS]', '--latency[=MS]',
215 'Scaled period (ms) when domain performs heavy I/O'),
216 ('-e [FLAG]', '--extra[=FLAG]',
217 'Flag (0 or 1) controls if domain can run in extra time.'),
218 ('-w [FLOAT]', '--weight[=FLOAT]',
219 'CPU Period/slice (do not set with --period/--slice)'),
220 ),
221 'sched-credit': (
222 ('-d DOMAIN', '--domain=DOMAIN', 'Domain to modify'),
223 ('-w WEIGHT', '--weight=WEIGHT', 'Weight (int)'),
224 ('-c CAP', '--cap=CAP', 'Cap (int)'),
225 ),
226 'list': (
227 ('-l', '--long', 'Output all VM details in SXP'),
228 ('', '--label', 'Include security labels'),
229 ('', '--state=<state>', 'Select only VMs with the specified state'),
230 ),
231 'console': (
232 ('-q', '--quiet', 'Do not print an error message if the domain does not exist'),
233 ),
234 'dmesg': (
235 ('-c', '--clear', 'Clear dmesg buffer as well as printing it'),
236 ),
237 'vnet-list': (
238 ('-l', '--long', 'List Vnets as SXP'),
239 ),
240 'network-list': (
241 ('-l', '--long', 'List resources as SXP'),
242 ),
243 'dump-core': (
244 ('-L', '--live', 'Dump core without pausing the domain'),
245 ('-C', '--crash', 'Crash domain after dumping core'),
246 ('-R', '--reset', 'Reset domain after dumping core'),
247 ),
248 'start': (
249 ('-p', '--paused', 'Do not unpause domain after starting it'),
250 ('-c', '--console_autoconnect', 'Connect to the console after the domain is created'),
251 ),
252 'resume': (
253 ('-p', '--paused', 'Do not unpause domain after resuming it'),
254 ),
255 'save': (
256 ('-c', '--checkpoint', 'Leave domain running after creating snapshot'),
257 ),
258 'restore': (
259 ('-p', '--paused', 'Do not unpause domain after restoring it'),
260 ),
261 'info': (
262 ('-c', '--config', 'List Xend configuration parameters'),
263 ),
264 }
266 common_commands = [
267 "console",
268 "create",
269 "new",
270 "delete",
271 "destroy",
272 "dump-core",
273 "help",
274 "list",
275 "mem-set",
276 "migrate",
277 "pause",
278 "reboot",
279 "reset",
280 "restore",
281 "resume",
282 "save",
283 "shell",
284 "shutdown",
285 "start",
286 "suspend",
287 "top",
288 "unpause",
289 "uptime",
290 "vcpu-set",
291 ]
293 domain_commands = [
294 "console",
295 "create",
296 "new",
297 "delete",
298 "destroy",
299 "domid",
300 "domname",
301 "dump-core",
302 "list",
303 "mem-max",
304 "mem-set",
305 "migrate",
306 "pause",
307 "reboot",
308 "rename",
309 "reset",
310 "restore",
311 "resume",
312 "save",
313 "shutdown",
314 "start",
315 "suspend",
316 "sysrq",
317 "trigger",
318 "top",
319 "unpause",
320 "uptime",
321 "vcpu-list",
322 "vcpu-pin",
323 "vcpu-set",
324 ]
326 host_commands = [
327 "debug-keys",
328 "dmesg",
329 "info",
330 "log",
331 "serve",
332 ]
334 scheduler_commands = [
335 "sched-credit",
336 "sched-sedf",
337 ]
339 device_commands = [
340 "block-attach",
341 "block-detach",
342 "block-list",
343 "block-configure",
344 "network-attach",
345 "network-detach",
346 "network-list",
347 "vtpm-list",
348 "pci-attach",
349 "pci-detach",
350 "pci-list",
351 ]
353 vnet_commands = [
354 "vnet-list",
355 "vnet-create",
356 "vnet-delete",
357 ]
359 acm_commands = [
360 "labels",
361 "addlabel",
362 "rmlabel",
363 "getlabel",
364 "dry-run",
365 "resources",
366 "dumppolicy",
367 "setpolicy",
368 "resetpolicy",
369 "getpolicy",
370 ]
372 all_commands = (domain_commands + host_commands + scheduler_commands +
373 device_commands + vnet_commands + acm_commands +
374 ['shell', 'event-monitor'])
377 ##
378 # Configuration File Parsing
379 ##
381 xmConfigFile = os.getenv(XM_CONFIG_FILE_ENVVAR, XM_CONFIG_FILE_DEFAULT)
382 config = None
383 if os.path.isfile(xmConfigFile):
384 try:
385 config = xml.dom.minidom.parse(xmConfigFile)
386 except:
387 print >>sys.stderr, ('Ignoring invalid configuration file %s.' %
388 xmConfigFile)
390 def parseServer():
391 if config:
392 server = config.getElementsByTagName('server')
393 if server:
394 st = server[0].getAttribute('type')
395 if st != SERVER_XEN_API and st != SERVER_LEGACY_XMLRPC:
396 print >>sys.stderr, ('Invalid server type %s; using %s.' %
397 (st, SERVER_LEGACY_XMLRPC))
398 st = SERVER_LEGACY_XMLRPC
399 return (st, server[0].getAttribute('uri'))
401 return SERVER_LEGACY_XMLRPC, XendClient.uri
403 def parseAuthentication():
404 server = config.getElementsByTagName('server')[0]
405 return (server.getAttribute('username'),
406 server.getAttribute('password'))
408 serverType, serverURI = parseServer()
409 server = None
412 ####################################################################
413 #
414 # Help/usage printing functions
415 #
416 ####################################################################
418 def cmdHelp(cmd):
419 """Print help for a specific subcommand."""
421 if not SUBCOMMAND_HELP.has_key(cmd):
422 for fc in SUBCOMMAND_HELP.keys():
423 if fc[:len(cmd)] == cmd:
424 cmd = fc
425 break
427 try:
428 args, desc = SUBCOMMAND_HELP[cmd]
429 except KeyError:
430 shortHelp()
431 return
433 print 'Usage: xm %s %s' % (cmd, args)
434 print
435 print desc
437 try:
438 # If options help message is defined, print this.
439 for shortopt, longopt, desc in SUBCOMMAND_OPTIONS[cmd]:
440 if shortopt and longopt:
441 optdesc = '%s, %s' % (shortopt, longopt)
442 elif shortopt:
443 optdesc = shortopt
444 elif longopt:
445 optdesc = longopt
447 wrapped_desc = wrap(desc, 43)
448 print ' %-30s %-43s' % (optdesc, wrapped_desc[0])
449 for line in wrapped_desc[1:]:
450 print ' ' * 33 + line
451 print
452 except KeyError:
453 # if the command is an external module, we grab usage help
454 # from the module itself.
455 if cmd in IMPORTED_COMMANDS:
456 try:
457 cmd_module = __import__(cmd, globals(), locals(), 'xen.xm')
458 cmd_usage = getattr(cmd_module, "help", None)
459 if cmd_usage:
460 print cmd_usage()
461 except ImportError:
462 pass
464 def shortHelp():
465 """Print out generic help when xm is called without subcommand."""
467 print USAGE_HELP
468 print 'Common \'xm\' commands:\n'
470 for command in common_commands:
471 try:
472 args, desc = SUBCOMMAND_HELP[command]
473 except KeyError:
474 continue
475 wrapped_desc = wrap(desc, 50)
476 print ' %-20s %-50s' % (command, wrapped_desc[0])
477 for line in wrapped_desc[1:]:
478 print ' ' * 22 + line
480 print
481 print USAGE_FOOTER
482 print 'For a complete list of subcommands run \'xm help\'.'
484 def longHelp():
485 """Print out full help when xm is called with xm --help or xm help"""
487 print USAGE_HELP
488 print 'xm full list of subcommands:\n'
490 for command in all_commands:
491 try:
492 args, desc = SUBCOMMAND_HELP[command]
493 except KeyError:
494 continue
496 wrapped_desc = wrap(desc, 50)
497 print ' %-20s %-50s' % (command, wrapped_desc[0])
498 for line in wrapped_desc[1:]:
499 print ' ' * 22 + line
501 print
502 print USAGE_FOOTER
504 def _usage(cmd):
505 """ Print help usage information """
506 if cmd:
507 cmdHelp(cmd)
508 else:
509 shortHelp()
511 def usage(cmd = None):
512 """ Print help usage information and exits """
513 _usage(cmd)
514 sys.exit(1)
517 ####################################################################
518 #
519 # Utility functions
520 #
521 ####################################################################
523 def get_default_SR():
524 return [sr_ref
525 for sr_ref in server.xenapi.SR.get_all()
526 if server.xenapi.SR.get_type(sr_ref) == "local"][0]
528 def get_default_Network():
529 return [network_ref
530 for network_ref in server.xenapi.network.get_all()][0]
532 class XenAPIUnsupportedException(Exception):
533 pass
535 def xenapi_unsupported():
536 if serverType == SERVER_XEN_API:
537 raise XenAPIUnsupportedException, "This function is not supported by Xen-API"
539 def xenapi_only():
540 if serverType != SERVER_XEN_API:
541 raise XenAPIUnsupportedException, "This function is only supported by Xen-API"
543 def map2sxp(m):
544 return [[k, m[k]] for k in m.keys()]
546 def arg_check(args, name, lo, hi = -1):
547 n = len([i for i in args if i != '--'])
549 if hi == -1:
550 if n != lo:
551 err("'xm %s' requires %d argument%s.\n" % (name, lo,
552 lo == 1 and '' or 's'))
553 usage(name)
554 else:
555 if n < lo or n > hi:
556 err("'xm %s' requires between %d and %d arguments.\n" %
557 (name, lo, hi))
558 usage(name)
561 def unit(c):
562 if not c.isalpha():
563 return 0
564 base = 1
565 if c == 'G' or c == 'g': base = 1024 * 1024 * 1024
566 elif c == 'M' or c == 'm': base = 1024 * 1024
567 elif c == 'K' or c == 'k': base = 1024
568 else:
569 print 'ignoring unknown unit'
570 return base
572 def int_unit(str, dest):
573 base = unit(str[-1])
574 if not base:
575 return int(str)
577 value = int(str[:-1])
578 dst_base = unit(dest)
579 if dst_base == 0:
580 dst_base = 1
581 if dst_base > base:
582 return value / (dst_base / base)
583 else:
584 return value * (base / dst_base)
586 def err(msg):
587 print >>sys.stderr, "Error:", msg
590 def get_single_vm(dom):
591 if serverType == SERVER_XEN_API:
592 uuids = server.xenapi.VM.get_by_name_label(dom)
593 if len(uuids) > 0:
594 return uuids[0]
596 refs = []
598 try:
599 domid = int(dom)
600 refs = [vm_ref
601 for vm_ref in server.xenapi.VM.get_all()
602 if int(server.xenapi.VM.get_domid(vm_ref)) == domid]
603 except:
604 pass
606 if len(refs) > 0:
607 return refs[0]
609 raise OptionError("Domain '%s' not found." % dom)
610 else:
611 dominfo = server.xend.domain(dom, False)
612 return dominfo['uuid']
614 ##
615 #
616 # Xen-API Shell
617 #
618 ##
620 class Shell(cmd.Cmd):
621 def __init__(self):
622 cmd.Cmd.__init__(self)
623 self.prompt = "xm> "
624 if serverType == SERVER_XEN_API:
625 try:
626 res = server.xenapi.host.list_methods()
627 for f in res:
628 setattr(Shell, 'do_' + f + ' ', self.default)
629 except:
630 pass
632 def preloop(self):
633 cmd.Cmd.preloop(self)
634 try:
635 import readline
636 readline.set_completer_delims(' ')
637 except ImportError:
638 pass
640 def default(self, line):
641 words = shlex.split(line)
642 if len(words) > 0 and words[0] == 'xm':
643 words = words[1:]
644 if len(words) > 0:
645 cmd = xm_lookup_cmd(words[0])
646 if cmd:
647 _run_cmd(cmd, words[0], words[1:])
648 elif serverType == SERVER_XEN_API:
649 ok, res = _run_cmd(lambda x: server.xenapi_request(words[0],
650 tuple(x)),
651 words[0], words[1:])
652 if ok and res is not None and res != '':
653 pprint.pprint(res)
654 else:
655 print '*** Unknown command: %s' % words[0]
656 return False
658 def completedefault(self, text, line, begidx, endidx):
659 words = shlex.split(line[:begidx])
660 clas, func = words[0].split('.')
661 if len(words) > 1 or \
662 func.startswith('get_by_') or \
663 func == 'get_all':
664 return []
665 uuids = server.xenapi_request('%s.get_all' % clas, ())
666 return [u + " " for u in uuids if u.startswith(text)]
668 def emptyline(self):
669 pass
671 def do_EOF(self, line):
672 print
673 sys.exit(0)
675 def do_help(self, line):
676 _usage(line)
679 def xm_shell(args):
680 Shell().cmdloop('The Xen Master. Type "help" for a list of functions.')
683 def xm_event_monitor(args):
684 if serverType == SERVER_XEN_API:
685 while True:
686 server.xenapi.event.register(args)
687 events = server.xenapi.event.next()
688 for e in events:
689 print e
690 else:
691 err("Event monitoring not supported unless using Xen-API.")
694 #########################################################################
695 #
696 # Main xm functions
697 #
698 #########################################################################
700 def xm_save(args):
702 arg_check(args, "save", 2, 3)
704 try:
705 (options, params) = getopt.gnu_getopt(args, 'c', ['checkpoint'])
706 except getopt.GetoptError, opterr:
707 err(opterr)
708 sys.exit(1)
710 checkpoint = False
711 for (k, v) in options:
712 if k in ['-c', '--checkpoint']:
713 checkpoint = True
715 if len(params) != 2:
716 err("Wrong number of parameters")
717 usage('save')
719 dom = params[0]
720 savefile = os.path.abspath(params[1])
722 if not os.access(os.path.dirname(savefile), os.W_OK):
723 err("xm save: Unable to create file %s" % savefile)
724 sys.exit(1)
726 if serverType == SERVER_XEN_API:
727 server.xenapi.VM.save(get_single_vm(dom), savefile, checkpoint)
728 else:
729 server.xend.domain.save(dom, savefile, checkpoint)
731 def xm_restore(args):
732 arg_check(args, "restore", 1, 2)
734 try:
735 (options, params) = getopt.gnu_getopt(args, 'p', ['paused'])
736 except getopt.GetoptError, opterr:
737 err(opterr)
738 usage('restore')
740 paused = False
741 for (k, v) in options:
742 if k in ['-p', '--paused']:
743 paused = True
745 if len(params) != 1:
746 err("Wrong number of parameters")
747 usage('restore')
749 savefile = os.path.abspath(params[0])
751 if not os.access(savefile, os.R_OK):
752 err("xm restore: Unable to read file %s" % savefile)
753 sys.exit(1)
755 if serverType == SERVER_XEN_API:
756 server.xenapi.VM.restore(savefile, paused)
757 else:
758 server.xend.domain.restore(savefile, paused)
761 def datetime_to_secs(v):
762 unwanted = ":-."
763 for c in unwanted:
764 v = str(v).replace(c, "")
765 return time.mktime(time.strptime(v[0:14], '%Y%m%dT%H%M%S'))
767 def getDomains(domain_names, state, full = 0):
768 if serverType == SERVER_XEN_API:
769 doms_sxp = []
770 doms_dict = []
772 dom_recs = server.xenapi.VM.get_all_records()
773 dom_metrics_recs = server.xenapi.VM_metrics.get_all_records()
775 for dom_ref, dom_rec in dom_recs.items():
776 dom_metrics_rec = dom_metrics_recs[dom_rec['metrics']]
778 states = ('running', 'blocked', 'paused', 'shutdown',
779 'crashed', 'dying')
780 def state_on_off(state):
781 if state in dom_metrics_rec['state']:
782 return state[0]
783 else:
784 return "-"
785 state_str = "".join([state_on_off(state)
786 for state in states])
788 dom_rec.update({'name': dom_rec['name_label'],
789 'memory_actual': int(dom_metrics_rec['memory_actual'])/1024,
790 'vcpus': dom_metrics_rec['VCPUs_number'],
791 'state': state_str,
792 'cpu_time': dom_metrics_rec['VCPUs_utilisation'],
793 'start_time': datetime_to_secs(
794 dom_metrics_rec['start_time'])})
796 doms_sxp.append(['domain'] + map2sxp(dom_rec))
797 doms_dict.append(dom_rec)
799 if domain_names:
800 doms = [['domain'] + map2sxp(dom) for dom in doms_dict
801 if dom["name"] in domain_names]
803 if len(doms) > 0:
804 return doms
805 else:
806 print "Error: no domain%s named %s" % \
807 (len(domain_names) > 1 and 's' or '',
808 ', '.join(domain_names))
809 sys.exit(-1)
810 else:
811 return doms_sxp
812 else:
813 if domain_names:
814 return [server.xend.domain(dom, full) for dom in domain_names]
815 else:
816 return server.xend.domains_with_state(True, state, full)
819 def xm_list(args):
820 use_long = 0
821 show_vcpus = 0
822 show_labels = 0
823 state = 'all'
824 try:
825 (options, params) = getopt.gnu_getopt(args, 'lv',
826 ['long','vcpus','label',
827 'state='])
828 except getopt.GetoptError, opterr:
829 err(opterr)
830 usage('list')
832 for (k, v) in options:
833 if k in ['-l', '--long']:
834 use_long = 1
835 if k in ['-v', '--vcpus']:
836 show_vcpus = 1
837 if k in ['--label']:
838 show_labels = 1
839 if k in ['--state']:
840 state = v
842 if state != 'all' and len(params) > 0:
843 raise OptionError(
844 "You may specify either a state or a particular VM, but not both")
846 if show_vcpus:
847 print >>sys.stderr, (
848 "xm list -v is deprecated. Please use xm vcpu-list.")
849 xm_vcpu_list(params)
850 return
852 doms = getDomains(params, state, use_long)
854 if use_long:
855 map(PrettyPrint.prettyprint, doms)
856 elif show_labels:
857 xm_label_list(doms)
858 else:
859 xm_brief_list(doms)
862 def parse_doms_info(info):
863 def get_info(n, t, d):
864 return t(sxp.child_value(info, n, d))
866 def get_status(n, t, d):
867 return DOM_STATES[t(sxp.child_value(info, n, d))]
869 start_time = get_info('start_time', float, -1)
870 if start_time == -1:
871 up_time = float(-1)
872 else:
873 up_time = time.time() - start_time
875 parsed_info = {
876 'domid' : get_info('domid', str, ''),
877 'name' : get_info('name', str, '??'),
878 'state' : get_info('state', str, ''),
880 # VCPUs is the number online when the VM is up, or the number
881 # configured otherwise.
882 'vcpus' : get_info('online_vcpus', int,
883 get_info('vcpus', int, 0)),
884 'up_time' : up_time
885 }
887 security_label = get_info('security_label', str, '')
888 parsed_info['seclabel'] = security.parse_security_label(security_label)
890 if serverType == SERVER_XEN_API:
891 parsed_info['mem'] = get_info('memory_actual', int, 0) / 1024
892 cpu_times = get_info('cpu_time', lambda x : (x), 0.0)
893 if sum(cpu_times.values()) > 0:
894 parsed_info['cpu_time'] = sum(cpu_times.values()) / float(len(cpu_times.values()))
895 else:
896 parsed_info['cpu_time'] = 0
897 else:
898 parsed_info['mem'] = get_info('memory', int,0)
899 parsed_info['cpu_time'] = get_info('cpu_time', float, 0.0)
901 return parsed_info
903 def check_sched_type(sched):
904 if serverType == SERVER_XEN_API:
905 current = server.xenapi.host.get_sched_policy(
906 server.xenapi.session.get_this_host(server.getSession()))
907 else:
908 current = 'unknown'
909 for x in server.xend.node.info()[1:]:
910 if len(x) > 1 and x[0] == 'xen_scheduler':
911 current = x[1]
912 break
913 if sched != current:
914 err("Xen is running with the %s scheduler" % current)
915 sys.exit(1)
917 def parse_sedf_info(info):
918 def get_info(n, t, d):
919 return t(sxp.child_value(info, n, d))
921 return {
922 'domid' : get_info('domid', int, -1),
923 'period' : get_info('period', int, -1),
924 'slice' : get_info('slice', int, -1),
925 'latency' : get_info('latency', int, -1),
926 'extratime': get_info('extratime', int, -1),
927 'weight' : get_info('weight', int, -1),
928 }
930 def domid_match(domid, info):
931 return domid is None or domid == info['name'] or \
932 domid == str(info['domid'])
934 def xm_brief_list(doms):
935 print '%-40s %5s %5s %5s %10s %9s' % \
936 ('Name', 'ID', 'Mem', 'VCPUs', 'State', 'Time(s)')
938 format = "%(name)-40s %(domid)5s %(mem)5d %(vcpus)5d %(state)10s " \
939 "%(cpu_time)8.1f"
941 for dom in doms:
942 d = parse_doms_info(dom)
943 print format % d
945 def xm_label_list(doms):
946 print '%-40s %5s %5s %5s %10s %9s %-10s' % \
947 ('Name', 'ID', 'Mem', 'VCPUs', 'State', 'Time(s)', 'Label')
949 output = []
950 format = '%(name)-40s %(domid)5s %(mem)5d %(vcpus)5d %(state)10s ' \
951 '%(cpu_time)8.1f %(seclabel)10s'
953 for dom in doms:
954 d = parse_doms_info(dom)
955 if d['seclabel'] == "" and serverType != SERVER_XEN_API:
956 seclab = server.xend.security.get_domain_label(d['name'])
957 if len(seclab) > 0 and seclab[0] == '\'':
958 seclab = seclab[1:]
959 d['seclabel'] = seclab
960 output.append((format % d, d['seclabel']))
962 #sort by labels
963 output.sort(lambda x,y: cmp( x[1].lower(), y[1].lower()))
964 for line, label in output:
965 print line
968 def xm_vcpu_list(args):
969 if serverType == SERVER_XEN_API:
970 if args:
971 vm_refs = map(get_single_vm, args)
972 else:
973 vm_refs = server.xenapi.VM.get_all()
975 vm_records = dict(map(lambda vm_ref:
976 (vm_ref, server.xenapi.VM.get_record(
977 vm_ref)),
978 vm_refs))
980 vm_metrics = dict(map(lambda (ref, record):
981 (ref,
982 server.xenapi.VM_metrics.get_record(
983 record['metrics'])),
984 vm_records.items()))
986 dominfo = []
988 # vcpu_list doesn't list 'managed' domains
989 # when they are not running, so filter them out
991 vm_refs = [vm_ref
992 for vm_ref in vm_refs
993 if vm_records[vm_ref]["power_state"] != "Halted"]
995 for vm_ref in vm_refs:
996 info = ['domain',
997 ['domid', vm_records[vm_ref]['domid']],
998 ['name', vm_records[vm_ref]['name_label']],
999 ['vcpu_count', vm_records[vm_ref]['VCPUs_max']]]
1001 for i in range(int(vm_records[vm_ref]['VCPUs_max'])):
1002 def chk_flag(flag):
1003 return flag in vm_metrics[vm_ref]['VCPUs_flags'][str(i)] \
1004 and 1 or 0
1006 vcpu_info = ['vcpu',
1007 ['number',
1008 i],
1009 ['online',
1010 chk_flag("online")],
1011 ['blocked',
1012 chk_flag("blocked")],
1013 ['running',
1014 chk_flag("running")],
1015 ['cpu_time',
1016 vm_metrics[vm_ref]['VCPUs_utilisation'][str(i)]],
1017 ['cpu',
1018 vm_metrics[vm_ref]['VCPUs_CPU'][str(i)]],
1019 ['cpumap',
1020 vm_metrics[vm_ref]['VCPUs_params']\
1021 ['cpumap%i' % i].split(",")]]
1023 info.append(vcpu_info)
1025 dominfo.append(info)
1026 else:
1027 if args:
1028 dominfo = map(server.xend.domain.getVCPUInfo, args)
1029 else:
1030 doms = server.xend.domains_with_state(False, 'all', False)
1031 dominfo = map(server.xend.domain.getVCPUInfo, doms)
1033 print '%-32s %5s %5s %5s %5s %9s %s' % \
1034 ('Name', 'ID', 'VCPU', 'CPU', 'State', 'Time(s)', 'CPU Affinity')
1036 format = '%(name)-32s %(domid)5s %(number)5d %(c)5s %(s)5s ' \
1037 ' %(cpu_time)8.1f %(cpumap)s'
1039 for dom in dominfo:
1040 def get_info(n):
1041 return sxp.child_value(dom, n)
1044 # convert a list of integers into a list of pairs indicating
1045 # continuous sequences in the list:
1047 # [0,1,2,3] -> [(0,3)]
1048 # [1,2,4,5] -> [(1,2),(4,5)]
1049 # [0] -> [(0,0)]
1050 # [0,1,4,6,7] -> [(0,1),(4,4),(6,7)]
1052 def list_to_rangepairs(cmap):
1053 cmap.sort()
1054 pairs = []
1055 x = y = 0
1056 for i in range(0,len(cmap)):
1057 try:
1058 if ((cmap[y+1] - cmap[i]) > 1):
1059 pairs.append((cmap[x],cmap[y]))
1060 x = y = i+1
1061 else:
1062 y = y + 1
1063 # if we go off the end, then just add x to y
1064 except IndexError:
1065 pairs.append((cmap[x],cmap[y]))
1067 return pairs
1070 # Convert pairs to range string, e.g: [(1,2),(3,3),(5,7)] -> 1-2,3,5-7
1072 def format_pairs(pairs):
1073 if not pairs:
1074 return "no cpus"
1075 out = ""
1076 for f,s in pairs:
1077 if (f==s):
1078 out += '%d'%f
1079 else:
1080 out += '%d-%d'%(f,s)
1081 out += ','
1082 # trim trailing ','
1083 return out[:-1]
1085 def format_cpumap(cpumap):
1086 cpumap = map(lambda x: int(x), cpumap)
1087 cpumap.sort()
1089 if serverType == SERVER_XEN_API:
1090 nr_cpus = len(server.xenapi.host.get_host_CPUs(
1091 server.xenapi.session.get_this_host(server.getSession())))
1092 else:
1093 for x in server.xend.node.info()[1:]:
1094 if len(x) > 1 and x[0] == 'nr_cpus':
1095 nr_cpus = int(x[1])
1097 # normalize cpumap by modulus nr_cpus, and drop duplicates
1098 cpumap = dict.fromkeys(
1099 filter(lambda x: x < nr_cpus, cpumap)).keys()
1100 if len(cpumap) == nr_cpus:
1101 return "any cpu"
1103 return format_pairs(list_to_rangepairs(cpumap))
1105 name = get_info('name')
1106 domid = get_info('domid')
1107 if domid is not None:
1108 domid = str(domid)
1109 else:
1110 domid = ''
1112 for vcpu in sxp.children(dom, 'vcpu'):
1113 def vinfo(n, t):
1114 return t(sxp.child_value(vcpu, n))
1116 number = vinfo('number', int)
1117 cpu = vinfo('cpu', int)
1118 cpumap = format_cpumap(vinfo('cpumap', list))
1119 online = vinfo('online', int)
1120 cpu_time = vinfo('cpu_time', float)
1121 running = vinfo('running', int)
1122 blocked = vinfo('blocked', int)
1124 if cpu < 0:
1125 c = ''
1126 s = ''
1127 elif online:
1128 c = str(cpu)
1129 if running:
1130 s = 'r'
1131 else:
1132 s = '-'
1133 if blocked:
1134 s += 'b'
1135 else:
1136 s += '-'
1137 s += '-'
1138 else:
1139 c = '-'
1140 s = '--p'
1142 print format % locals()
1144 def start_do_console(domain_name):
1145 cpid = os.fork()
1146 if cpid != 0:
1147 for i in range(10):
1148 # Catch failure of the create process
1149 time.sleep(1)
1150 (p, rv) = os.waitpid(cpid, os.WNOHANG)
1151 if os.WIFEXITED(rv):
1152 if os.WEXITSTATUS(rv) != 0:
1153 sys.exit(os.WEXITSTATUS(rv))
1154 try:
1155 # Acquire the console of the created dom
1156 if serverType == SERVER_XEN_API:
1157 domid = server.xenapi.VM.get_domid(
1158 get_single_vm(domain_name))
1159 else:
1160 dom = server.xend.domain(domain_name)
1161 domid = int(sxp.child_value(dom, 'domid', '-1'))
1162 console.execConsole(domid)
1163 except:
1164 pass
1165 print("Could not start console\n");
1166 sys.exit(0)
1168 def xm_start(args):
1170 paused = False
1171 console_autoconnect = False
1173 try:
1174 (options, params) = getopt.gnu_getopt(args, 'cp', ['console_autoconnect','paused'])
1175 for (k, v) in options:
1176 if k in ('-p', '--paused'):
1177 paused = True
1178 if k in ('-c', '--console_autoconnect'):
1179 console_autoconnect = True
1181 if len(params) != 1:
1182 raise OptionError("Expects 1 argument")
1183 except getopt.GetoptError, opterr:
1184 err(opterr)
1185 usage('start')
1187 dom = params[0]
1189 if console_autoconnect:
1190 start_do_console(dom)
1192 try:
1193 if serverType == SERVER_XEN_API:
1194 server.xenapi.VM.start(get_single_vm(dom), paused)
1195 domid = int(server.xenapi.VM.get_domid(get_single_vm(dom)))
1196 else:
1197 server.xend.domain.start(dom, paused)
1198 info = server.xend.domain(dom)
1199 domid = int(sxp.child_value(info, 'domid', '-1'))
1200 except:
1201 raise
1203 if domid == -1:
1204 raise xmlrpclib.Fault(0, "Domain '%s' is not started" % dom)
1206 def xm_delete(args):
1207 arg_check(args, "delete", 1)
1208 dom = args[0]
1209 if serverType == SERVER_XEN_API:
1210 server.xenapi.VM.destroy(get_single_vm(dom))
1211 else:
1212 server.xend.domain.delete(dom)
1214 def xm_suspend(args):
1215 arg_check(args, "suspend", 1)
1216 dom = args[0]
1217 if serverType == SERVER_XEN_API:
1218 server.xenapi.VM.suspend(get_single_vm(dom))
1219 else:
1220 server.xend.domain.suspend(dom)
1222 def xm_resume(args):
1223 arg_check(args, "resume", 1, 2)
1225 try:
1226 (options, params) = getopt.gnu_getopt(args, 'p', ['paused'])
1227 except getopt.GetoptError, opterr:
1228 err(opterr)
1229 usage('resume')
1231 paused = False
1232 for (k, v) in options:
1233 if k in ['-p', '--paused']:
1234 paused = True
1236 if len(params) != 1:
1237 err("Wrong number of parameters")
1238 usage('resume')
1240 dom = params[0]
1241 if serverType == SERVER_XEN_API:
1242 server.xenapi.VM.resume(get_single_vm(dom), paused)
1243 else:
1244 server.xend.domain.resume(dom, paused)
1246 def xm_reboot(args):
1247 arg_check(args, "reboot", 1, 3)
1248 from xen.xm import shutdown
1249 shutdown.main(["shutdown", "-R"] + args)
1251 def xm_shutdown(args):
1252 arg_check(args, "shutdown", 1, 4)
1253 from xen.xm import shutdown
1254 shutdown.main(["shutdown"] + args)
1256 def xm_reset(args):
1257 arg_check(args, "reset", 1)
1258 dom = args[0]
1260 # TODO: XenAPI
1261 server.xend.domain.reset(dom)
1263 def xm_pause(args):
1264 arg_check(args, "pause", 1)
1265 dom = args[0]
1267 if serverType == SERVER_XEN_API:
1268 server.xenapi.VM.pause(get_single_vm(dom))
1269 else:
1270 server.xend.domain.pause(dom)
1272 def xm_unpause(args):
1273 arg_check(args, "unpause", 1)
1274 dom = args[0]
1276 if serverType == SERVER_XEN_API:
1277 server.xenapi.VM.unpause(get_single_vm(dom))
1278 else:
1279 server.xend.domain.unpause(dom)
1281 def xm_dump_core(args):
1282 live = False
1283 crash = False
1284 reset = False
1285 try:
1286 (options, params) = getopt.gnu_getopt(args, 'LCR', ['live', 'crash', 'reset'])
1287 for (k, v) in options:
1288 if k in ('-L', '--live'):
1289 live = True
1290 elif k in ('-C', '--crash'):
1291 crash = True
1292 elif k in ('-R', '--reset'):
1293 reset = True
1295 if crash and reset:
1296 raise OptionError("You may not specify more than one '-CR' option")
1297 if len(params) not in (1, 2):
1298 raise OptionError("Expects 1 or 2 argument(s)")
1299 except getopt.GetoptError, e:
1300 raise OptionError(str(e))
1302 dom = params[0]
1303 if len(params) == 2:
1304 filename = os.path.abspath(params[1])
1305 else:
1306 filename = None
1308 if not live:
1309 ds = server.xend.domain.pause(dom, True)
1311 try:
1312 print "Dumping core of domain: %s ..." % str(dom)
1313 server.xend.domain.dump(dom, filename, live, crash)
1315 if crash:
1316 print "Destroying domain: %s ..." % str(dom)
1317 server.xend.domain.destroy(dom)
1318 elif reset:
1319 print "Resetting domain: %s ..." % str(dom)
1320 server.xend.domain.reset(dom)
1321 finally:
1322 if not live and not crash and not reset and ds == DOM_STATE_RUNNING:
1323 server.xend.domain.unpause(dom)
1325 def xm_rename(args):
1326 arg_check(args, "rename", 2)
1328 if serverType == SERVER_XEN_API:
1329 server.xenapi.VM.set_name_label(get_single_vm(args[0]), args[1])
1330 else:
1331 server.xend.domain.setName(args[0], args[1])
1333 def xm_importcommand(command, args):
1334 cmd = __import__(command, globals(), locals(), 'xen.xm')
1335 cmd.main([command] + args)
1338 #############################################################
1340 def xm_vcpu_pin(args):
1341 arg_check(args, "vcpu-pin", 3)
1343 def cpu_make_map(cpulist):
1344 cpus = []
1345 for c in cpulist.split(','):
1346 if c.find('-') != -1:
1347 (x,y) = c.split('-')
1348 for i in range(int(x),int(y)+1):
1349 cpus.append(int(i))
1350 else:
1351 # remove this element from the list
1352 if c[0] == '^':
1353 cpus = [x for x in cpus if x != int(c[1:])]
1354 else:
1355 cpus.append(int(c))
1356 cpus.sort()
1357 return cpus
1359 dom = args[0]
1360 vcpu = args[1]
1361 if args[2] == 'all':
1362 cpumap = cpu_make_map('0-63')
1363 else:
1364 cpumap = cpu_make_map(args[2])
1366 if serverType == SERVER_XEN_API:
1367 cpumap = map(str, cpumap)
1368 server.xenapi.VM.add_to_VCPUs_params_live(
1369 get_single_vm(dom), "cpumap%i" % int(vcpu), ",".join(cpumap))
1370 else:
1371 server.xend.domain.pincpu(dom, vcpu, cpumap)
1373 def xm_mem_max(args):
1374 arg_check(args, "mem-max", 2)
1376 dom = args[0]
1378 if serverType == SERVER_XEN_API:
1379 mem = int_unit(args[1], 'k') * 1024
1380 server.xenapi.VM.set_memory_static_max(get_single_vm(dom), mem)
1381 else:
1382 mem = int_unit(args[1], 'm')
1383 server.xend.domain.maxmem_set(dom, mem)
1385 def xm_mem_set(args):
1386 arg_check(args, "mem-set", 2)
1388 dom = args[0]
1390 if serverType == SERVER_XEN_API:
1391 mem_target = int_unit(args[1], 'm') * 1024 * 1024
1392 server.xenapi.VM.set_memory_dynamic_max_live(get_single_vm(dom),
1393 mem_target)
1394 server.xenapi.VM.set_memory_dynamic_min_live(get_single_vm(dom),
1395 mem_target)
1396 else:
1397 mem_target = int_unit(args[1], 'm')
1398 server.xend.domain.setMemoryTarget(dom, mem_target)
1400 def xm_vcpu_set(args):
1401 arg_check(args, "vcpu-set", 2)
1403 dom = args[0]
1404 vcpus = int(args[1])
1406 if serverType == SERVER_XEN_API:
1407 server.xenapi.VM.set_VCPUs_number_live(get_single_vm(dom), vcpus)
1408 else:
1409 server.xend.domain.setVCpuCount(dom, vcpus)
1411 def xm_destroy(args):
1412 arg_check(args, "destroy", 1)
1414 dom = args[0]
1416 if serverType == SERVER_XEN_API:
1417 server.xenapi.VM.hard_shutdown(get_single_vm(dom))
1418 else:
1419 server.xend.domain.destroy(dom)
1421 def xm_domid(args):
1422 arg_check(args, "domid", 1)
1424 name = args[0]
1426 if serverType == SERVER_XEN_API:
1427 print server.xenapi.VM.get_domid(get_single_vm(name))
1428 else:
1429 dom = server.xend.domain(name)
1430 print sxp.child_value(dom, 'domid')
1432 def xm_domname(args):
1433 arg_check(args, "domname", 1)
1435 name = args[0]
1437 if serverType == SERVER_XEN_API:
1438 print server.xenapi.VM.get_name_label(get_single_vm(name))
1439 else:
1440 dom = server.xend.domain(name)
1441 print sxp.child_value(dom, 'name')
1443 def xm_sched_sedf(args):
1444 xenapi_unsupported()
1446 def ns_to_ms(val):
1447 return float(val) * 0.000001
1449 def ms_to_ns(val):
1450 return (float(val) / 0.000001)
1452 def print_sedf(info):
1453 info['period'] = ns_to_ms(info['period'])
1454 info['slice'] = ns_to_ms(info['slice'])
1455 info['latency'] = ns_to_ms(info['latency'])
1456 print( ("%(name)-32s %(domid)5d %(period)9.1f %(slice)9.1f" +
1457 " %(latency)7.1f %(extratime)6d %(weight)6d") % info)
1459 check_sched_type('sedf')
1461 # we want to just display current info if no parameters are passed
1462 if len(args) == 0:
1463 domid = None
1464 else:
1465 # we expect at least a domain id (name or number)
1466 # and at most a domid up to 5 options with values
1467 arg_check(args, "sched-sedf", 1, 11)
1468 domid = args[0]
1469 # drop domid from args since get_opt doesn't recognize it
1470 args = args[1:]
1472 opts = {}
1473 try:
1474 (options, params) = getopt.gnu_getopt(args, 'p:s:l:e:w:',
1475 ['period=', 'slice=', 'latency=', 'extratime=', 'weight='])
1476 except getopt.GetoptError, opterr:
1477 err(opterr)
1478 usage('sched-sedf')
1480 # convert to nanoseconds if needed
1481 for (k, v) in options:
1482 if k in ['-p', '--period']:
1483 opts['period'] = ms_to_ns(v)
1484 elif k in ['-s', '--slice']:
1485 opts['slice'] = ms_to_ns(v)
1486 elif k in ['-l', '--latency']:
1487 opts['latency'] = ms_to_ns(v)
1488 elif k in ['-e', '--extratime']:
1489 opts['extratime'] = v
1490 elif k in ['-w', '--weight']:
1491 opts['weight'] = v
1493 doms = filter(lambda x : domid_match(domid, x),
1494 [parse_doms_info(dom)
1495 for dom in getDomains(None, 'running')])
1496 if domid is not None and doms == []:
1497 err("Domain '%s' does not exist." % domid)
1498 usage('sched-sedf')
1500 # print header if we aren't setting any parameters
1501 if len(opts.keys()) == 0:
1502 print '%-33s %4s %-4s %-4s %-7s %-5s %-6s' % \
1503 ('Name','ID','Period(ms)', 'Slice(ms)', 'Lat(ms)',
1504 'Extra','Weight')
1506 for d in doms:
1507 # fetch current values so as not to clobber them
1508 try:
1509 sedf_raw = server.xend.domain.cpu_sedf_get(d['domid'])
1510 except xmlrpclib.Fault:
1511 # domain does not support sched-sedf?
1512 sedf_raw = {}
1514 sedf_info = parse_sedf_info(sedf_raw)
1515 sedf_info['name'] = d['name']
1516 # update values in case of call to set
1517 if len(opts.keys()) > 0:
1518 for k in opts.keys():
1519 sedf_info[k]=opts[k]
1521 # send the update, converting user input
1522 v = map(int, [sedf_info['period'], sedf_info['slice'],
1523 sedf_info['latency'],sedf_info['extratime'],
1524 sedf_info['weight']])
1525 rv = server.xend.domain.cpu_sedf_set(d['domid'], *v)
1526 if int(rv) != 0:
1527 err("Failed to set sedf parameters (rv=%d)."%(rv))
1529 # not setting values, display info
1530 else:
1531 print_sedf(sedf_info)
1533 def xm_sched_credit(args):
1534 """Get/Set options for Credit Scheduler."""
1536 check_sched_type('credit')
1538 try:
1539 opts, params = getopt.getopt(args, "d:w:c:",
1540 ["domain=", "weight=", "cap="])
1541 except getopt.GetoptError, opterr:
1542 err(opterr)
1543 usage('sched-credit')
1545 domid = None
1546 weight = None
1547 cap = None
1549 for o, a in opts:
1550 if o in ["-d", "--domain"]:
1551 domid = a
1552 elif o in ["-w", "--weight"]:
1553 weight = int(a)
1554 elif o in ["-c", "--cap"]:
1555 cap = int(a);
1557 doms = filter(lambda x : domid_match(domid, x),
1558 [parse_doms_info(dom)
1559 for dom in getDomains(None, 'all')])
1561 if weight is None and cap is None:
1562 if domid is not None and doms == []:
1563 err("Domain '%s' does not exist." % domid)
1564 usage('sched-credit')
1565 # print header if we aren't setting any parameters
1566 print '%-33s %4s %6s %4s' % ('Name','ID','Weight','Cap')
1568 for d in doms:
1569 try:
1570 if serverType == SERVER_XEN_API:
1571 info = server.xenapi.VM_metrics.get_VCPUs_params(
1572 server.xenapi.VM.get_metrics(
1573 get_single_vm(d['name'])))
1574 else:
1575 info = server.xend.domain.sched_credit_get(d['name'])
1576 except xmlrpclib.Fault:
1577 pass
1579 if 'weight' not in info or 'cap' not in info:
1580 # domain does not support sched-credit?
1581 info = {'weight': -1, 'cap': -1}
1583 info['weight'] = int(info['weight'])
1584 info['cap'] = int(info['cap'])
1586 info['name'] = d['name']
1587 info['domid'] = str(d['domid'])
1588 print( ("%(name)-32s %(domid)5s %(weight)6d %(cap)4d") % info)
1589 else:
1590 if domid is None:
1591 # place holder for system-wide scheduler parameters
1592 err("No domain given.")
1593 usage('sched-credit')
1595 if serverType == SERVER_XEN_API:
1596 if doms[0]['domid']:
1597 server.xenapi.VM.add_to_VCPUs_params_live(
1598 get_single_vm(domid),
1599 "weight",
1600 weight)
1601 server.xenapi.VM.add_to_VCPUs_params_live(
1602 get_single_vm(domid),
1603 "cap",
1604 cap)
1605 else:
1606 server.xenapi.VM.add_to_VCPUs_params(
1607 get_single_vm(domid),
1608 "weight",
1609 weight)
1610 server.xenapi.VM.add_to_VCPUs_params(
1611 get_single_vm(domid),
1612 "cap",
1613 cap)
1614 else:
1615 result = server.xend.domain.sched_credit_set(domid, weight, cap)
1616 if result != 0:
1617 err(str(result))
1619 def xm_info(args):
1620 arg_check(args, "info", 0, 1)
1622 try:
1623 (options, params) = getopt.gnu_getopt(args, 'c', ['config'])
1624 except getopt.GetoptError, opterr:
1625 err(opterr)
1626 usage('info')
1628 show_xend_config = 0
1629 for (k, v) in options:
1630 if k in ['-c', '--config']:
1631 show_xend_config = 1
1633 if show_xend_config:
1634 for name, obj in inspect.getmembers(xoptions):
1635 if not inspect.ismethod(obj):
1636 if name == "config":
1637 for x in obj[1:]:
1638 if len(x) < 2:
1639 print "%-38s: (none)" % x[0]
1640 else:
1641 print "%-38s:" % x[0], x[1]
1642 else:
1643 print "%-38s:" % name, obj
1644 return
1646 if serverType == SERVER_XEN_API:
1648 # Need to fake out old style xm info as people rely on parsing it
1650 host_record = server.xenapi.host.get_record(
1651 server.xenapi.session.get_this_host(server.getSession()))
1653 host_cpu_records = map(server.xenapi.host_cpu.get_record, host_record["host_CPUs"])
1655 host_metrics_record = server.xenapi.host_metrics.get_record(host_record["metrics"])
1657 def getVal(keys, default=""):
1658 data = host_record
1659 for key in keys:
1660 if key in data:
1661 data = data[key]
1662 else:
1663 return default
1664 return data
1666 def getCpuMhz():
1667 cpu_speeds = [int(host_cpu_record["speed"])
1668 for host_cpu_record in host_cpu_records
1669 if "speed" in host_cpu_record]
1670 if len(cpu_speeds) > 0:
1671 return sum(cpu_speeds) / len(cpu_speeds)
1672 else:
1673 return 0
1675 getCpuMhz()
1677 def getCpuFeatures():
1678 if len(host_cpu_records) > 0:
1679 return host_cpu_records[0].get("features", "")
1680 else:
1681 return ""
1683 info = {
1684 "host": getVal(["name_label"]),
1685 "release": getVal(["software_version", "release"]),
1686 "version": getVal(["software_version", "version"]),
1687 "machine": getVal(["software_version", "machine"]),
1688 "nr_cpus": getVal(["cpu_configuration", "nr_cpus"]),
1689 "nr_nodes": getVal(["cpu_configuration", "nr_nodes"]),
1690 "cores_per_socket": getVal(["cpu_configuration", "cores_per_socket"]),
1691 "threads_per_core": getVal(["cpu_configuration", "threads_per_core"]),
1692 "cpu_mhz": getCpuMhz(),
1693 "hw_caps": getCpuFeatures(),
1694 "total_memory": int(host_metrics_record["memory_total"])/1024/1024,
1695 "free_memory": int(host_metrics_record["memory_free"])/1024/1024,
1696 "xen_major": getVal(["software_version", "xen_major"]),
1697 "xen_minor": getVal(["software_version", "xen_minor"]),
1698 "xen_extra": getVal(["software_version", "xen_extra"]),
1699 "xen_caps": " ".join(getVal(["capabilities"], [])),
1700 "xen_scheduler": getVal(["sched_policy"]),
1701 "xen_pagesize": getVal(["other_config", "xen_pagesize"]),
1702 "platform_params": getVal(["other_config", "platform_params"]),
1703 "xen_changeset": getVal(["software_version", "xen_changeset"]),
1704 "cc_compiler": getVal(["software_version", "cc_compiler"]),
1705 "cc_compile_by": getVal(["software_version", "cc_compile_by"]),
1706 "cc_compile_domain": getVal(["software_version", "cc_compile_domain"]),
1707 "cc_compile_date": getVal(["software_version", "cc_compile_date"]),
1708 "xend_config_format":getVal(["software_version", "xend_config_format"])
1711 sorted = info.items()
1712 sorted.sort(lambda (x1,y1), (x2,y2): -cmp(x1,x2))
1714 for (k, v) in sorted:
1715 print "%-23s:" % k, v
1716 else:
1717 info = server.xend.node.info()
1718 for x in info[1:]:
1719 if len(x) < 2:
1720 print "%-23s: (none)" % x[0]
1721 else:
1722 print "%-23s:" % x[0], x[1]
1724 def xm_console(args):
1725 arg_check(args, "console", 1, 2)
1727 quiet = False;
1729 try:
1730 (options, params) = getopt.gnu_getopt(args, 'q', ['quiet'])
1731 except getopt.GetoptError, opterr:
1732 err(opterr)
1733 usage('console')
1735 for (k, v) in options:
1736 if k in ['-q', '--quiet']:
1737 quiet = True
1738 else:
1739 assert False
1741 if len(params) != 1:
1742 err('No domain given')
1743 usage('console')
1745 dom = params[0]
1747 try:
1748 if serverType == SERVER_XEN_API:
1749 domid = int(server.xenapi.VM.get_domid(get_single_vm(dom)))
1750 else:
1751 info = server.xend.domain(dom)
1752 domid = int(sxp.child_value(info, 'domid', '-1'))
1753 except:
1754 if quiet:
1755 sys.exit(1)
1756 else:
1757 raise
1759 if domid == -1:
1760 if quiet:
1761 sys.exit(1)
1762 else:
1763 raise xmlrpclib.Fault(0, "Domain '%s' is not started" % dom)
1765 console.execConsole(domid)
1768 def xm_uptime(args):
1769 short_mode = 0
1771 try:
1772 (options, params) = getopt.gnu_getopt(args, 's', ['short'])
1773 except getopt.GetoptError, opterr:
1774 err(opterr)
1775 usage('uptime')
1777 for (k, v) in options:
1778 if k in ['-s', '--short']:
1779 short_mode = 1
1781 doms = getDomains(params, 'all')
1783 if short_mode == 0:
1784 print '%-33s %4s %s ' % ('Name','ID','Uptime')
1786 for dom in doms:
1787 d = parse_doms_info(dom)
1788 if d['domid'] == '':
1789 uptime = 0
1790 elif int(d['domid']) > 0:
1791 uptime = int(round(d['up_time']))
1792 else:
1793 f=open('/proc/uptime', 'r')
1794 upfile = f.read()
1795 uptime = int(round(float(upfile.split(' ')[0])))
1796 f.close()
1798 days = int(uptime / 86400)
1799 uptime -= (days * 86400)
1800 hours = int(uptime / 3600)
1801 uptime -= (hours * 3600)
1802 minutes = int(uptime / 60)
1803 uptime -= (minutes * 60)
1804 seconds = uptime
1806 upstring = ""
1807 if days > 0:
1808 upstring += str(days) + " day"
1809 if days > 1:
1810 upstring += "s"
1811 upstring += ", "
1812 upstring += '%(hours)2d:%(minutes)02d' % vars()
1814 if short_mode:
1815 now = datetime.datetime.now()
1816 upstring = now.strftime(" %H:%M:%S") + " up " + upstring
1817 upstring += ", " + d['name'] + " (" + d['domid'] + ")"
1818 else:
1819 upstring += ':%(seconds)02d' % vars()
1820 upstring = ("%(name)-32s %(domid)5s " % d) + upstring
1822 print upstring
1824 def xm_sysrq(args):
1825 arg_check(args, "sysrq", 2)
1826 dom = args[0]
1827 req = args[1]
1828 if serverType == SERVER_XEN_API:
1829 server.xenapi.VM.send_sysrq(get_single_vm(dom), req)
1830 else:
1831 server.xend.domain.send_sysrq(dom, req)
1833 def xm_trigger(args):
1834 vcpu = 0
1836 arg_check(args, "trigger", 2, 3)
1837 dom = args[0]
1838 trigger = args[1]
1839 if len(args) == 3:
1840 vcpu = int(args[2])
1842 if serverType == SERVER_XEN_API:
1843 server.xenapi.VM.send_trigger(get_single_vm(dom), trigger, vcpu)
1844 else:
1845 server.xend.domain.send_trigger(dom, trigger, vcpu)
1847 def xm_debug_keys(args):
1848 arg_check(args, "debug-keys", 1)
1850 keys = str(args[0])
1852 if serverType == SERVER_XEN_API:
1853 server.xenapi.host.send_debug_keys(
1854 server.xenapi.session.get_this_host(server.getSession()),
1855 keys)
1856 else:
1857 server.xend.node.send_debug_keys(keys)
1859 def xm_top(args):
1860 arg_check(args, "top", 0)
1862 os.system('xentop')
1864 def xm_dmesg(args):
1865 arg_check(args, "dmesg", 0, 1)
1867 try:
1868 (options, params) = getopt.gnu_getopt(args, 'c', ['clear'])
1869 except getopt.GetoptError, opterr:
1870 err(opterr)
1871 usage('dmesg')
1873 use_clear = 0
1874 for (k, v) in options:
1875 if k in ['-c', '--clear']:
1876 use_clear = 1
1878 if len(params) :
1879 err("No parameter required")
1880 usage('dmesg')
1882 if serverType == SERVER_XEN_API:
1883 host = server.xenapi.session.get_this_host(server.getSession())
1884 if use_clear:
1885 print server.xenapi.host.dmesg_clear(host),
1886 else:
1887 print server.xenapi.host.dmesg(host),
1888 else:
1889 if not use_clear:
1890 print server.xend.node.dmesg.info(),
1891 else:
1892 print server.xend.node.dmesg.clear(),
1894 def xm_log(args):
1895 arg_check(args, "log", 0)
1897 if serverType == SERVER_XEN_API:
1898 print server.xenapi.host.get_log(
1899 server.xenapi.session.get_this_host(server.getSession()))
1900 else:
1901 print server.xend.node.log()
1903 def xm_serve(args):
1904 if serverType == SERVER_XEN_API:
1905 print "Not supported with XenAPI"
1906 sys.exit(-1)
1908 arg_check(args, "serve", 0)
1910 from fcntl import fcntl, F_SETFL
1912 s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
1913 s.connect(XendClient.XML_RPC_SOCKET)
1914 fcntl(sys.stdin, F_SETFL, os.O_NONBLOCK)
1916 while True:
1917 iwtd, owtd, ewtd = select([sys.stdin, s], [], [])
1918 if s in iwtd:
1919 data = s.recv(4096)
1920 if len(data) > 0:
1921 sys.stdout.write(data)
1922 sys.stdout.flush()
1923 else:
1924 break
1925 if sys.stdin in iwtd:
1926 data = sys.stdin.read(4096)
1927 if len(data) > 0:
1928 s.sendall(data)
1929 else:
1930 break
1931 s.close()
1933 def parse_dev_info(info):
1934 def get_info(n, t, d):
1935 i = 0
1936 while i < len(info):
1937 if (info[i][0] == n):
1938 return t(info[i][1])
1939 i = i + 1
1940 return t(d)
1941 return {
1942 #common
1943 'backend-id' : get_info('backend-id', int, -1),
1944 'handle' : get_info('handle', int, 0),
1945 'state' : get_info('state', int, -1),
1946 'be-path' : get_info('backend', str, '??'),
1947 'event-ch' : get_info('event-channel',int, -1),
1948 #network specific
1949 'virtual-device' : get_info('virtual-device', str, '??'),
1950 'tx-ring-ref': get_info('tx-ring-ref', int, -1),
1951 'rx-ring-ref': get_info('rx-ring-ref', int, -1),
1952 'mac' : get_info('mac', str, '??'),
1953 #block-device specific
1954 'ring-ref' : get_info('ring-ref', int, -1),
1957 def arg_check_for_resource_list(args, name):
1958 use_long = 0
1959 try:
1960 (options, params) = getopt.gnu_getopt(args, 'l', ['long'])
1961 except getopt.GetoptError, opterr:
1962 err(opterr)
1963 sys.exit(1)
1965 for (k, v) in options:
1966 if k in ['-l', '--long']:
1967 use_long = 1
1969 if len(params) == 0:
1970 print 'No domain parameter given'
1971 usage(name)
1972 if len(params) > 1:
1973 print 'No multiple domain parameters allowed'
1974 usage(name)
1976 return (use_long, params)
1978 def xm_network_list(args):
1979 (use_long, params) = arg_check_for_resource_list(args, "network-list")
1981 dom = params[0]
1983 if serverType == SERVER_XEN_API:
1984 vif_refs = server.xenapi.VM.get_VIFs(get_single_vm(dom))
1985 vif_properties = \
1986 map(server.xenapi.VIF.get_runtime_properties, vif_refs)
1987 devs = map(lambda (handle, properties): [handle, map2sxp(properties)],
1988 zip(range(len(vif_properties)), vif_properties))
1989 else:
1990 devs = server.xend.domain.getDeviceSxprs(dom, 'vif')
1992 if use_long:
1993 map(PrettyPrint.prettyprint, devs)
1994 else:
1995 hdr = 0
1996 for x in devs:
1997 if hdr == 0:
1998 print 'Idx BE MAC Addr. handle state evt-ch tx-/rx-ring-ref BE-path'
1999 hdr = 1
2000 ni = parse_dev_info(x[1])
2001 ni['idx'] = int(x[0])
2002 print ("%(idx)-3d "
2003 "%(backend-id)-3d"
2004 "%(mac)-17s "
2005 "%(handle)-3d "
2006 "%(state)-3d "
2007 "%(event-ch)-3d "
2008 "%(tx-ring-ref)-5d/%(rx-ring-ref)-5d "
2009 "%(be-path)-30s "
2010 % ni)
2012 def xm_block_list(args):
2013 (use_long, params) = arg_check_for_resource_list(args, "block-list")
2015 dom = params[0]
2017 if serverType == SERVER_XEN_API:
2018 vbd_refs = server.xenapi.VM.get_VBDs(get_single_vm(dom))
2019 vbd_properties = \
2020 map(server.xenapi.VBD.get_runtime_properties, vbd_refs)
2021 vbd_devs = \
2022 map(server.xenapi.VBD.get_device, vbd_refs)
2023 vbd_devids = \
2024 map(blkdev_name_to_number, vbd_devs)
2025 devs = map(lambda (devid, prop): [devid, map2sxp(prop)],
2026 zip(vbd_devids, vbd_properties))
2027 else:
2028 devs = server.xend.domain.getDeviceSxprs(dom, 'vbd')
2030 if use_long:
2031 map(PrettyPrint.prettyprint, devs)
2032 else:
2033 hdr = 0
2034 for x in devs:
2035 if hdr == 0:
2036 print 'Vdev BE handle state evt-ch ring-ref BE-path'
2037 hdr = 1
2038 ni = parse_dev_info(x[1])
2039 ni['idx'] = int(x[0])
2040 print ("%(idx)-3d "
2041 "%(backend-id)-3d "
2042 "%(handle)-3d "
2043 "%(state)-3d "
2044 "%(event-ch)-3d "
2045 "%(ring-ref)-5d "
2046 "%(be-path)-30s "
2047 % ni)
2049 def xm_vtpm_list(args):
2050 (use_long, params) = arg_check_for_resource_list(args, "vtpm-list")
2052 dom = params[0]
2054 if serverType == SERVER_XEN_API:
2055 vtpm_refs = server.xenapi.VM.get_VTPMs(get_single_vm(dom))
2056 vtpm_properties = \
2057 map(server.xenapi.VTPM.get_runtime_properties, vtpm_refs)
2058 devs = map(lambda (handle, properties): [handle, map2sxp(properties)],
2059 zip(range(len(vtpm_properties)), vtpm_properties))
2060 else:
2061 devs = server.xend.domain.getDeviceSxprs(dom, 'vtpm')
2063 if use_long:
2064 map(PrettyPrint.prettyprint, devs)
2065 else:
2066 hdr = 0
2067 for x in devs:
2068 if hdr == 0:
2069 print 'Idx BE handle state evt-ch ring-ref BE-path'
2070 hdr = 1
2071 ni = parse_dev_info(x[1])
2072 ni['idx'] = int(x[0])
2073 print ("%(idx)-3d "
2074 "%(backend-id)-3d "
2075 "%(handle)-3d "
2076 "%(state)-3d "
2077 "%(event-ch)-3d "
2078 "%(ring-ref)-5d "
2079 "%(be-path)-30s "
2080 % ni)
2083 def xm_pci_list(args):
2084 (use_long, params) = arg_check_for_resource_list(args, "pci-list")
2086 dom = params[0]
2088 devs = server.xend.domain.getDeviceSxprs(dom, 'pci')
2090 if len(devs) == 0:
2091 return
2093 has_vslt = devs[0].has_key('vslt')
2094 if has_vslt:
2095 hdr_str = 'VSlt domain bus slot func'
2096 fmt_str = "%(vslt)-3s %(domain)-3s %(bus)-3s %(slot)-3s %(func)-3s "
2097 else:
2098 hdr_str = 'domain bus slot func'
2099 fmt_str = "%(domain)-3s %(bus)-3s %(slot)-3s %(func)-3s "
2100 hdr = 0
2102 for x in devs:
2103 if hdr == 0:
2104 print (hdr_str)
2105 hdr = 1
2106 print ( fmt_str % x )
2108 def parse_block_configuration(args):
2109 dom = args[0]
2111 if args[1].startswith('tap:'):
2112 cls = 'tap'
2113 else:
2114 cls = 'vbd'
2116 vbd = [cls,
2117 ['uname', args[1]],
2118 ['dev', args[2]],
2119 ['mode', args[3]]]
2120 if len(args) == 5:
2121 vbd.append(['backend', args[4]])
2123 return (dom, vbd)
2126 def xm_block_attach(args):
2127 arg_check(args, 'block-attach', 4, 5)
2129 if serverType == SERVER_XEN_API:
2130 dom = args[0]
2131 uname = args[1]
2132 dev = args[2]
2133 mode = args[3]
2135 # First create new VDI
2136 vdi_record = {
2137 "name_label": "vdi" + str(uname.__hash__()),
2138 "name_description": "",
2139 "SR": get_default_SR(),
2140 "virtual_size": 0,
2141 "sector_size": 512,
2142 "type": "system",
2143 "sharable": False,
2144 "read_only": mode!="w",
2145 "other_config": {"location": uname}
2148 vdi_ref = server.xenapi.VDI.create(vdi_record)
2150 # Now create new VBD
2152 vbd_record = {
2153 "VM": get_single_vm(dom),
2154 "VDI": vdi_ref,
2155 "device": dev,
2156 "bootable": True,
2157 "mode": mode=="w" and "RW" or "RO",
2158 "type": "Disk",
2159 "qos_algorithm_type": "",
2160 "qos_algorithm_params": {}
2163 server.xenapi.VBD.create(vbd_record)
2165 else:
2166 (dom, vbd) = parse_block_configuration(args)
2167 server.xend.domain.device_create(dom, vbd)
2170 def xm_block_configure(args):
2171 arg_check(args, 'block-configure', 4, 5)
2173 (dom, vbd) = parse_block_configuration(args)
2174 server.xend.domain.device_configure(dom, vbd)
2177 def xm_network_attach(args):
2178 arg_check(args, 'network-attach', 1, 11)
2180 dom = args[0]
2181 vif = ['vif']
2182 vif_params = ['type', 'mac', 'bridge', 'ip', 'script', \
2183 'backend', 'vifname', 'rate', 'model', 'accel']
2185 if serverType == SERVER_XEN_API:
2186 vif_record = {
2187 "device": "eth0",
2188 "network": get_default_Network(),
2189 "VM": get_single_vm(dom),
2190 "MAC": "",
2191 "MTU": "",
2192 "qos_algorithm_type": "",
2193 "qos_algorithm_params": {},
2194 "other_config": {}
2197 def set(keys, val):
2198 record = vif_record
2199 for key in keys[:-1]:
2200 record = record[key]
2201 record[keys[-1]] = val
2203 def get_net_from_bridge(bridge):
2204 # In OSS, we just assert network.name_label == bridge name
2205 networks = dict([(record['name_label'], ref)
2206 for ref, record in server.xenapi.network
2207 .get_all_records().items()])
2208 if bridge not in networks.keys():
2209 raise "Unknown bridge name!"
2210 return networks[bridge]
2212 vif_conv = {
2213 'type':
2214 lambda x: None,
2215 'mac':
2216 lambda x: set(['MAC'], x),
2217 'bridge':
2218 lambda x: set(['network'], get_net_from_bridge(x)),
2219 'ip':
2220 lambda x: set(['other_config', 'ip'], x),
2221 'script':
2222 lambda x: set(['other_config', 'script'], x),
2223 'backend':
2224 lambda x: set(['other_config', 'backend'], x),
2225 'vifname':
2226 lambda x: set(['device'], x),
2227 'rate':
2228 lambda x: set(['qos_algorithm_params', 'rate'], x),
2229 'model':
2230 lambda x: None,
2231 'accel':
2232 lambda x: set(['other_config', 'accel'], x)
2235 for a in args[1:]:
2236 vif_param = a.split("=")
2237 if len(vif_param) != 2 or vif_param[1] == '' or \
2238 vif_param[0] not in vif_params:
2239 err("Invalid argument: %s" % a)
2240 usage('network-attach')
2241 else:
2242 vif_conv[vif_param[0]](vif_param[1])
2244 server.xenapi.VIF.create(vif_record)
2245 else:
2246 for a in args[1:]:
2247 vif_param = a.split("=")
2248 if len(vif_param) != 2 or vif_param[1] == '' or \
2249 vif_param[0] not in vif_params:
2250 err("Invalid argument: %s" % a)
2251 usage('network-attach')
2252 vif.append(vif_param)
2253 server.xend.domain.device_create(dom, vif)
2255 def parse_pci_configuration(args, state):
2256 dom = args[0]
2257 pci_dev_str = args[1]
2258 if len(args) == 3:
2259 vslt = args[2]
2260 else:
2261 vslt = '0x0' #chose a free virtual PCI slot
2262 pci=['pci']
2263 pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \
2264 r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \
2265 r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \
2266 r"(?P<func>[0-7])$", pci_dev_str)
2267 if pci_match == None:
2268 raise OptionError("Invalid argument: %s %s" % (pci_dev_str,vslt))
2269 pci_dev_info = pci_match.groupdict('0')
2270 try:
2271 pci.append(['dev', ['domain', '0x'+ pci_dev_info['domain']], \
2272 ['bus', '0x'+ pci_dev_info['bus']],
2273 ['slot', '0x'+ pci_dev_info['slot']],
2274 ['func', '0x'+ pci_dev_info['func']],
2275 ['vslt', '0x%x' % int(vslt, 16)]])
2276 except:
2277 raise OptionError("Invalid argument: %s %s" % (pci_dev_str,vslt))
2278 pci.append(['state', state])
2280 return (dom, pci)
2282 def xm_pci_attach(args):
2283 arg_check(args, 'pci-attach', 2, 3)
2284 (dom, pci) = parse_pci_configuration(args, 'Initialising')
2285 server.xend.domain.device_configure(dom, pci)
2287 def detach(args, deviceClass):
2288 rm_cfg = True
2289 dom = args[0]
2290 dev = args[1]
2291 try:
2292 force = args[2]
2293 if (force != "--force") and (force != "-f"):
2294 print "Ignoring option %s"%(force)
2295 force = None
2296 except IndexError:
2297 force = None
2299 server.xend.domain.destroyDevice(dom, deviceClass, dev, force, rm_cfg)
2302 def xm_block_detach(args):
2303 if serverType == SERVER_XEN_API:
2304 arg_check(args, "block-detach", 2, 3)
2305 dom = args[0]
2306 dev = args[1]
2307 vbd_refs = server.xenapi.VM.get_VBDs(get_single_vm(dom))
2308 vbd_refs = [vbd_ref for vbd_ref in vbd_refs
2309 if server.xenapi.VBD.get_device(vbd_ref) == dev]
2310 if len(vbd_refs) > 0:
2311 vbd_ref = vbd_refs[0]
2312 vdi_ref = server.xenapi.VBD.get_VDI(vbd_ref)
2314 server.xenapi.VBD.destroy(vbd_ref)
2316 if len(server.xenapi.VDI.get_VBDs(vdi_ref)) <= 0:
2317 server.xenapi.VDI.destroy(vdi_ref)
2318 else:
2319 raise OptionError("Cannot find device '%s' in domain '%s'"
2320 % (dev,dom))
2321 else:
2322 arg_check(args, 'block-detach', 2, 3)
2323 dom = args[0]
2324 dev = args[1]
2325 dc = server.xend.domain.getBlockDeviceClass(dom, dev)
2326 if dc == "tap":
2327 detach(args, 'tap')
2328 else:
2329 detach(args, 'vbd')
2331 def xm_network_detach(args):
2332 if serverType == SERVER_XEN_API:
2333 arg_check(args, "network-detach", 2, 3)
2334 dom = args[0]
2335 devid = args[1]
2336 vif_refs = server.xenapi.VM.get_VIFs(get_single_vm(dom))
2337 vif_refs = [vif_ref for vif_ref in vif_refs
2338 if server.xenapi.VIF.\
2339 get_runtime_properties(vif_ref)["handle"] == devid]
2340 if len(vif_refs) > 0:
2341 vif_ref = vif_refs[0]
2343 server.xenapi.VIF.destroy(vif_ref)
2344 else:
2345 print "Cannot find device '%s' in domain '%s'" % (devid,dom)
2346 else:
2347 arg_check(args, 'network-detach', 2, 3)
2348 detach(args, 'vif')
2350 def xm_pci_detach(args):
2351 arg_check(args, 'pci-detach', 2)
2352 (dom, pci) = parse_pci_configuration(args, 'Closing')
2353 server.xend.domain.device_configure(dom, pci)
2356 def xm_vnet_list(args):
2357 xenapi_unsupported()
2358 try:
2359 (options, params) = getopt.gnu_getopt(args, 'l', ['long'])
2360 except getopt.GetoptError, opterr:
2361 err(opterr)
2362 usage('vnet-list')
2364 use_long = 0
2365 for (k, v) in options:
2366 if k in ['-l', '--long']:
2367 use_long = 1
2369 if params:
2370 use_long = 1
2371 vnets = params
2372 else:
2373 vnets = server.xend_vnets()
2375 for vnet in vnets:
2376 try:
2377 if use_long:
2378 info = server.xend_vnet(vnet)
2379 PrettyPrint.prettyprint(info)
2380 else:
2381 print vnet
2382 except Exception, ex:
2383 print vnet, ex
2385 def xm_vnet_create(args):
2386 xenapi_unsupported()
2387 arg_check(args, "vnet-create", 1)
2388 conf = args[0]
2389 if not os.access(conf, os.R_OK):
2390 print "File not found: %s" % conf
2391 sys.exit(1)
2393 server.xend_vnet_create(conf)
2395 def xm_vnet_delete(args):
2396 xenapi_unsupported()
2397 arg_check(args, "vnet-delete", 1)
2398 vnet = args[0]
2399 server.xend_vnet_delete(vnet)
2401 def xm_network_new(args):
2402 xenapi_only()
2403 arg_check(args, "network-new", 1)
2404 network = args[0]
2406 record = {
2407 "name_label": network,
2408 "name_description": "",
2409 "other_config": {},
2410 "default_gateway": "",
2411 "default_netmask": ""
2414 server.xenapi.network.create(record)
2416 def xm_network_del(args):
2417 xenapi_only()
2418 arg_check(args, "network-del", 1)
2419 network = args[0]
2421 networks = dict([(record['name_label'], ref)
2422 for ref, record in
2423 server.xenapi.network.get_all_records().items()])
2425 if network not in networks.keys():
2426 raise ValueError("'%s' is not a valid network name" % network)
2428 server.xenapi.network.destroy(networks[network])
2430 def xm_network_show(args):
2431 xenapi_only()
2432 arg_check(args, "network-show", 0)
2434 networks = server.xenapi.network.get_all_records()
2435 pifs = server.xenapi.PIF.get_all_records()
2436 vifs = server.xenapi.VIF.get_all_records()
2438 print '%-20s %-40s %-10s' % \
2439 ('Name', 'VIFs', 'PIFs')
2441 format2 = "%(name_label)-20s %(vif)-40s %(pif)-10s"
2443 for network_ref, network in networks.items():
2444 for i in range(max(len(network['PIFs']),
2445 len(network['VIFs']), 1)):
2446 if i < len(network['PIFs']):
2447 pif_uuid = network['PIFs'][i]
2448 else:
2449 pif_uuid = None
2451 if i < len(network['VIFs']):
2452 vif_uuid = network['VIFs'][i]
2453 else:
2454 vif_uuid = None
2456 pif = pifs.get(pif_uuid, None)
2457 vif = vifs.get(vif_uuid, None)
2459 if vif:
2460 dom_name = server.xenapi.VM.get_name_label(vif['VM'])
2461 vif = "%s.%s" % (dom_name, vif['device'])
2462 else:
2463 vif = ''
2465 if pif:
2466 if int(pif['VLAN']) > -1:
2467 pif = '%s.%s' % (pif['device'], pif['VLAN'])
2468 else:
2469 pif = pif['device']
2470 else:
2471 pif = ''
2473 if i == 0:
2474 r = {'name_label':network['name_label'],
2475 'vif':vif, 'pif':pif}
2476 else:
2477 r = {'name_label':'', 'vif':vif, 'pif':pif}
2479 print format2 % r
2482 commands = {
2483 "shell": xm_shell,
2484 "event-monitor": xm_event_monitor,
2485 # console commands
2486 "console": xm_console,
2487 # xenstat commands
2488 "top": xm_top,
2489 # domain commands
2490 "delete": xm_delete,
2491 "destroy": xm_destroy,
2492 "domid": xm_domid,
2493 "domname": xm_domname,
2494 "dump-core": xm_dump_core,
2495 "reboot": xm_reboot,
2496 "rename": xm_rename,
2497 "reset": xm_reset,
2498 "restore": xm_restore,
2499 "resume": xm_resume,
2500 "save": xm_save,
2501 "shutdown": xm_shutdown,
2502 "start": xm_start,
2503 "sysrq": xm_sysrq,
2504 "trigger": xm_trigger,
2505 "uptime": xm_uptime,
2506 "suspend": xm_suspend,
2507 "list": xm_list,
2508 # memory commands
2509 "mem-max": xm_mem_max,
2510 "mem-set": xm_mem_set,
2511 # cpu commands
2512 "vcpu-pin": xm_vcpu_pin,
2513 "vcpu-list": xm_vcpu_list,
2514 "vcpu-set": xm_vcpu_set,
2515 # special
2516 "pause": xm_pause,
2517 "unpause": xm_unpause,
2518 # host commands
2519 "debug-keys": xm_debug_keys,
2520 "dmesg": xm_dmesg,
2521 "info": xm_info,
2522 "log": xm_log,
2523 "serve": xm_serve,
2524 # scheduler
2525 "sched-sedf": xm_sched_sedf,
2526 "sched-credit": xm_sched_credit,
2527 # block
2528 "block-attach": xm_block_attach,
2529 "block-detach": xm_block_detach,
2530 "block-list": xm_block_list,
2531 "block-configure": xm_block_configure,
2532 # network (AKA vifs)
2533 "network-attach": xm_network_attach,
2534 "network-detach": xm_network_detach,
2535 "network-list": xm_network_list,
2536 # network (as in XenAPI)
2537 "network-new": xm_network_new,
2538 "network-del": xm_network_del,
2539 "network-show": xm_network_show,
2540 # vnet
2541 "vnet-list": xm_vnet_list,
2542 "vnet-create": xm_vnet_create,
2543 "vnet-delete": xm_vnet_delete,
2544 # vtpm
2545 "vtpm-list": xm_vtpm_list,
2546 #pci
2547 "pci-attach": xm_pci_attach,
2548 "pci-detach": xm_pci_detach,
2549 "pci-list": xm_pci_list,
2552 ## The commands supported by a separate argument parser in xend.xm.
2553 IMPORTED_COMMANDS = [
2554 'create',
2555 'new',
2556 'migrate',
2557 'labels',
2558 'dumppolicy',
2559 'addlabel',
2560 'rmlabel',
2561 'getlabel',
2562 'dry-run',
2563 'resources',
2564 'getpolicy',
2565 'setpolicy',
2566 'resetpolicy',
2569 for c in IMPORTED_COMMANDS:
2570 commands[c] = eval('lambda args: xm_importcommand("%s", args)' % c)
2572 aliases = {
2573 "balloon": "mem-set",
2574 "set-vcpus": "vcpu-set",
2575 "vif-list": "network-list",
2576 "vbd-create": "block-attach",
2577 "vbd-destroy": "block-detach",
2578 "vbd-list": "block-list",
2582 def xm_lookup_cmd(cmd):
2583 if commands.has_key(cmd):
2584 return commands[cmd]
2585 elif aliases.has_key(cmd):
2586 deprecated(cmd,aliases[cmd])
2587 return commands[aliases[cmd]]
2588 elif cmd == 'help':
2589 longHelp()
2590 sys.exit(0)
2591 else:
2592 # simulate getopt's prefix matching behaviour
2593 if len(cmd) > 1:
2594 same_prefix_cmds = [commands[c] for c in commands.keys() \
2595 if c[:len(cmd)] == cmd]
2596 # only execute if there is only 1 match
2597 if len(same_prefix_cmds) == 1:
2598 return same_prefix_cmds[0]
2599 return None
2601 def deprecated(old,new):
2602 print >>sys.stderr, (
2603 "Command %s is deprecated. Please use xm %s instead." % (old, new))
2605 def main(argv=sys.argv):
2606 if len(argv) < 2:
2607 usage()
2609 # intercept --help(-h) and output our own help
2610 for help in ['--help', '-h']:
2611 if help in argv[1:]:
2612 if help == argv[1]:
2613 longHelp()
2614 sys.exit(0)
2615 else:
2616 usage(argv[1])
2618 cmd_name = argv[1]
2619 cmd = xm_lookup_cmd(cmd_name)
2620 if cmd:
2621 # strip off prog name and subcmd
2622 args = argv[2:]
2623 _, rc = _run_cmd(cmd, cmd_name, args)
2624 sys.exit(rc)
2625 else:
2626 err('Subcommand %s not found!' % cmd_name)
2627 usage()
2629 def _run_cmd(cmd, cmd_name, args):
2630 global server
2632 try:
2633 if server is None:
2634 if serverType == SERVER_XEN_API:
2635 server = XenAPI.Session(serverURI)
2636 username, password = parseAuthentication()
2637 server.login_with_password(username, password)
2638 def logout():
2639 try:
2640 server.xenapi.session.logout()
2641 except:
2642 pass
2643 atexit.register(logout)
2644 else:
2645 server = ServerProxy(serverURI)
2647 return True, cmd(args)
2648 except socket.error, ex:
2649 if os.geteuid() != 0:
2650 err("Most commands need root access. Please try again as root.")
2651 else:
2652 err("Unable to connect to xend: %s. Is xend running?" % ex[1])
2653 except KeyboardInterrupt:
2654 print "Interrupted."
2655 return True, ''
2656 except IOError, ex:
2657 if os.geteuid() != 0:
2658 err("Most commands need root access. Please try again as root.")
2659 else:
2660 err("Unable to connect to xend: %s." % ex[1])
2661 except SystemExit, code:
2662 return code == 0, code
2663 except XenAPI.Failure, exn:
2664 for line in [''] + wrap(str(exn), 80) + ['']:
2665 print >>sys.stderr, line
2666 except xmlrpclib.Fault, ex:
2667 if ex.faultCode == XendClient.ERROR_INVALID_DOMAIN:
2668 err("Domain '%s' does not exist." % ex.faultString)
2669 else:
2670 err(ex.faultString)
2671 _usage(cmd_name)
2672 except xmlrpclib.ProtocolError, ex:
2673 if ex.errcode == -1:
2674 print >>sys.stderr, (
2675 "Xend has probably crashed! Invalid or missing HTTP "
2676 "status code.")
2677 else:
2678 print >>sys.stderr, (
2679 "Xend has probably crashed! ProtocolError(%d, %s)." %
2680 (ex.errcode, ex.errmsg))
2681 except (ValueError, OverflowError):
2682 err("Invalid argument.")
2683 _usage(cmd_name)
2684 except OptionError, e:
2685 err(str(e))
2686 _usage(cmd_name)
2687 print e.usage
2688 except XenAPIUnsupportedException, e:
2689 err(str(e))
2690 except XSMError, e:
2691 err(str(e))
2692 except Exception, e:
2693 if serverType != SERVER_XEN_API:
2694 import xen.util.xsm.xsm as security
2695 if isinstance(e, security.XSMError):
2696 err(str(e))
2697 return False, 1
2698 print "Unexpected error:", sys.exc_info()[0]
2699 print
2700 print "Please report to xen-devel@lists.xensource.com"
2701 raise
2703 return False, 1
2705 if __name__ == "__main__":
2706 main()