ia64/xen-unstable

view tools/python/xen/xm/main.py @ 17780:420db89188ca

xend: implement VM_hard_reboot of XenAPI.

Signed-off-by: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Jun 03 09:33:41 2008 +0100 (2008-06-03)
parents 672c09aad49d
children b346fb1b8223
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|s3resume> [<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 if serverType == SERVER_XEN_API:
1261 server.xenapi.VM.hard_reboot(get_single_vm(dom))
1262 else:
1263 server.xend.domain.reset(dom)
1265 def xm_pause(args):
1266 arg_check(args, "pause", 1)
1267 dom = args[0]
1269 if serverType == SERVER_XEN_API:
1270 server.xenapi.VM.pause(get_single_vm(dom))
1271 else:
1272 server.xend.domain.pause(dom)
1274 def xm_unpause(args):
1275 arg_check(args, "unpause", 1)
1276 dom = args[0]
1278 if serverType == SERVER_XEN_API:
1279 server.xenapi.VM.unpause(get_single_vm(dom))
1280 else:
1281 server.xend.domain.unpause(dom)
1283 def xm_dump_core(args):
1284 live = False
1285 crash = False
1286 reset = False
1287 try:
1288 (options, params) = getopt.gnu_getopt(args, 'LCR', ['live', 'crash', 'reset'])
1289 for (k, v) in options:
1290 if k in ('-L', '--live'):
1291 live = True
1292 elif k in ('-C', '--crash'):
1293 crash = True
1294 elif k in ('-R', '--reset'):
1295 reset = True
1297 if crash and reset:
1298 raise OptionError("You may not specify more than one '-CR' option")
1299 if len(params) not in (1, 2):
1300 raise OptionError("Expects 1 or 2 argument(s)")
1301 except getopt.GetoptError, e:
1302 raise OptionError(str(e))
1304 dom = params[0]
1305 if len(params) == 2:
1306 filename = os.path.abspath(params[1])
1307 else:
1308 filename = None
1310 if not live:
1311 ds = server.xend.domain.pause(dom, True)
1313 try:
1314 print "Dumping core of domain: %s ..." % str(dom)
1315 server.xend.domain.dump(dom, filename, live, crash)
1317 if crash:
1318 print "Destroying domain: %s ..." % str(dom)
1319 server.xend.domain.destroy(dom)
1320 elif reset:
1321 print "Resetting domain: %s ..." % str(dom)
1322 server.xend.domain.reset(dom)
1323 finally:
1324 if not live and not crash and not reset and ds == DOM_STATE_RUNNING:
1325 server.xend.domain.unpause(dom)
1327 def xm_rename(args):
1328 arg_check(args, "rename", 2)
1330 if serverType == SERVER_XEN_API:
1331 server.xenapi.VM.set_name_label(get_single_vm(args[0]), args[1])
1332 else:
1333 server.xend.domain.setName(args[0], args[1])
1335 def xm_importcommand(command, args):
1336 cmd = __import__(command, globals(), locals(), 'xen.xm')
1337 cmd.main([command] + args)
1340 #############################################################
1342 def xm_vcpu_pin(args):
1343 arg_check(args, "vcpu-pin", 3)
1345 def cpu_make_map(cpulist):
1346 cpus = []
1347 for c in cpulist.split(','):
1348 if c.find('-') != -1:
1349 (x,y) = c.split('-')
1350 for i in range(int(x),int(y)+1):
1351 cpus.append(int(i))
1352 else:
1353 # remove this element from the list
1354 if c[0] == '^':
1355 cpus = [x for x in cpus if x != int(c[1:])]
1356 else:
1357 cpus.append(int(c))
1358 cpus.sort()
1359 return cpus
1361 dom = args[0]
1362 vcpu = args[1]
1363 if args[2] == 'all':
1364 cpumap = cpu_make_map('0-63')
1365 else:
1366 cpumap = cpu_make_map(args[2])
1368 if serverType == SERVER_XEN_API:
1369 cpumap = map(str, cpumap)
1370 server.xenapi.VM.add_to_VCPUs_params_live(
1371 get_single_vm(dom), "cpumap%i" % int(vcpu), ",".join(cpumap))
1372 else:
1373 server.xend.domain.pincpu(dom, vcpu, cpumap)
1375 def xm_mem_max(args):
1376 arg_check(args, "mem-max", 2)
1378 dom = args[0]
1380 if serverType == SERVER_XEN_API:
1381 mem = int_unit(args[1], 'k') * 1024
1382 server.xenapi.VM.set_memory_static_max(get_single_vm(dom), mem)
1383 else:
1384 mem = int_unit(args[1], 'm')
1385 server.xend.domain.maxmem_set(dom, mem)
1387 def xm_mem_set(args):
1388 arg_check(args, "mem-set", 2)
1390 dom = args[0]
1392 if serverType == SERVER_XEN_API:
1393 mem_target = int_unit(args[1], 'm') * 1024 * 1024
1394 server.xenapi.VM.set_memory_dynamic_max_live(get_single_vm(dom),
1395 mem_target)
1396 server.xenapi.VM.set_memory_dynamic_min_live(get_single_vm(dom),
1397 mem_target)
1398 else:
1399 mem_target = int_unit(args[1], 'm')
1400 server.xend.domain.setMemoryTarget(dom, mem_target)
1402 def xm_vcpu_set(args):
1403 arg_check(args, "vcpu-set", 2)
1405 dom = args[0]
1406 vcpus = int(args[1])
1408 if serverType == SERVER_XEN_API:
1409 server.xenapi.VM.set_VCPUs_number_live(get_single_vm(dom), vcpus)
1410 else:
1411 server.xend.domain.setVCpuCount(dom, vcpus)
1413 def xm_destroy(args):
1414 arg_check(args, "destroy", 1)
1416 dom = args[0]
1418 if serverType == SERVER_XEN_API:
1419 server.xenapi.VM.hard_shutdown(get_single_vm(dom))
1420 else:
1421 server.xend.domain.destroy(dom)
1423 def xm_domid(args):
1424 arg_check(args, "domid", 1)
1426 name = args[0]
1428 if serverType == SERVER_XEN_API:
1429 print server.xenapi.VM.get_domid(get_single_vm(name))
1430 else:
1431 dom = server.xend.domain(name)
1432 print sxp.child_value(dom, 'domid')
1434 def xm_domname(args):
1435 arg_check(args, "domname", 1)
1437 name = args[0]
1439 if serverType == SERVER_XEN_API:
1440 print server.xenapi.VM.get_name_label(get_single_vm(name))
1441 else:
1442 dom = server.xend.domain(name)
1443 print sxp.child_value(dom, 'name')
1445 def xm_sched_sedf(args):
1446 xenapi_unsupported()
1448 def ns_to_ms(val):
1449 return float(val) * 0.000001
1451 def ms_to_ns(val):
1452 return (float(val) / 0.000001)
1454 def print_sedf(info):
1455 info['period'] = ns_to_ms(info['period'])
1456 info['slice'] = ns_to_ms(info['slice'])
1457 info['latency'] = ns_to_ms(info['latency'])
1458 print( ("%(name)-32s %(domid)5d %(period)9.1f %(slice)9.1f" +
1459 " %(latency)7.1f %(extratime)6d %(weight)6d") % info)
1461 check_sched_type('sedf')
1463 # we want to just display current info if no parameters are passed
1464 if len(args) == 0:
1465 domid = None
1466 else:
1467 # we expect at least a domain id (name or number)
1468 # and at most a domid up to 5 options with values
1469 arg_check(args, "sched-sedf", 1, 11)
1470 domid = args[0]
1471 # drop domid from args since get_opt doesn't recognize it
1472 args = args[1:]
1474 opts = {}
1475 try:
1476 (options, params) = getopt.gnu_getopt(args, 'p:s:l:e:w:',
1477 ['period=', 'slice=', 'latency=', 'extratime=', 'weight='])
1478 except getopt.GetoptError, opterr:
1479 err(opterr)
1480 usage('sched-sedf')
1482 # convert to nanoseconds if needed
1483 for (k, v) in options:
1484 if k in ['-p', '--period']:
1485 opts['period'] = ms_to_ns(v)
1486 elif k in ['-s', '--slice']:
1487 opts['slice'] = ms_to_ns(v)
1488 elif k in ['-l', '--latency']:
1489 opts['latency'] = ms_to_ns(v)
1490 elif k in ['-e', '--extratime']:
1491 opts['extratime'] = v
1492 elif k in ['-w', '--weight']:
1493 opts['weight'] = v
1495 doms = filter(lambda x : domid_match(domid, x),
1496 [parse_doms_info(dom)
1497 for dom in getDomains(None, 'running')])
1498 if domid is not None and doms == []:
1499 err("Domain '%s' does not exist." % domid)
1500 usage('sched-sedf')
1502 # print header if we aren't setting any parameters
1503 if len(opts.keys()) == 0:
1504 print '%-33s %4s %-4s %-4s %-7s %-5s %-6s' % \
1505 ('Name','ID','Period(ms)', 'Slice(ms)', 'Lat(ms)',
1506 'Extra','Weight')
1508 for d in doms:
1509 # fetch current values so as not to clobber them
1510 try:
1511 sedf_raw = server.xend.domain.cpu_sedf_get(d['domid'])
1512 except xmlrpclib.Fault:
1513 # domain does not support sched-sedf?
1514 sedf_raw = {}
1516 sedf_info = parse_sedf_info(sedf_raw)
1517 sedf_info['name'] = d['name']
1518 # update values in case of call to set
1519 if len(opts.keys()) > 0:
1520 for k in opts.keys():
1521 sedf_info[k]=opts[k]
1523 # send the update, converting user input
1524 v = map(int, [sedf_info['period'], sedf_info['slice'],
1525 sedf_info['latency'],sedf_info['extratime'],
1526 sedf_info['weight']])
1527 rv = server.xend.domain.cpu_sedf_set(d['domid'], *v)
1528 if int(rv) != 0:
1529 err("Failed to set sedf parameters (rv=%d)."%(rv))
1531 # not setting values, display info
1532 else:
1533 print_sedf(sedf_info)
1535 def xm_sched_credit(args):
1536 """Get/Set options for Credit Scheduler."""
1538 check_sched_type('credit')
1540 try:
1541 opts, params = getopt.getopt(args, "d:w:c:",
1542 ["domain=", "weight=", "cap="])
1543 except getopt.GetoptError, opterr:
1544 err(opterr)
1545 usage('sched-credit')
1547 domid = None
1548 weight = None
1549 cap = None
1551 for o, a in opts:
1552 if o in ["-d", "--domain"]:
1553 domid = a
1554 elif o in ["-w", "--weight"]:
1555 weight = int(a)
1556 elif o in ["-c", "--cap"]:
1557 cap = int(a);
1559 doms = filter(lambda x : domid_match(domid, x),
1560 [parse_doms_info(dom)
1561 for dom in getDomains(None, 'all')])
1563 if weight is None and cap is None:
1564 if domid is not None and doms == []:
1565 err("Domain '%s' does not exist." % domid)
1566 usage('sched-credit')
1567 # print header if we aren't setting any parameters
1568 print '%-33s %4s %6s %4s' % ('Name','ID','Weight','Cap')
1570 for d in doms:
1571 try:
1572 if serverType == SERVER_XEN_API:
1573 info = server.xenapi.VM_metrics.get_VCPUs_params(
1574 server.xenapi.VM.get_metrics(
1575 get_single_vm(d['name'])))
1576 else:
1577 info = server.xend.domain.sched_credit_get(d['name'])
1578 except xmlrpclib.Fault:
1579 pass
1581 if 'weight' not in info or 'cap' not in info:
1582 # domain does not support sched-credit?
1583 info = {'weight': -1, 'cap': -1}
1585 info['weight'] = int(info['weight'])
1586 info['cap'] = int(info['cap'])
1588 info['name'] = d['name']
1589 info['domid'] = str(d['domid'])
1590 print( ("%(name)-32s %(domid)5s %(weight)6d %(cap)4d") % info)
1591 else:
1592 if domid is None:
1593 # place holder for system-wide scheduler parameters
1594 err("No domain given.")
1595 usage('sched-credit')
1597 if serverType == SERVER_XEN_API:
1598 if doms[0]['domid']:
1599 server.xenapi.VM.add_to_VCPUs_params_live(
1600 get_single_vm(domid),
1601 "weight",
1602 weight)
1603 server.xenapi.VM.add_to_VCPUs_params_live(
1604 get_single_vm(domid),
1605 "cap",
1606 cap)
1607 else:
1608 server.xenapi.VM.add_to_VCPUs_params(
1609 get_single_vm(domid),
1610 "weight",
1611 weight)
1612 server.xenapi.VM.add_to_VCPUs_params(
1613 get_single_vm(domid),
1614 "cap",
1615 cap)
1616 else:
1617 result = server.xend.domain.sched_credit_set(domid, weight, cap)
1618 if result != 0:
1619 err(str(result))
1621 def xm_info(args):
1622 arg_check(args, "info", 0, 1)
1624 try:
1625 (options, params) = getopt.gnu_getopt(args, 'c', ['config'])
1626 except getopt.GetoptError, opterr:
1627 err(opterr)
1628 usage('info')
1630 show_xend_config = 0
1631 for (k, v) in options:
1632 if k in ['-c', '--config']:
1633 show_xend_config = 1
1635 if show_xend_config:
1636 for name, obj in inspect.getmembers(xoptions):
1637 if not inspect.ismethod(obj):
1638 if name == "config":
1639 for x in obj[1:]:
1640 if len(x) < 2:
1641 print "%-38s: (none)" % x[0]
1642 else:
1643 print "%-38s:" % x[0], x[1]
1644 else:
1645 print "%-38s:" % name, obj
1646 return
1648 if serverType == SERVER_XEN_API:
1650 # Need to fake out old style xm info as people rely on parsing it
1652 host_record = server.xenapi.host.get_record(
1653 server.xenapi.session.get_this_host(server.getSession()))
1655 host_cpu_records = map(server.xenapi.host_cpu.get_record, host_record["host_CPUs"])
1657 host_metrics_record = server.xenapi.host_metrics.get_record(host_record["metrics"])
1659 def getVal(keys, default=""):
1660 data = host_record
1661 for key in keys:
1662 if key in data:
1663 data = data[key]
1664 else:
1665 return default
1666 return data
1668 def getCpuMhz():
1669 cpu_speeds = [int(host_cpu_record["speed"])
1670 for host_cpu_record in host_cpu_records
1671 if "speed" in host_cpu_record]
1672 if len(cpu_speeds) > 0:
1673 return sum(cpu_speeds) / len(cpu_speeds)
1674 else:
1675 return 0
1677 getCpuMhz()
1679 def getCpuFeatures():
1680 if len(host_cpu_records) > 0:
1681 return host_cpu_records[0].get("features", "")
1682 else:
1683 return ""
1685 info = {
1686 "host": getVal(["name_label"]),
1687 "release": getVal(["software_version", "release"]),
1688 "version": getVal(["software_version", "version"]),
1689 "machine": getVal(["software_version", "machine"]),
1690 "nr_cpus": getVal(["cpu_configuration", "nr_cpus"]),
1691 "nr_nodes": getVal(["cpu_configuration", "nr_nodes"]),
1692 "cores_per_socket": getVal(["cpu_configuration", "cores_per_socket"]),
1693 "threads_per_core": getVal(["cpu_configuration", "threads_per_core"]),
1694 "cpu_mhz": getCpuMhz(),
1695 "hw_caps": getCpuFeatures(),
1696 "total_memory": int(host_metrics_record["memory_total"])/1024/1024,
1697 "free_memory": int(host_metrics_record["memory_free"])/1024/1024,
1698 "xen_major": getVal(["software_version", "xen_major"]),
1699 "xen_minor": getVal(["software_version", "xen_minor"]),
1700 "xen_extra": getVal(["software_version", "xen_extra"]),
1701 "xen_caps": " ".join(getVal(["capabilities"], [])),
1702 "xen_scheduler": getVal(["sched_policy"]),
1703 "xen_pagesize": getVal(["other_config", "xen_pagesize"]),
1704 "platform_params": getVal(["other_config", "platform_params"]),
1705 "xen_changeset": getVal(["software_version", "xen_changeset"]),
1706 "cc_compiler": getVal(["software_version", "cc_compiler"]),
1707 "cc_compile_by": getVal(["software_version", "cc_compile_by"]),
1708 "cc_compile_domain": getVal(["software_version", "cc_compile_domain"]),
1709 "cc_compile_date": getVal(["software_version", "cc_compile_date"]),
1710 "xend_config_format":getVal(["software_version", "xend_config_format"])
1713 sorted = info.items()
1714 sorted.sort(lambda (x1,y1), (x2,y2): -cmp(x1,x2))
1716 for (k, v) in sorted:
1717 print "%-23s:" % k, v
1718 else:
1719 info = server.xend.node.info()
1720 for x in info[1:]:
1721 if len(x) < 2:
1722 print "%-23s: (none)" % x[0]
1723 else:
1724 print "%-23s:" % x[0], x[1]
1726 def xm_console(args):
1727 arg_check(args, "console", 1, 2)
1729 quiet = False;
1731 try:
1732 (options, params) = getopt.gnu_getopt(args, 'q', ['quiet'])
1733 except getopt.GetoptError, opterr:
1734 err(opterr)
1735 usage('console')
1737 for (k, v) in options:
1738 if k in ['-q', '--quiet']:
1739 quiet = True
1740 else:
1741 assert False
1743 if len(params) != 1:
1744 err('No domain given')
1745 usage('console')
1747 dom = params[0]
1749 try:
1750 if serverType == SERVER_XEN_API:
1751 domid = int(server.xenapi.VM.get_domid(get_single_vm(dom)))
1752 else:
1753 info = server.xend.domain(dom)
1754 domid = int(sxp.child_value(info, 'domid', '-1'))
1755 except:
1756 if quiet:
1757 sys.exit(1)
1758 else:
1759 raise
1761 if domid == -1:
1762 if quiet:
1763 sys.exit(1)
1764 else:
1765 raise xmlrpclib.Fault(0, "Domain '%s' is not started" % dom)
1767 console.execConsole(domid)
1770 def xm_uptime(args):
1771 short_mode = 0
1773 try:
1774 (options, params) = getopt.gnu_getopt(args, 's', ['short'])
1775 except getopt.GetoptError, opterr:
1776 err(opterr)
1777 usage('uptime')
1779 for (k, v) in options:
1780 if k in ['-s', '--short']:
1781 short_mode = 1
1783 doms = getDomains(params, 'all')
1785 if short_mode == 0:
1786 print '%-33s %4s %s ' % ('Name','ID','Uptime')
1788 for dom in doms:
1789 d = parse_doms_info(dom)
1790 if d['domid'] == '':
1791 uptime = 0
1792 elif int(d['domid']) > 0:
1793 uptime = int(round(d['up_time']))
1794 else:
1795 f=open('/proc/uptime', 'r')
1796 upfile = f.read()
1797 uptime = int(round(float(upfile.split(' ')[0])))
1798 f.close()
1800 days = int(uptime / 86400)
1801 uptime -= (days * 86400)
1802 hours = int(uptime / 3600)
1803 uptime -= (hours * 3600)
1804 minutes = int(uptime / 60)
1805 uptime -= (minutes * 60)
1806 seconds = uptime
1808 upstring = ""
1809 if days > 0:
1810 upstring += str(days) + " day"
1811 if days > 1:
1812 upstring += "s"
1813 upstring += ", "
1814 upstring += '%(hours)2d:%(minutes)02d' % vars()
1816 if short_mode:
1817 now = datetime.datetime.now()
1818 upstring = now.strftime(" %H:%M:%S") + " up " + upstring
1819 upstring += ", " + d['name'] + " (" + d['domid'] + ")"
1820 else:
1821 upstring += ':%(seconds)02d' % vars()
1822 upstring = ("%(name)-32s %(domid)5s " % d) + upstring
1824 print upstring
1826 def xm_sysrq(args):
1827 arg_check(args, "sysrq", 2)
1828 dom = args[0]
1829 req = args[1]
1830 if serverType == SERVER_XEN_API:
1831 server.xenapi.VM.send_sysrq(get_single_vm(dom), req)
1832 else:
1833 server.xend.domain.send_sysrq(dom, req)
1835 def xm_trigger(args):
1836 vcpu = 0
1838 arg_check(args, "trigger", 2, 3)
1839 dom = args[0]
1840 trigger = args[1]
1841 if len(args) == 3:
1842 vcpu = int(args[2])
1844 if serverType == SERVER_XEN_API:
1845 server.xenapi.VM.send_trigger(get_single_vm(dom), trigger, vcpu)
1846 else:
1847 server.xend.domain.send_trigger(dom, trigger, vcpu)
1849 def xm_debug_keys(args):
1850 arg_check(args, "debug-keys", 1)
1852 keys = str(args[0])
1854 if serverType == SERVER_XEN_API:
1855 server.xenapi.host.send_debug_keys(
1856 server.xenapi.session.get_this_host(server.getSession()),
1857 keys)
1858 else:
1859 server.xend.node.send_debug_keys(keys)
1861 def xm_top(args):
1862 arg_check(args, "top", 0)
1864 os.system('xentop')
1866 def xm_dmesg(args):
1867 arg_check(args, "dmesg", 0, 1)
1869 try:
1870 (options, params) = getopt.gnu_getopt(args, 'c', ['clear'])
1871 except getopt.GetoptError, opterr:
1872 err(opterr)
1873 usage('dmesg')
1875 use_clear = 0
1876 for (k, v) in options:
1877 if k in ['-c', '--clear']:
1878 use_clear = 1
1880 if len(params) :
1881 err("No parameter required")
1882 usage('dmesg')
1884 if serverType == SERVER_XEN_API:
1885 host = server.xenapi.session.get_this_host(server.getSession())
1886 if use_clear:
1887 print server.xenapi.host.dmesg_clear(host),
1888 else:
1889 print server.xenapi.host.dmesg(host),
1890 else:
1891 if not use_clear:
1892 print server.xend.node.dmesg.info(),
1893 else:
1894 print server.xend.node.dmesg.clear(),
1896 def xm_log(args):
1897 arg_check(args, "log", 0)
1899 if serverType == SERVER_XEN_API:
1900 print server.xenapi.host.get_log(
1901 server.xenapi.session.get_this_host(server.getSession()))
1902 else:
1903 print server.xend.node.log()
1905 def xm_serve(args):
1906 if serverType == SERVER_XEN_API:
1907 print "Not supported with XenAPI"
1908 sys.exit(-1)
1910 arg_check(args, "serve", 0)
1912 from fcntl import fcntl, F_SETFL
1914 s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
1915 s.connect(XendClient.XML_RPC_SOCKET)
1916 fcntl(sys.stdin, F_SETFL, os.O_NONBLOCK)
1918 while True:
1919 iwtd, owtd, ewtd = select([sys.stdin, s], [], [])
1920 if s in iwtd:
1921 data = s.recv(4096)
1922 if len(data) > 0:
1923 sys.stdout.write(data)
1924 sys.stdout.flush()
1925 else:
1926 break
1927 if sys.stdin in iwtd:
1928 data = sys.stdin.read(4096)
1929 if len(data) > 0:
1930 s.sendall(data)
1931 else:
1932 break
1933 s.close()
1935 def parse_dev_info(info):
1936 def get_info(n, t, d):
1937 i = 0
1938 while i < len(info):
1939 if (info[i][0] == n):
1940 return t(info[i][1])
1941 i = i + 1
1942 return t(d)
1943 return {
1944 #common
1945 'backend-id' : get_info('backend-id', int, -1),
1946 'handle' : get_info('handle', int, 0),
1947 'state' : get_info('state', int, -1),
1948 'be-path' : get_info('backend', str, '??'),
1949 'event-ch' : get_info('event-channel',int, -1),
1950 #network specific
1951 'virtual-device' : get_info('virtual-device', str, '??'),
1952 'tx-ring-ref': get_info('tx-ring-ref', int, -1),
1953 'rx-ring-ref': get_info('rx-ring-ref', int, -1),
1954 'mac' : get_info('mac', str, '??'),
1955 #block-device specific
1956 'ring-ref' : get_info('ring-ref', int, -1),
1959 def arg_check_for_resource_list(args, name):
1960 use_long = 0
1961 try:
1962 (options, params) = getopt.gnu_getopt(args, 'l', ['long'])
1963 except getopt.GetoptError, opterr:
1964 err(opterr)
1965 sys.exit(1)
1967 for (k, v) in options:
1968 if k in ['-l', '--long']:
1969 use_long = 1
1971 if len(params) == 0:
1972 print 'No domain parameter given'
1973 usage(name)
1974 if len(params) > 1:
1975 print 'No multiple domain parameters allowed'
1976 usage(name)
1978 return (use_long, params)
1980 def xm_network_list(args):
1981 (use_long, params) = arg_check_for_resource_list(args, "network-list")
1983 dom = params[0]
1985 if serverType == SERVER_XEN_API:
1986 vif_refs = server.xenapi.VM.get_VIFs(get_single_vm(dom))
1987 vif_properties = \
1988 map(server.xenapi.VIF.get_runtime_properties, vif_refs)
1989 devs = map(lambda (handle, properties): [handle, map2sxp(properties)],
1990 zip(range(len(vif_properties)), vif_properties))
1991 else:
1992 devs = server.xend.domain.getDeviceSxprs(dom, 'vif')
1994 if use_long:
1995 map(PrettyPrint.prettyprint, devs)
1996 else:
1997 hdr = 0
1998 for x in devs:
1999 if hdr == 0:
2000 print 'Idx BE MAC Addr. handle state evt-ch tx-/rx-ring-ref BE-path'
2001 hdr = 1
2002 ni = parse_dev_info(x[1])
2003 ni['idx'] = int(x[0])
2004 print ("%(idx)-3d "
2005 "%(backend-id)-3d"
2006 "%(mac)-17s "
2007 "%(handle)-3d "
2008 "%(state)-3d "
2009 "%(event-ch)-3d "
2010 "%(tx-ring-ref)-5d/%(rx-ring-ref)-5d "
2011 "%(be-path)-30s "
2012 % ni)
2014 def xm_block_list(args):
2015 (use_long, params) = arg_check_for_resource_list(args, "block-list")
2017 dom = params[0]
2019 if serverType == SERVER_XEN_API:
2020 vbd_refs = server.xenapi.VM.get_VBDs(get_single_vm(dom))
2021 vbd_properties = \
2022 map(server.xenapi.VBD.get_runtime_properties, vbd_refs)
2023 vbd_devs = \
2024 map(server.xenapi.VBD.get_device, vbd_refs)
2025 vbd_devids = \
2026 map(blkdev_name_to_number, vbd_devs)
2027 devs = map(lambda (devid, prop): [devid, map2sxp(prop)],
2028 zip(vbd_devids, vbd_properties))
2029 else:
2030 devs = server.xend.domain.getDeviceSxprs(dom, 'vbd')
2032 if use_long:
2033 map(PrettyPrint.prettyprint, devs)
2034 else:
2035 hdr = 0
2036 for x in devs:
2037 if hdr == 0:
2038 print 'Vdev BE handle state evt-ch ring-ref BE-path'
2039 hdr = 1
2040 ni = parse_dev_info(x[1])
2041 ni['idx'] = int(x[0])
2042 print ("%(idx)-3d "
2043 "%(backend-id)-3d "
2044 "%(handle)-3d "
2045 "%(state)-3d "
2046 "%(event-ch)-3d "
2047 "%(ring-ref)-5d "
2048 "%(be-path)-30s "
2049 % ni)
2051 def xm_vtpm_list(args):
2052 (use_long, params) = arg_check_for_resource_list(args, "vtpm-list")
2054 dom = params[0]
2056 if serverType == SERVER_XEN_API:
2057 vtpm_refs = server.xenapi.VM.get_VTPMs(get_single_vm(dom))
2058 vtpm_properties = \
2059 map(server.xenapi.VTPM.get_runtime_properties, vtpm_refs)
2060 devs = map(lambda (handle, properties): [handle, map2sxp(properties)],
2061 zip(range(len(vtpm_properties)), vtpm_properties))
2062 else:
2063 devs = server.xend.domain.getDeviceSxprs(dom, 'vtpm')
2065 if use_long:
2066 map(PrettyPrint.prettyprint, devs)
2067 else:
2068 hdr = 0
2069 for x in devs:
2070 if hdr == 0:
2071 print 'Idx BE handle state evt-ch ring-ref BE-path'
2072 hdr = 1
2073 ni = parse_dev_info(x[1])
2074 ni['idx'] = int(x[0])
2075 print ("%(idx)-3d "
2076 "%(backend-id)-3d "
2077 "%(handle)-3d "
2078 "%(state)-3d "
2079 "%(event-ch)-3d "
2080 "%(ring-ref)-5d "
2081 "%(be-path)-30s "
2082 % ni)
2085 def xm_pci_list(args):
2086 (use_long, params) = arg_check_for_resource_list(args, "pci-list")
2088 dom = params[0]
2090 devs = server.xend.domain.getDeviceSxprs(dom, 'pci')
2092 if len(devs) == 0:
2093 return
2095 has_vslt = devs[0].has_key('vslt')
2096 if has_vslt:
2097 hdr_str = 'VSlt domain bus slot func'
2098 fmt_str = "%(vslt)-3s %(domain)-3s %(bus)-3s %(slot)-3s %(func)-3s "
2099 else:
2100 hdr_str = 'domain bus slot func'
2101 fmt_str = "%(domain)-3s %(bus)-3s %(slot)-3s %(func)-3s "
2102 hdr = 0
2104 for x in devs:
2105 if hdr == 0:
2106 print (hdr_str)
2107 hdr = 1
2108 print ( fmt_str % x )
2110 def parse_block_configuration(args):
2111 dom = args[0]
2113 if args[1].startswith('tap:'):
2114 cls = 'tap'
2115 else:
2116 cls = 'vbd'
2118 vbd = [cls,
2119 ['uname', args[1]],
2120 ['dev', args[2]],
2121 ['mode', args[3]]]
2122 if len(args) == 5:
2123 vbd.append(['backend', args[4]])
2125 return (dom, vbd)
2128 def xm_block_attach(args):
2129 arg_check(args, 'block-attach', 4, 5)
2131 if serverType == SERVER_XEN_API:
2132 dom = args[0]
2133 uname = args[1]
2134 dev = args[2]
2135 mode = args[3]
2137 # First create new VDI
2138 vdi_record = {
2139 "name_label": "vdi" + str(uname.__hash__()),
2140 "name_description": "",
2141 "SR": get_default_SR(),
2142 "virtual_size": 0,
2143 "sector_size": 512,
2144 "type": "system",
2145 "sharable": False,
2146 "read_only": mode!="w",
2147 "other_config": {"location": uname}
2150 vdi_ref = server.xenapi.VDI.create(vdi_record)
2152 # Now create new VBD
2154 vbd_record = {
2155 "VM": get_single_vm(dom),
2156 "VDI": vdi_ref,
2157 "device": dev,
2158 "bootable": True,
2159 "mode": mode=="w" and "RW" or "RO",
2160 "type": "Disk",
2161 "qos_algorithm_type": "",
2162 "qos_algorithm_params": {}
2165 server.xenapi.VBD.create(vbd_record)
2167 else:
2168 (dom, vbd) = parse_block_configuration(args)
2169 server.xend.domain.device_create(dom, vbd)
2172 def xm_block_configure(args):
2173 arg_check(args, 'block-configure', 4, 5)
2175 (dom, vbd) = parse_block_configuration(args)
2176 server.xend.domain.device_configure(dom, vbd)
2179 def xm_network_attach(args):
2180 arg_check(args, 'network-attach', 1, 11)
2182 dom = args[0]
2183 vif = ['vif']
2184 vif_params = ['type', 'mac', 'bridge', 'ip', 'script', \
2185 'backend', 'vifname', 'rate', 'model', 'accel']
2187 if serverType == SERVER_XEN_API:
2188 vif_record = {
2189 "device": "eth0",
2190 "network": get_default_Network(),
2191 "VM": get_single_vm(dom),
2192 "MAC": "",
2193 "MTU": "",
2194 "qos_algorithm_type": "",
2195 "qos_algorithm_params": {},
2196 "other_config": {}
2199 def set(keys, val):
2200 record = vif_record
2201 for key in keys[:-1]:
2202 record = record[key]
2203 record[keys[-1]] = val
2205 def get_net_from_bridge(bridge):
2206 # In OSS, we just assert network.name_label == bridge name
2207 networks = dict([(record['name_label'], ref)
2208 for ref, record in server.xenapi.network
2209 .get_all_records().items()])
2210 if bridge not in networks.keys():
2211 raise "Unknown bridge name!"
2212 return networks[bridge]
2214 vif_conv = {
2215 'type':
2216 lambda x: None,
2217 'mac':
2218 lambda x: set(['MAC'], x),
2219 'bridge':
2220 lambda x: set(['network'], get_net_from_bridge(x)),
2221 'ip':
2222 lambda x: set(['other_config', 'ip'], x),
2223 'script':
2224 lambda x: set(['other_config', 'script'], x),
2225 'backend':
2226 lambda x: set(['other_config', 'backend'], x),
2227 'vifname':
2228 lambda x: set(['device'], x),
2229 'rate':
2230 lambda x: set(['qos_algorithm_params', 'rate'], x),
2231 'model':
2232 lambda x: None,
2233 'accel':
2234 lambda x: set(['other_config', 'accel'], x)
2237 for a in args[1:]:
2238 vif_param = a.split("=")
2239 if len(vif_param) != 2 or vif_param[1] == '' or \
2240 vif_param[0] not in vif_params:
2241 err("Invalid argument: %s" % a)
2242 usage('network-attach')
2243 else:
2244 vif_conv[vif_param[0]](vif_param[1])
2246 server.xenapi.VIF.create(vif_record)
2247 else:
2248 for a in args[1:]:
2249 vif_param = a.split("=")
2250 if len(vif_param) != 2 or vif_param[1] == '' or \
2251 vif_param[0] not in vif_params:
2252 err("Invalid argument: %s" % a)
2253 usage('network-attach')
2254 vif.append(vif_param)
2255 server.xend.domain.device_create(dom, vif)
2257 def parse_pci_configuration(args, state):
2258 dom = args[0]
2259 pci_dev_str = args[1]
2260 if len(args) == 3:
2261 vslt = args[2]
2262 else:
2263 vslt = '0x0' #chose a free virtual PCI slot
2264 pci=['pci']
2265 pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \
2266 r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \
2267 r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \
2268 r"(?P<func>[0-7])$", pci_dev_str)
2269 if pci_match == None:
2270 raise OptionError("Invalid argument: %s %s" % (pci_dev_str,vslt))
2271 pci_dev_info = pci_match.groupdict('0')
2272 try:
2273 pci.append(['dev', ['domain', '0x'+ pci_dev_info['domain']], \
2274 ['bus', '0x'+ pci_dev_info['bus']],
2275 ['slot', '0x'+ pci_dev_info['slot']],
2276 ['func', '0x'+ pci_dev_info['func']],
2277 ['vslt', '0x%x' % int(vslt, 16)]])
2278 except:
2279 raise OptionError("Invalid argument: %s %s" % (pci_dev_str,vslt))
2280 pci.append(['state', state])
2282 return (dom, pci)
2284 def xm_pci_attach(args):
2285 arg_check(args, 'pci-attach', 2, 3)
2286 (dom, pci) = parse_pci_configuration(args, 'Initialising')
2287 server.xend.domain.device_configure(dom, pci)
2289 def detach(args, deviceClass):
2290 rm_cfg = True
2291 dom = args[0]
2292 dev = args[1]
2293 try:
2294 force = args[2]
2295 if (force != "--force") and (force != "-f"):
2296 print "Ignoring option %s"%(force)
2297 force = None
2298 except IndexError:
2299 force = None
2301 server.xend.domain.destroyDevice(dom, deviceClass, dev, force, rm_cfg)
2304 def xm_block_detach(args):
2305 if serverType == SERVER_XEN_API:
2306 arg_check(args, "block-detach", 2, 3)
2307 dom = args[0]
2308 dev = args[1]
2309 vbd_refs = server.xenapi.VM.get_VBDs(get_single_vm(dom))
2310 vbd_refs = [vbd_ref for vbd_ref in vbd_refs
2311 if server.xenapi.VBD.get_device(vbd_ref) == dev]
2312 if len(vbd_refs) > 0:
2313 vbd_ref = vbd_refs[0]
2314 vdi_ref = server.xenapi.VBD.get_VDI(vbd_ref)
2316 server.xenapi.VBD.destroy(vbd_ref)
2318 if len(server.xenapi.VDI.get_VBDs(vdi_ref)) <= 0:
2319 server.xenapi.VDI.destroy(vdi_ref)
2320 else:
2321 raise OptionError("Cannot find device '%s' in domain '%s'"
2322 % (dev,dom))
2323 else:
2324 arg_check(args, 'block-detach', 2, 3)
2325 dom = args[0]
2326 dev = args[1]
2327 dc = server.xend.domain.getBlockDeviceClass(dom, dev)
2328 if dc == "tap":
2329 detach(args, 'tap')
2330 else:
2331 detach(args, 'vbd')
2333 def xm_network_detach(args):
2334 if serverType == SERVER_XEN_API:
2335 arg_check(args, "network-detach", 2, 3)
2336 dom = args[0]
2337 devid = args[1]
2338 vif_refs = server.xenapi.VM.get_VIFs(get_single_vm(dom))
2339 vif_refs = [vif_ref for vif_ref in vif_refs
2340 if server.xenapi.VIF.\
2341 get_runtime_properties(vif_ref)["handle"] == devid]
2342 if len(vif_refs) > 0:
2343 vif_ref = vif_refs[0]
2345 server.xenapi.VIF.destroy(vif_ref)
2346 else:
2347 print "Cannot find device '%s' in domain '%s'" % (devid,dom)
2348 else:
2349 arg_check(args, 'network-detach', 2, 3)
2350 detach(args, 'vif')
2352 def xm_pci_detach(args):
2353 arg_check(args, 'pci-detach', 2)
2354 (dom, pci) = parse_pci_configuration(args, 'Closing')
2355 server.xend.domain.device_configure(dom, pci)
2358 def xm_vnet_list(args):
2359 xenapi_unsupported()
2360 try:
2361 (options, params) = getopt.gnu_getopt(args, 'l', ['long'])
2362 except getopt.GetoptError, opterr:
2363 err(opterr)
2364 usage('vnet-list')
2366 use_long = 0
2367 for (k, v) in options:
2368 if k in ['-l', '--long']:
2369 use_long = 1
2371 if params:
2372 use_long = 1
2373 vnets = params
2374 else:
2375 vnets = server.xend_vnets()
2377 for vnet in vnets:
2378 try:
2379 if use_long:
2380 info = server.xend_vnet(vnet)
2381 PrettyPrint.prettyprint(info)
2382 else:
2383 print vnet
2384 except Exception, ex:
2385 print vnet, ex
2387 def xm_vnet_create(args):
2388 xenapi_unsupported()
2389 arg_check(args, "vnet-create", 1)
2390 conf = args[0]
2391 if not os.access(conf, os.R_OK):
2392 print "File not found: %s" % conf
2393 sys.exit(1)
2395 server.xend_vnet_create(conf)
2397 def xm_vnet_delete(args):
2398 xenapi_unsupported()
2399 arg_check(args, "vnet-delete", 1)
2400 vnet = args[0]
2401 server.xend_vnet_delete(vnet)
2403 def xm_network_new(args):
2404 xenapi_only()
2405 arg_check(args, "network-new", 1)
2406 network = args[0]
2408 record = {
2409 "name_label": network,
2410 "name_description": "",
2411 "other_config": {},
2412 "default_gateway": "",
2413 "default_netmask": ""
2416 server.xenapi.network.create(record)
2418 def xm_network_del(args):
2419 xenapi_only()
2420 arg_check(args, "network-del", 1)
2421 network = args[0]
2423 networks = dict([(record['name_label'], ref)
2424 for ref, record in
2425 server.xenapi.network.get_all_records().items()])
2427 if network not in networks.keys():
2428 raise ValueError("'%s' is not a valid network name" % network)
2430 server.xenapi.network.destroy(networks[network])
2432 def xm_network_show(args):
2433 xenapi_only()
2434 arg_check(args, "network-show", 0)
2436 networks = server.xenapi.network.get_all_records()
2437 pifs = server.xenapi.PIF.get_all_records()
2438 vifs = server.xenapi.VIF.get_all_records()
2440 print '%-20s %-40s %-10s' % \
2441 ('Name', 'VIFs', 'PIFs')
2443 format2 = "%(name_label)-20s %(vif)-40s %(pif)-10s"
2445 for network_ref, network in networks.items():
2446 for i in range(max(len(network['PIFs']),
2447 len(network['VIFs']), 1)):
2448 if i < len(network['PIFs']):
2449 pif_uuid = network['PIFs'][i]
2450 else:
2451 pif_uuid = None
2453 if i < len(network['VIFs']):
2454 vif_uuid = network['VIFs'][i]
2455 else:
2456 vif_uuid = None
2458 pif = pifs.get(pif_uuid, None)
2459 vif = vifs.get(vif_uuid, None)
2461 if vif:
2462 dom_name = server.xenapi.VM.get_name_label(vif['VM'])
2463 vif = "%s.%s" % (dom_name, vif['device'])
2464 else:
2465 vif = ''
2467 if pif:
2468 if int(pif['VLAN']) > -1:
2469 pif = '%s.%s' % (pif['device'], pif['VLAN'])
2470 else:
2471 pif = pif['device']
2472 else:
2473 pif = ''
2475 if i == 0:
2476 r = {'name_label':network['name_label'],
2477 'vif':vif, 'pif':pif}
2478 else:
2479 r = {'name_label':'', 'vif':vif, 'pif':pif}
2481 print format2 % r
2484 commands = {
2485 "shell": xm_shell,
2486 "event-monitor": xm_event_monitor,
2487 # console commands
2488 "console": xm_console,
2489 # xenstat commands
2490 "top": xm_top,
2491 # domain commands
2492 "delete": xm_delete,
2493 "destroy": xm_destroy,
2494 "domid": xm_domid,
2495 "domname": xm_domname,
2496 "dump-core": xm_dump_core,
2497 "reboot": xm_reboot,
2498 "rename": xm_rename,
2499 "reset": xm_reset,
2500 "restore": xm_restore,
2501 "resume": xm_resume,
2502 "save": xm_save,
2503 "shutdown": xm_shutdown,
2504 "start": xm_start,
2505 "sysrq": xm_sysrq,
2506 "trigger": xm_trigger,
2507 "uptime": xm_uptime,
2508 "suspend": xm_suspend,
2509 "list": xm_list,
2510 # memory commands
2511 "mem-max": xm_mem_max,
2512 "mem-set": xm_mem_set,
2513 # cpu commands
2514 "vcpu-pin": xm_vcpu_pin,
2515 "vcpu-list": xm_vcpu_list,
2516 "vcpu-set": xm_vcpu_set,
2517 # special
2518 "pause": xm_pause,
2519 "unpause": xm_unpause,
2520 # host commands
2521 "debug-keys": xm_debug_keys,
2522 "dmesg": xm_dmesg,
2523 "info": xm_info,
2524 "log": xm_log,
2525 "serve": xm_serve,
2526 # scheduler
2527 "sched-sedf": xm_sched_sedf,
2528 "sched-credit": xm_sched_credit,
2529 # block
2530 "block-attach": xm_block_attach,
2531 "block-detach": xm_block_detach,
2532 "block-list": xm_block_list,
2533 "block-configure": xm_block_configure,
2534 # network (AKA vifs)
2535 "network-attach": xm_network_attach,
2536 "network-detach": xm_network_detach,
2537 "network-list": xm_network_list,
2538 # network (as in XenAPI)
2539 "network-new": xm_network_new,
2540 "network-del": xm_network_del,
2541 "network-show": xm_network_show,
2542 # vnet
2543 "vnet-list": xm_vnet_list,
2544 "vnet-create": xm_vnet_create,
2545 "vnet-delete": xm_vnet_delete,
2546 # vtpm
2547 "vtpm-list": xm_vtpm_list,
2548 #pci
2549 "pci-attach": xm_pci_attach,
2550 "pci-detach": xm_pci_detach,
2551 "pci-list": xm_pci_list,
2554 ## The commands supported by a separate argument parser in xend.xm.
2555 IMPORTED_COMMANDS = [
2556 'create',
2557 'new',
2558 'migrate',
2559 'labels',
2560 'dumppolicy',
2561 'addlabel',
2562 'rmlabel',
2563 'getlabel',
2564 'dry-run',
2565 'resources',
2566 'getpolicy',
2567 'setpolicy',
2568 'resetpolicy',
2571 for c in IMPORTED_COMMANDS:
2572 commands[c] = eval('lambda args: xm_importcommand("%s", args)' % c)
2574 aliases = {
2575 "balloon": "mem-set",
2576 "set-vcpus": "vcpu-set",
2577 "vif-list": "network-list",
2578 "vbd-create": "block-attach",
2579 "vbd-destroy": "block-detach",
2580 "vbd-list": "block-list",
2584 def xm_lookup_cmd(cmd):
2585 if commands.has_key(cmd):
2586 return commands[cmd]
2587 elif aliases.has_key(cmd):
2588 deprecated(cmd,aliases[cmd])
2589 return commands[aliases[cmd]]
2590 elif cmd == 'help':
2591 longHelp()
2592 sys.exit(0)
2593 else:
2594 # simulate getopt's prefix matching behaviour
2595 if len(cmd) > 1:
2596 same_prefix_cmds = [commands[c] for c in commands.keys() \
2597 if c[:len(cmd)] == cmd]
2598 # only execute if there is only 1 match
2599 if len(same_prefix_cmds) == 1:
2600 return same_prefix_cmds[0]
2601 return None
2603 def deprecated(old,new):
2604 print >>sys.stderr, (
2605 "Command %s is deprecated. Please use xm %s instead." % (old, new))
2607 def main(argv=sys.argv):
2608 if len(argv) < 2:
2609 usage()
2611 # intercept --help(-h) and output our own help
2612 for help in ['--help', '-h']:
2613 if help in argv[1:]:
2614 if help == argv[1]:
2615 longHelp()
2616 sys.exit(0)
2617 else:
2618 usage(argv[1])
2620 cmd_name = argv[1]
2621 cmd = xm_lookup_cmd(cmd_name)
2622 if cmd:
2623 # strip off prog name and subcmd
2624 args = argv[2:]
2625 _, rc = _run_cmd(cmd, cmd_name, args)
2626 sys.exit(rc)
2627 else:
2628 err('Subcommand %s not found!' % cmd_name)
2629 usage()
2631 def _run_cmd(cmd, cmd_name, args):
2632 global server
2634 try:
2635 if server is None:
2636 if serverType == SERVER_XEN_API:
2637 server = XenAPI.Session(serverURI)
2638 username, password = parseAuthentication()
2639 server.login_with_password(username, password)
2640 def logout():
2641 try:
2642 server.xenapi.session.logout()
2643 except:
2644 pass
2645 atexit.register(logout)
2646 else:
2647 server = ServerProxy(serverURI)
2649 return True, cmd(args)
2650 except socket.error, ex:
2651 if os.geteuid() != 0:
2652 err("Most commands need root access. Please try again as root.")
2653 else:
2654 err("Unable to connect to xend: %s. Is xend running?" % ex[1])
2655 except KeyboardInterrupt:
2656 print "Interrupted."
2657 return True, ''
2658 except IOError, ex:
2659 if os.geteuid() != 0:
2660 err("Most commands need root access. Please try again as root.")
2661 else:
2662 err("Unable to connect to xend: %s." % ex[1])
2663 except SystemExit, code:
2664 return code == 0, code
2665 except XenAPI.Failure, exn:
2666 for line in [''] + wrap(str(exn), 80) + ['']:
2667 print >>sys.stderr, line
2668 except xmlrpclib.Fault, ex:
2669 if ex.faultCode == XendClient.ERROR_INVALID_DOMAIN:
2670 err("Domain '%s' does not exist." % ex.faultString)
2671 else:
2672 err(ex.faultString)
2673 _usage(cmd_name)
2674 except xmlrpclib.ProtocolError, ex:
2675 if ex.errcode == -1:
2676 print >>sys.stderr, (
2677 "Xend has probably crashed! Invalid or missing HTTP "
2678 "status code.")
2679 else:
2680 print >>sys.stderr, (
2681 "Xend has probably crashed! ProtocolError(%d, %s)." %
2682 (ex.errcode, ex.errmsg))
2683 except (ValueError, OverflowError):
2684 err("Invalid argument.")
2685 _usage(cmd_name)
2686 except OptionError, e:
2687 err(str(e))
2688 _usage(cmd_name)
2689 print e.usage
2690 except XenAPIUnsupportedException, e:
2691 err(str(e))
2692 except XSMError, e:
2693 err(str(e))
2694 except Exception, e:
2695 if serverType != SERVER_XEN_API:
2696 import xen.util.xsm.xsm as security
2697 if isinstance(e, security.XSMError):
2698 err(str(e))
2699 return False, 1
2700 print "Unexpected error:", sys.exc_info()[0]
2701 print
2702 print "Please report to xen-devel@lists.xensource.com"
2703 raise
2705 return False, 1
2707 if __name__ == "__main__":
2708 main()