ia64/xen-unstable

view tools/python/xen/xm/main.py @ 17238:4ee7c6a4d193

xm: allow non-existent readline module

Let xm work even if Python doesn't have its readline module installed.

Signed-off-by: John Levon <john.levon@sun.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Mar 18 11:32:06 2008 +0000 (2008-03-18)
parents f76f151a7431
children 3f407392da49
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 'restore' : ('<CheckpointFile> [-p]',
111 'Restore a domain from a saved state.'),
112 'save' : ('[-c] <Domain> <CheckpointFile>',
113 'Save a domain state to restore later.'),
114 'shutdown' : ('<Domain> [-waRH]', 'Shutdown a domain.'),
115 'top' : ('', 'Monitor a host and the domains in real time.'),
116 'unpause' : ('<Domain>', 'Unpause a paused domain.'),
117 'uptime' : ('[-s] [Domain, ...]',
118 'Print uptime for all/some domains.'),
120 # Life cycle xm commands
121 'new' : ('<ConfigFile> [options] [vars]',
122 'Adds a domain to Xend domain management'),
123 'delete' : ('<DomainName>',
124 'Remove a domain from Xend domain management.'),
125 'start' : ('<DomainName>', 'Start a Xend managed domain'),
126 'resume' : ('<DomainName>', 'Resume a Xend managed domain'),
127 'suspend' : ('<DomainName>', 'Suspend a Xend managed domain'),
129 # less used commands
131 'dmesg' : ('[-c|--clear]',
132 'Read and/or clear Xend\'s message buffer.'),
133 'domid' : ('<DomainName>', 'Convert a domain name to domain id.'),
134 'domname' : ('<DomId>', 'Convert a domain id to domain name.'),
135 'dump-core' : ('[-L|--live] [-C|--crash] <Domain> [Filename]',
136 'Dump core for a specific domain.'),
137 'info' : ('[-c|--config]', 'Get information about Xen host.'),
138 'log' : ('', 'Print Xend log'),
139 'rename' : ('<Domain> <NewDomainName>', 'Rename a domain.'),
140 'sched-sedf' : ('<Domain> [options]', 'Get/set EDF parameters.'),
141 'sched-credit': ('[-d <Domain> [-w[=WEIGHT]|-c[=CAP]]]',
142 'Get/set credit scheduler parameters.'),
143 'sysrq' : ('<Domain> <letter>', 'Send a sysrq to a domain.'),
144 'debug-keys' : ('<Keys>', 'Send debug keys to Xen.'),
145 'trigger' : ('<Domain> <nmi|reset|init> [<VCPU>]',
146 'Send a trigger to a domain.'),
147 'vcpu-list' : ('[Domain, ...]',
148 'List the VCPUs for all/some domains.'),
149 'vcpu-pin' : ('<Domain> <VCPU|all> <CPUs|all>',
150 'Set which CPUs a VCPU can use.'),
151 'vcpu-set' : ('<Domain> <vCPUs>',
152 'Set the number of active VCPUs for allowed for the'
153 ' domain.'),
155 # device commands
157 'block-attach' : ('<Domain> <BackDev> <FrontDev> <Mode> [BackDomain]',
158 'Create a new virtual block device.'),
159 'block-configure': ('<Domain> <BackDev> <FrontDev> <Mode> [BackDomain]',
160 'Change block device configuration'),
161 'block-detach' : ('<Domain> <DevId> [-f|--force]',
162 'Destroy a domain\'s virtual block device.'),
163 'block-list' : ('<Domain> [--long]',
164 'List virtual block devices for a domain.'),
165 'network-attach': ('<Domain> [type=<type>] [mac=<mac>] [bridge=<bridge>] '
166 '[ip=<ip>] [script=<script>] [backend=<BackDomain>] '
167 '[vifname=<name>] [rate=<rate>] [model=<model>]'
168 '[accel=<accel>]',
169 'Create a new virtual network device.'),
170 'network-detach': ('<Domain> <DevId> [-f|--force]',
171 'Destroy a domain\'s virtual network device.'),
172 'network-list' : ('<Domain> [--long]',
173 'List virtual network interfaces for a domain.'),
174 'vnet-create' : ('<ConfigFile>','Create a vnet from ConfigFile.'),
175 'vnet-delete' : ('<VnetId>', 'Delete a Vnet.'),
176 'vnet-list' : ('[-l|--long]', 'List Vnets.'),
177 'vtpm-list' : ('<Domain> [--long]', 'List virtual TPM devices.'),
178 'pci-attach ' : ('<Domain> <dom> <bus> <slot> <func> [virtual slot]',
179 'Insert a new pass-through pci device.'),
180 'pci-detach ' : ('<Domain> <virtual slot>',
181 'Remove a domain\'s pass-through pci device.'),
182 'pci-list' : ('<Domain>',
183 'List pass-through pci devices for a domain.'),
185 # security
187 'addlabel' : ('<label> {dom <ConfigFile>|res <resource>|mgt <managed domain>}\n'
188 ' [<policy>]',
189 'Add security label to domain.'),
190 'rmlabel' : ('{dom <ConfigFile>|res <Resource>|mgt<managed domain>}',
191 'Remove a security label from domain.'),
192 'getlabel' : ('{dom <ConfigFile>|res <Resource>|mgt <managed domain>}',
193 'Show security label for domain or resource.'),
194 'dry-run' : ('<ConfigFile>',
195 'Test if a domain can access its resources.'),
196 'resources' : ('', 'Show info for each labeled resource.'),
197 'dumppolicy' : ('', 'Print hypervisor ACM state information.'),
198 'setpolicy' : ('<policytype> <policyfile> [options]',
199 'Set the policy of the system.'),
200 'resetpolicy' : ('',
201 'Set the policy of the system to the default policy.'),
202 'getpolicy' : ('[options]', 'Get the policy of the system.'),
203 'labels' : ('[policy] [type=dom|res|any]',
204 'List <type> labels for (active) policy.'),
205 'serve' : ('', 'Proxy Xend XMLRPC over stdio.'),
206 }
208 SUBCOMMAND_OPTIONS = {
209 'sched-sedf': (
210 ('-p [MS]', '--period[=MS]', 'Relative deadline(ms)'),
211 ('-s [MS]', '--slice[=MS]' ,
212 'Worst-case execution time(ms). (slice < period)'),
213 ('-l [MS]', '--latency[=MS]',
214 'Scaled period (ms) when domain performs heavy I/O'),
215 ('-e [FLAG]', '--extra[=FLAG]',
216 'Flag (0 or 1) controls if domain can run in extra time.'),
217 ('-w [FLOAT]', '--weight[=FLOAT]',
218 'CPU Period/slice (do not set with --period/--slice)'),
219 ),
220 'sched-credit': (
221 ('-d DOMAIN', '--domain=DOMAIN', 'Domain to modify'),
222 ('-w WEIGHT', '--weight=WEIGHT', 'Weight (int)'),
223 ('-c CAP', '--cap=CAP', 'Cap (int)'),
224 ),
225 'list': (
226 ('-l', '--long', 'Output all VM details in SXP'),
227 ('', '--label', 'Include security labels'),
228 ('', '--state=<state>', 'Select only VMs with the specified state'),
229 ),
230 'console': (
231 ('-q', '--quiet', 'Do not print an error message if the domain does not exist'),
232 ),
233 'dmesg': (
234 ('-c', '--clear', 'Clear dmesg buffer as well as printing it'),
235 ),
236 'vnet-list': (
237 ('-l', '--long', 'List Vnets as SXP'),
238 ),
239 'network-list': (
240 ('-l', '--long', 'List resources as SXP'),
241 ),
242 'dump-core': (
243 ('-L', '--live', 'Dump core without pausing the domain'),
244 ('-C', '--crash', 'Crash domain after dumping core'),
245 ),
246 'start': (
247 ('-p', '--paused', 'Do not unpause domain after starting it'),
248 ('-c', '--console_autoconnect', 'Connect to the console after the domain is created'),
249 ),
250 'resume': (
251 ('-p', '--paused', 'Do not unpause domain after resuming it'),
252 ),
253 'save': (
254 ('-c', '--checkpoint', 'Leave domain running after creating snapshot'),
255 ),
256 'restore': (
257 ('-p', '--paused', 'Do not unpause domain after restoring it'),
258 ),
259 'info': (
260 ('-c', '--config', 'List Xend configuration parameters'),
261 ),
262 }
264 common_commands = [
265 "console",
266 "create",
267 "new",
268 "delete",
269 "destroy",
270 "dump-core",
271 "help",
272 "list",
273 "mem-set",
274 "migrate",
275 "pause",
276 "reboot",
277 "restore",
278 "resume",
279 "save",
280 "shell",
281 "shutdown",
282 "start",
283 "suspend",
284 "top",
285 "unpause",
286 "uptime",
287 "vcpu-set",
288 ]
290 domain_commands = [
291 "console",
292 "create",
293 "new",
294 "delete",
295 "destroy",
296 "domid",
297 "domname",
298 "dump-core",
299 "list",
300 "mem-max",
301 "mem-set",
302 "migrate",
303 "pause",
304 "reboot",
305 "rename",
306 "restore",
307 "resume",
308 "save",
309 "shutdown",
310 "start",
311 "suspend",
312 "sysrq",
313 "trigger",
314 "top",
315 "unpause",
316 "uptime",
317 "vcpu-list",
318 "vcpu-pin",
319 "vcpu-set",
320 ]
322 host_commands = [
323 "debug-keys",
324 "dmesg",
325 "info",
326 "log",
327 "serve",
328 ]
330 scheduler_commands = [
331 "sched-credit",
332 "sched-sedf",
333 ]
335 device_commands = [
336 "block-attach",
337 "block-detach",
338 "block-list",
339 "block-configure",
340 "network-attach",
341 "network-detach",
342 "network-list",
343 "vtpm-list",
344 "pci-attach",
345 "pci-detach",
346 "pci-list",
347 ]
349 vnet_commands = [
350 "vnet-list",
351 "vnet-create",
352 "vnet-delete",
353 ]
355 acm_commands = [
356 "labels",
357 "addlabel",
358 "rmlabel",
359 "getlabel",
360 "dry-run",
361 "resources",
362 "dumppolicy",
363 "setpolicy",
364 "resetpolicy",
365 "getpolicy",
366 ]
368 all_commands = (domain_commands + host_commands + scheduler_commands +
369 device_commands + vnet_commands + acm_commands +
370 ['shell', 'event-monitor'])
373 ##
374 # Configuration File Parsing
375 ##
377 xmConfigFile = os.getenv(XM_CONFIG_FILE_ENVVAR, XM_CONFIG_FILE_DEFAULT)
378 config = None
379 if os.path.isfile(xmConfigFile):
380 try:
381 config = xml.dom.minidom.parse(xmConfigFile)
382 except:
383 print >>sys.stderr, ('Ignoring invalid configuration file %s.' %
384 xmConfigFile)
386 def parseServer():
387 if config:
388 server = config.getElementsByTagName('server')
389 if server:
390 st = server[0].getAttribute('type')
391 if st != SERVER_XEN_API and st != SERVER_LEGACY_XMLRPC:
392 print >>sys.stderr, ('Invalid server type %s; using %s.' %
393 (st, SERVER_LEGACY_XMLRPC))
394 st = SERVER_LEGACY_XMLRPC
395 return (st, server[0].getAttribute('uri'))
397 return SERVER_LEGACY_XMLRPC, XendClient.uri
399 def parseAuthentication():
400 server = config.getElementsByTagName('server')[0]
401 return (server.getAttribute('username'),
402 server.getAttribute('password'))
404 serverType, serverURI = parseServer()
405 server = None
408 ####################################################################
409 #
410 # Help/usage printing functions
411 #
412 ####################################################################
414 def cmdHelp(cmd):
415 """Print help for a specific subcommand."""
417 for fc in SUBCOMMAND_HELP.keys():
418 if fc[:len(cmd)] == cmd:
419 cmd = fc
420 break
422 try:
423 args, desc = SUBCOMMAND_HELP[cmd]
424 except KeyError:
425 shortHelp()
426 return
428 print 'Usage: xm %s %s' % (cmd, args)
429 print
430 print desc
432 try:
433 # If options help message is defined, print this.
434 for shortopt, longopt, desc in SUBCOMMAND_OPTIONS[cmd]:
435 if shortopt and longopt:
436 optdesc = '%s, %s' % (shortopt, longopt)
437 elif shortopt:
438 optdesc = shortopt
439 elif longopt:
440 optdesc = longopt
442 wrapped_desc = wrap(desc, 43)
443 print ' %-30s %-43s' % (optdesc, wrapped_desc[0])
444 for line in wrapped_desc[1:]:
445 print ' ' * 33 + line
446 print
447 except KeyError:
448 # if the command is an external module, we grab usage help
449 # from the module itself.
450 if cmd in IMPORTED_COMMANDS:
451 try:
452 cmd_module = __import__(cmd, globals(), locals(), 'xen.xm')
453 cmd_usage = getattr(cmd_module, "help", None)
454 if cmd_usage:
455 print cmd_usage()
456 except ImportError:
457 pass
459 def shortHelp():
460 """Print out generic help when xm is called without subcommand."""
462 print USAGE_HELP
463 print 'Common \'xm\' commands:\n'
465 for command in common_commands:
466 try:
467 args, desc = SUBCOMMAND_HELP[command]
468 except KeyError:
469 continue
470 wrapped_desc = wrap(desc, 50)
471 print ' %-20s %-50s' % (command, wrapped_desc[0])
472 for line in wrapped_desc[1:]:
473 print ' ' * 22 + line
475 print
476 print USAGE_FOOTER
477 print 'For a complete list of subcommands run \'xm help\'.'
479 def longHelp():
480 """Print out full help when xm is called with xm --help or xm help"""
482 print USAGE_HELP
483 print 'xm full list of subcommands:\n'
485 for command in all_commands:
486 try:
487 args, desc = SUBCOMMAND_HELP[command]
488 except KeyError:
489 continue
491 wrapped_desc = wrap(desc, 50)
492 print ' %-20s %-50s' % (command, wrapped_desc[0])
493 for line in wrapped_desc[1:]:
494 print ' ' * 22 + line
496 print
497 print USAGE_FOOTER
499 def _usage(cmd):
500 """ Print help usage information """
501 if cmd:
502 cmdHelp(cmd)
503 else:
504 shortHelp()
506 def usage(cmd = None):
507 """ Print help usage information and exits """
508 _usage(cmd)
509 sys.exit(1)
512 ####################################################################
513 #
514 # Utility functions
515 #
516 ####################################################################
518 def get_default_SR():
519 return [sr_ref
520 for sr_ref in server.xenapi.SR.get_all()
521 if server.xenapi.SR.get_type(sr_ref) == "local"][0]
523 def get_default_Network():
524 return [network_ref
525 for network_ref in server.xenapi.network.get_all()][0]
527 class XenAPIUnsupportedException(Exception):
528 pass
530 def xenapi_unsupported():
531 if serverType == SERVER_XEN_API:
532 raise XenAPIUnsupportedException, "This function is not supported by Xen-API"
534 def xenapi_only():
535 if serverType != SERVER_XEN_API:
536 raise XenAPIUnsupportedException, "This function is only supported by Xen-API"
538 def map2sxp(m):
539 return [[k, m[k]] for k in m.keys()]
541 def arg_check(args, name, lo, hi = -1):
542 n = len([i for i in args if i != '--'])
544 if hi == -1:
545 if n != lo:
546 err("'xm %s' requires %d argument%s.\n" % (name, lo,
547 lo == 1 and '' or 's'))
548 usage(name)
549 else:
550 if n < lo or n > hi:
551 err("'xm %s' requires between %d and %d arguments.\n" %
552 (name, lo, hi))
553 usage(name)
556 def unit(c):
557 if not c.isalpha():
558 return 0
559 base = 1
560 if c == 'G' or c == 'g': base = 1024 * 1024 * 1024
561 elif c == 'M' or c == 'm': base = 1024 * 1024
562 elif c == 'K' or c == 'k': base = 1024
563 else:
564 print 'ignoring unknown unit'
565 return base
567 def int_unit(str, dest):
568 base = unit(str[-1])
569 if not base:
570 return int(str)
572 value = int(str[:-1])
573 dst_base = unit(dest)
574 if dst_base == 0:
575 dst_base = 1
576 if dst_base > base:
577 return value / (dst_base / base)
578 else:
579 return value * (base / dst_base)
581 def err(msg):
582 print >>sys.stderr, "Error:", msg
585 def get_single_vm(dom):
586 if serverType == SERVER_XEN_API:
587 uuids = server.xenapi.VM.get_by_name_label(dom)
588 if len(uuids) > 0:
589 return uuids[0]
591 refs = []
593 try:
594 domid = int(dom)
595 refs = [vm_ref
596 for vm_ref in server.xenapi.VM.get_all()
597 if int(server.xenapi.VM.get_domid(vm_ref)) == domid]
598 except:
599 pass
601 if len(refs) > 0:
602 return refs[0]
604 raise OptionError("Domain '%s' not found." % dom)
605 else:
606 dominfo = server.xend.domain(dom, False)
607 return dominfo['uuid']
609 ##
610 #
611 # Xen-API Shell
612 #
613 ##
615 class Shell(cmd.Cmd):
616 def __init__(self):
617 cmd.Cmd.__init__(self)
618 self.prompt = "xm> "
619 if serverType == SERVER_XEN_API:
620 try:
621 res = server.xenapi.host.list_methods()
622 for f in res:
623 setattr(Shell, 'do_' + f + ' ', self.default)
624 except:
625 pass
627 def preloop(self):
628 cmd.Cmd.preloop(self)
629 try:
630 import readline
631 readline.set_completer_delims(' ')
632 except ImportError:
633 pass
635 def default(self, line):
636 words = shlex.split(line)
637 if len(words) > 0 and words[0] == 'xm':
638 words = words[1:]
639 if len(words) > 0:
640 cmd = xm_lookup_cmd(words[0])
641 if cmd:
642 _run_cmd(cmd, words[0], words[1:])
643 elif serverType == SERVER_XEN_API:
644 ok, res = _run_cmd(lambda x: server.xenapi_request(words[0],
645 tuple(x)),
646 words[0], words[1:])
647 if ok and res is not None and res != '':
648 pprint.pprint(res)
649 else:
650 print '*** Unknown command: %s' % words[0]
651 return False
653 def completedefault(self, text, line, begidx, endidx):
654 words = shlex.split(line[:begidx])
655 clas, func = words[0].split('.')
656 if len(words) > 1 or \
657 func.startswith('get_by_') or \
658 func == 'get_all':
659 return []
660 uuids = server.xenapi_request('%s.get_all' % clas, ())
661 return [u + " " for u in uuids if u.startswith(text)]
663 def emptyline(self):
664 pass
666 def do_EOF(self, line):
667 print
668 sys.exit(0)
670 def do_help(self, line):
671 _usage(line)
674 def xm_shell(args):
675 Shell().cmdloop('The Xen Master. Type "help" for a list of functions.')
678 def xm_event_monitor(args):
679 if serverType == SERVER_XEN_API:
680 while True:
681 server.xenapi.event.register(args)
682 events = server.xenapi.event.next()
683 for e in events:
684 print e
685 else:
686 err("Event monitoring not supported unless using Xen-API.")
689 #########################################################################
690 #
691 # Main xm functions
692 #
693 #########################################################################
695 def xm_save(args):
697 arg_check(args, "save", 2, 3)
699 try:
700 (options, params) = getopt.gnu_getopt(args, 'c', ['checkpoint'])
701 except getopt.GetoptError, opterr:
702 err(opterr)
703 sys.exit(1)
705 checkpoint = False
706 for (k, v) in options:
707 if k in ['-c', '--checkpoint']:
708 checkpoint = True
710 if len(params) != 2:
711 err("Wrong number of parameters")
712 usage('save')
714 dom = params[0]
715 savefile = os.path.abspath(params[1])
717 if not os.access(os.path.dirname(savefile), os.W_OK):
718 err("xm save: Unable to create file %s" % savefile)
719 sys.exit(1)
721 if serverType == SERVER_XEN_API:
722 server.xenapi.VM.save(get_single_vm(dom), savefile, checkpoint)
723 else:
724 server.xend.domain.save(dom, savefile, checkpoint)
726 def xm_restore(args):
727 arg_check(args, "restore", 1, 2)
729 try:
730 (options, params) = getopt.gnu_getopt(args, 'p', ['paused'])
731 except getopt.GetoptError, opterr:
732 err(opterr)
733 usage('restore')
735 paused = False
736 for (k, v) in options:
737 if k in ['-p', '--paused']:
738 paused = True
740 if len(params) != 1:
741 err("Wrong number of parameters")
742 usage('restore')
744 savefile = os.path.abspath(params[0])
746 if not os.access(savefile, os.R_OK):
747 err("xm restore: Unable to read file %s" % savefile)
748 sys.exit(1)
750 if serverType == SERVER_XEN_API:
751 server.xenapi.VM.restore(savefile, paused)
752 else:
753 server.xend.domain.restore(savefile, paused)
756 def datetime_to_secs(v):
757 unwanted = ":-."
758 for c in unwanted:
759 v = str(v).replace(c, "")
760 return time.mktime(time.strptime(v[0:14], '%Y%m%dT%H%M%S'))
762 def getDomains(domain_names, state, full = 0):
763 if serverType == SERVER_XEN_API:
764 doms_sxp = []
765 doms_dict = []
767 dom_recs = server.xenapi.VM.get_all_records()
768 dom_metrics_recs = server.xenapi.VM_metrics.get_all_records()
770 for dom_ref, dom_rec in dom_recs.items():
771 dom_metrics_rec = dom_metrics_recs[dom_rec['metrics']]
773 states = ('running', 'blocked', 'paused', 'shutdown',
774 'crashed', 'dying')
775 def state_on_off(state):
776 if state in dom_metrics_rec['state']:
777 return state[0]
778 else:
779 return "-"
780 state_str = "".join([state_on_off(state)
781 for state in states])
783 dom_rec.update({'name': dom_rec['name_label'],
784 'memory_actual': int(dom_metrics_rec['memory_actual'])/1024,
785 'vcpus': dom_metrics_rec['VCPUs_number'],
786 'state': state_str,
787 'cpu_time': dom_metrics_rec['VCPUs_utilisation'],
788 'start_time': datetime_to_secs(
789 dom_metrics_rec['start_time'])})
791 doms_sxp.append(['domain'] + map2sxp(dom_rec))
792 doms_dict.append(dom_rec)
794 if domain_names:
795 doms = [['domain'] + map2sxp(dom) for dom in doms_dict
796 if dom["name"] in domain_names]
798 if len(doms) > 0:
799 return doms
800 else:
801 print "Error: no domain%s named %s" % \
802 (len(domain_names) > 1 and 's' or '',
803 ', '.join(domain_names))
804 sys.exit(-1)
805 else:
806 return doms_sxp
807 else:
808 if domain_names:
809 return [server.xend.domain(dom, full) for dom in domain_names]
810 else:
811 return server.xend.domains_with_state(True, state, full)
814 def xm_list(args):
815 use_long = 0
816 show_vcpus = 0
817 show_labels = 0
818 state = 'all'
819 try:
820 (options, params) = getopt.gnu_getopt(args, 'lv',
821 ['long','vcpus','label',
822 'state='])
823 except getopt.GetoptError, opterr:
824 err(opterr)
825 usage('list')
827 for (k, v) in options:
828 if k in ['-l', '--long']:
829 use_long = 1
830 if k in ['-v', '--vcpus']:
831 show_vcpus = 1
832 if k in ['--label']:
833 show_labels = 1
834 if k in ['--state']:
835 state = v
837 if state != 'all' and len(params) > 0:
838 raise OptionError(
839 "You may specify either a state or a particular VM, but not both")
841 if show_vcpus:
842 print >>sys.stderr, (
843 "xm list -v is deprecated. Please use xm vcpu-list.")
844 xm_vcpu_list(params)
845 return
847 doms = getDomains(params, state, use_long)
849 if use_long:
850 map(PrettyPrint.prettyprint, doms)
851 elif show_labels:
852 xm_label_list(doms)
853 else:
854 xm_brief_list(doms)
857 def parse_doms_info(info):
858 def get_info(n, t, d):
859 return t(sxp.child_value(info, n, d))
861 def get_status(n, t, d):
862 return DOM_STATES[t(sxp.child_value(info, n, d))]
864 start_time = get_info('start_time', float, -1)
865 if start_time == -1:
866 up_time = float(-1)
867 else:
868 up_time = time.time() - start_time
870 parsed_info = {
871 'domid' : get_info('domid', str, ''),
872 'name' : get_info('name', str, '??'),
873 'state' : get_info('state', str, ''),
875 # VCPUs is the number online when the VM is up, or the number
876 # configured otherwise.
877 'vcpus' : get_info('online_vcpus', int,
878 get_info('vcpus', int, 0)),
879 'up_time' : up_time
880 }
882 security_label = get_info('security_label', str, '')
883 parsed_info['seclabel'] = security.parse_security_label(security_label)
885 if serverType == SERVER_XEN_API:
886 parsed_info['mem'] = get_info('memory_actual', int, 0) / 1024
887 cpu_times = get_info('cpu_time', lambda x : (x), 0.0)
888 if sum(cpu_times.values()) > 0:
889 parsed_info['cpu_time'] = sum(cpu_times.values()) / float(len(cpu_times.values()))
890 else:
891 parsed_info['cpu_time'] = 0
892 else:
893 parsed_info['mem'] = get_info('memory', int,0)
894 parsed_info['cpu_time'] = get_info('cpu_time', float, 0.0)
896 return parsed_info
898 def check_sched_type(sched):
899 if serverType == SERVER_XEN_API:
900 current = server.xenapi.host.get_sched_policy(
901 server.xenapi.session.get_this_host(server.getSession()))
902 else:
903 current = 'unknown'
904 for x in server.xend.node.info()[1:]:
905 if len(x) > 1 and x[0] == 'xen_scheduler':
906 current = x[1]
907 break
908 if sched != current:
909 err("Xen is running with the %s scheduler" % current)
910 sys.exit(1)
912 def parse_sedf_info(info):
913 def get_info(n, t, d):
914 return t(sxp.child_value(info, n, d))
916 return {
917 'domid' : get_info('domid', int, -1),
918 'period' : get_info('period', int, -1),
919 'slice' : get_info('slice', int, -1),
920 'latency' : get_info('latency', int, -1),
921 'extratime': get_info('extratime', int, -1),
922 'weight' : get_info('weight', int, -1),
923 }
925 def domid_match(domid, info):
926 return domid is None or domid == info['name'] or \
927 domid == str(info['domid'])
929 def xm_brief_list(doms):
930 print '%-40s %5s %5s %5s %10s %9s' % \
931 ('Name', 'ID', 'Mem', 'VCPUs', 'State', 'Time(s)')
933 format = "%(name)-40s %(domid)5s %(mem)5d %(vcpus)5d %(state)10s " \
934 "%(cpu_time)8.1f"
936 for dom in doms:
937 d = parse_doms_info(dom)
938 print format % d
940 def xm_label_list(doms):
941 print '%-40s %5s %5s %5s %10s %9s %-10s' % \
942 ('Name', 'ID', 'Mem', 'VCPUs', 'State', 'Time(s)', 'Label')
944 output = []
945 format = '%(name)-40s %(domid)5s %(mem)5d %(vcpus)5d %(state)10s ' \
946 '%(cpu_time)8.1f %(seclabel)10s'
948 for dom in doms:
949 d = parse_doms_info(dom)
950 if d['seclabel'] == "" and serverType != SERVER_XEN_API:
951 seclab = server.xend.security.get_domain_label(d['name'])
952 if len(seclab) > 0 and seclab[0] == '\'':
953 seclab = seclab[1:]
954 d['seclabel'] = seclab
955 output.append((format % d, d['seclabel']))
957 #sort by labels
958 output.sort(lambda x,y: cmp( x[1].lower(), y[1].lower()))
959 for line, label in output:
960 print line
963 def xm_vcpu_list(args):
964 if serverType == SERVER_XEN_API:
965 if args:
966 vm_refs = map(get_single_vm, args)
967 else:
968 vm_refs = server.xenapi.VM.get_all()
970 vm_records = dict(map(lambda vm_ref:
971 (vm_ref, server.xenapi.VM.get_record(
972 vm_ref)),
973 vm_refs))
975 vm_metrics = dict(map(lambda (ref, record):
976 (ref,
977 server.xenapi.VM_metrics.get_record(
978 record['metrics'])),
979 vm_records.items()))
981 dominfo = []
983 # vcpu_list doesn't list 'managed' domains
984 # when they are not running, so filter them out
986 vm_refs = [vm_ref
987 for vm_ref in vm_refs
988 if vm_records[vm_ref]["power_state"] != "Halted"]
990 for vm_ref in vm_refs:
991 info = ['domain',
992 ['domid', vm_records[vm_ref]['domid']],
993 ['name', vm_records[vm_ref]['name_label']],
994 ['vcpu_count', vm_records[vm_ref]['VCPUs_max']]]
996 for i in range(int(vm_records[vm_ref]['VCPUs_max'])):
997 def chk_flag(flag):
998 return flag in vm_metrics[vm_ref]['VCPUs_flags'][str(i)] \
999 and 1 or 0
1001 vcpu_info = ['vcpu',
1002 ['number',
1003 i],
1004 ['online',
1005 chk_flag("online")],
1006 ['blocked',
1007 chk_flag("blocked")],
1008 ['running',
1009 chk_flag("running")],
1010 ['cpu_time',
1011 vm_metrics[vm_ref]['VCPUs_utilisation'][str(i)]],
1012 ['cpu',
1013 vm_metrics[vm_ref]['VCPUs_CPU'][str(i)]],
1014 ['cpumap',
1015 vm_metrics[vm_ref]['VCPUs_params']\
1016 ['cpumap%i' % i].split(",")]]
1018 info.append(vcpu_info)
1020 dominfo.append(info)
1021 else:
1022 if args:
1023 dominfo = map(server.xend.domain.getVCPUInfo, args)
1024 else:
1025 doms = server.xend.domains_with_state(False, 'all', False)
1026 dominfo = map(server.xend.domain.getVCPUInfo, doms)
1028 print '%-32s %5s %5s %5s %5s %9s %s' % \
1029 ('Name', 'ID', 'VCPU', 'CPU', 'State', 'Time(s)', 'CPU Affinity')
1031 format = '%(name)-32s %(domid)5s %(number)5d %(c)5s %(s)5s ' \
1032 ' %(cpu_time)8.1f %(cpumap)s'
1034 for dom in dominfo:
1035 def get_info(n):
1036 return sxp.child_value(dom, n)
1039 # convert a list of integers into a list of pairs indicating
1040 # continuous sequences in the list:
1042 # [0,1,2,3] -> [(0,3)]
1043 # [1,2,4,5] -> [(1,2),(4,5)]
1044 # [0] -> [(0,0)]
1045 # [0,1,4,6,7] -> [(0,1),(4,4),(6,7)]
1047 def list_to_rangepairs(cmap):
1048 cmap.sort()
1049 pairs = []
1050 x = y = 0
1051 for i in range(0,len(cmap)):
1052 try:
1053 if ((cmap[y+1] - cmap[i]) > 1):
1054 pairs.append((cmap[x],cmap[y]))
1055 x = y = i+1
1056 else:
1057 y = y + 1
1058 # if we go off the end, then just add x to y
1059 except IndexError:
1060 pairs.append((cmap[x],cmap[y]))
1062 return pairs
1065 # Convert pairs to range string, e.g: [(1,2),(3,3),(5,7)] -> 1-2,3,5-7
1067 def format_pairs(pairs):
1068 if not pairs:
1069 return "no cpus"
1070 out = ""
1071 for f,s in pairs:
1072 if (f==s):
1073 out += '%d'%f
1074 else:
1075 out += '%d-%d'%(f,s)
1076 out += ','
1077 # trim trailing ','
1078 return out[:-1]
1080 def format_cpumap(cpumap):
1081 cpumap = map(lambda x: int(x), cpumap)
1082 cpumap.sort()
1084 if serverType == SERVER_XEN_API:
1085 nr_cpus = len(server.xenapi.host.get_host_CPUs(
1086 server.xenapi.session.get_this_host(server.getSession())))
1087 else:
1088 for x in server.xend.node.info()[1:]:
1089 if len(x) > 1 and x[0] == 'nr_cpus':
1090 nr_cpus = int(x[1])
1092 # normalize cpumap by modulus nr_cpus, and drop duplicates
1093 cpumap = dict.fromkeys(
1094 map(lambda x: x % nr_cpus, cpumap)).keys()
1095 if len(cpumap) == nr_cpus:
1096 return "any cpu"
1098 return format_pairs(list_to_rangepairs(cpumap))
1100 name = get_info('name')
1101 domid = get_info('domid')
1102 if domid is not None:
1103 domid = str(domid)
1104 else:
1105 domid = ''
1107 for vcpu in sxp.children(dom, 'vcpu'):
1108 def vinfo(n, t):
1109 return t(sxp.child_value(vcpu, n))
1111 number = vinfo('number', int)
1112 cpu = vinfo('cpu', int)
1113 cpumap = format_cpumap(vinfo('cpumap', list))
1114 online = vinfo('online', int)
1115 cpu_time = vinfo('cpu_time', float)
1116 running = vinfo('running', int)
1117 blocked = vinfo('blocked', int)
1119 if cpu < 0:
1120 c = ''
1121 s = ''
1122 elif online:
1123 c = str(cpu)
1124 if running:
1125 s = 'r'
1126 else:
1127 s = '-'
1128 if blocked:
1129 s += 'b'
1130 else:
1131 s += '-'
1132 s += '-'
1133 else:
1134 c = '-'
1135 s = '--p'
1137 print format % locals()
1139 def start_do_console(domain_name):
1140 cpid = os.fork()
1141 if cpid != 0:
1142 for i in range(10):
1143 # Catch failure of the create process
1144 time.sleep(1)
1145 (p, rv) = os.waitpid(cpid, os.WNOHANG)
1146 if os.WIFEXITED(rv):
1147 if os.WEXITSTATUS(rv) != 0:
1148 sys.exit(os.WEXITSTATUS(rv))
1149 try:
1150 # Acquire the console of the created dom
1151 if serverType == SERVER_XEN_API:
1152 domid = server.xenapi.VM.get_domid(
1153 get_single_vm(domain_name))
1154 else:
1155 dom = server.xend.domain(domain_name)
1156 domid = int(sxp.child_value(dom, 'domid', '-1'))
1157 console.execConsole(domid)
1158 except:
1159 pass
1160 print("Could not start console\n");
1161 sys.exit(0)
1163 def xm_start(args):
1165 paused = False
1166 console_autoconnect = False
1168 try:
1169 (options, params) = getopt.gnu_getopt(args, 'cp', ['console_autoconnect','paused'])
1170 for (k, v) in options:
1171 if k in ('-p', '--paused'):
1172 paused = True
1173 if k in ('-c', '--console_autoconnect'):
1174 console_autoconnect = True
1176 if len(params) != 1:
1177 raise OptionError("Expects 1 argument")
1178 except getopt.GetoptError, opterr:
1179 err(opterr)
1180 usage('start')
1182 dom = params[0]
1184 if console_autoconnect:
1185 start_do_console(dom)
1187 try:
1188 if serverType == SERVER_XEN_API:
1189 server.xenapi.VM.start(get_single_vm(dom), paused)
1190 domid = int(server.xenapi.VM.get_domid(get_single_vm(dom)))
1191 else:
1192 server.xend.domain.start(dom, paused)
1193 info = server.xend.domain(dom)
1194 domid = int(sxp.child_value(info, 'domid', '-1'))
1195 except:
1196 raise
1198 if domid == -1:
1199 raise xmlrpclib.Fault(0, "Domain '%s' is not started" % dom)
1201 def xm_delete(args):
1202 arg_check(args, "delete", 1)
1203 dom = args[0]
1204 if serverType == SERVER_XEN_API:
1205 server.xenapi.VM.destroy(get_single_vm(dom))
1206 else:
1207 server.xend.domain.delete(dom)
1209 def xm_suspend(args):
1210 arg_check(args, "suspend", 1)
1211 dom = args[0]
1212 if serverType == SERVER_XEN_API:
1213 server.xenapi.VM.suspend(get_single_vm(dom))
1214 else:
1215 server.xend.domain.suspend(dom)
1217 def xm_resume(args):
1218 arg_check(args, "resume", 1, 2)
1220 try:
1221 (options, params) = getopt.gnu_getopt(args, 'p', ['paused'])
1222 except getopt.GetoptError, opterr:
1223 err(opterr)
1224 usage('resume')
1226 paused = False
1227 for (k, v) in options:
1228 if k in ['-p', '--paused']:
1229 paused = True
1231 if len(params) != 1:
1232 err("Wrong number of parameters")
1233 usage('resume')
1235 dom = params[0]
1236 if serverType == SERVER_XEN_API:
1237 server.xenapi.VM.resume(get_single_vm(dom), paused)
1238 else:
1239 server.xend.domain.resume(dom, paused)
1241 def xm_reboot(args):
1242 arg_check(args, "reboot", 1, 3)
1243 from xen.xm import shutdown
1244 shutdown.main(["shutdown", "-R"] + args)
1246 def xm_shutdown(args):
1247 arg_check(args, "shutdown", 1, 4)
1248 from xen.xm import shutdown
1249 shutdown.main(["shutdown"] + args)
1251 def xm_pause(args):
1252 arg_check(args, "pause", 1)
1253 dom = args[0]
1255 if serverType == SERVER_XEN_API:
1256 server.xenapi.VM.pause(get_single_vm(dom))
1257 else:
1258 server.xend.domain.pause(dom)
1260 def xm_unpause(args):
1261 arg_check(args, "unpause", 1)
1262 dom = args[0]
1264 if serverType == SERVER_XEN_API:
1265 server.xenapi.VM.unpause(get_single_vm(dom))
1266 else:
1267 server.xend.domain.unpause(dom)
1269 def xm_dump_core(args):
1270 live = False
1271 crash = False
1272 try:
1273 (options, params) = getopt.gnu_getopt(args, 'LC', ['live','crash'])
1274 for (k, v) in options:
1275 if k in ('-L', '--live'):
1276 live = True
1277 if k in ('-C', '--crash'):
1278 crash = True
1280 if len(params) not in (1, 2):
1281 raise OptionError("Expects 1 or 2 argument(s)")
1282 except getopt.GetoptError, e:
1283 raise OptionError(str(e))
1285 dom = params[0]
1286 if len(params) == 2:
1287 filename = os.path.abspath(params[1])
1288 else:
1289 filename = None
1291 if not live:
1292 ds = server.xend.domain.pause(dom, True)
1294 try:
1295 print "Dumping core of domain: %s ..." % str(dom)
1296 server.xend.domain.dump(dom, filename, live, crash)
1297 finally:
1298 if not live and ds == DOM_STATE_RUNNING:
1299 server.xend.domain.unpause(dom)
1301 if crash:
1302 print "Destroying domain: %s ..." % str(dom)
1303 server.xend.domain.destroy(dom)
1305 def xm_rename(args):
1306 arg_check(args, "rename", 2)
1308 if serverType == SERVER_XEN_API:
1309 server.xenapi.VM.set_name_label(get_single_vm(args[0]), args[1])
1310 else:
1311 server.xend.domain.setName(args[0], args[1])
1313 def xm_importcommand(command, args):
1314 cmd = __import__(command, globals(), locals(), 'xen.xm')
1315 cmd.main([command] + args)
1318 #############################################################
1320 def xm_vcpu_pin(args):
1321 arg_check(args, "vcpu-pin", 3)
1323 def cpu_make_map(cpulist):
1324 cpus = []
1325 for c in cpulist.split(','):
1326 if c.find('-') != -1:
1327 (x,y) = c.split('-')
1328 for i in range(int(x),int(y)+1):
1329 cpus.append(int(i))
1330 else:
1331 # remove this element from the list
1332 if c[0] == '^':
1333 cpus = [x for x in cpus if x != int(c[1:])]
1334 else:
1335 cpus.append(int(c))
1336 cpus.sort()
1337 return cpus
1339 dom = args[0]
1340 vcpu = args[1]
1341 if args[2] == 'all':
1342 cpumap = cpu_make_map('0-63')
1343 else:
1344 cpumap = cpu_make_map(args[2])
1346 if serverType == SERVER_XEN_API:
1347 cpumap = map(str, cpumap)
1348 server.xenapi.VM.add_to_VCPUs_params_live(
1349 get_single_vm(dom), "cpumap%i" % int(vcpu), ",".join(cpumap))
1350 else:
1351 server.xend.domain.pincpu(dom, vcpu, cpumap)
1353 def xm_mem_max(args):
1354 arg_check(args, "mem-max", 2)
1356 dom = args[0]
1358 if serverType == SERVER_XEN_API:
1359 mem = int_unit(args[1], 'k') * 1024
1360 server.xenapi.VM.set_memory_static_max(get_single_vm(dom), mem)
1361 else:
1362 mem = int_unit(args[1], 'm')
1363 server.xend.domain.maxmem_set(dom, mem)
1365 def xm_mem_set(args):
1366 arg_check(args, "mem-set", 2)
1368 dom = args[0]
1370 if serverType == SERVER_XEN_API:
1371 mem_target = int_unit(args[1], 'm') * 1024 * 1024
1372 server.xenapi.VM.set_memory_dynamic_max_live(get_single_vm(dom),
1373 mem_target)
1374 server.xenapi.VM.set_memory_dynamic_min_live(get_single_vm(dom),
1375 mem_target)
1376 else:
1377 mem_target = int_unit(args[1], 'm')
1378 server.xend.domain.setMemoryTarget(dom, mem_target)
1380 def xm_vcpu_set(args):
1381 arg_check(args, "vcpu-set", 2)
1383 dom = args[0]
1384 vcpus = int(args[1])
1386 if serverType == SERVER_XEN_API:
1387 server.xenapi.VM.set_VCPUs_number_live(get_single_vm(dom), vcpus)
1388 else:
1389 server.xend.domain.setVCpuCount(dom, vcpus)
1391 def xm_destroy(args):
1392 arg_check(args, "destroy", 1)
1394 dom = args[0]
1396 if serverType == SERVER_XEN_API:
1397 server.xenapi.VM.hard_shutdown(get_single_vm(dom))
1398 else:
1399 server.xend.domain.destroy(dom)
1401 def xm_domid(args):
1402 arg_check(args, "domid", 1)
1404 name = args[0]
1406 if serverType == SERVER_XEN_API:
1407 print server.xenapi.VM.get_domid(get_single_vm(name))
1408 else:
1409 dom = server.xend.domain(name)
1410 print sxp.child_value(dom, 'domid')
1412 def xm_domname(args):
1413 arg_check(args, "domname", 1)
1415 name = args[0]
1417 if serverType == SERVER_XEN_API:
1418 print server.xenapi.VM.get_name_label(get_single_vm(name))
1419 else:
1420 dom = server.xend.domain(name)
1421 print sxp.child_value(dom, 'name')
1423 def xm_sched_sedf(args):
1424 xenapi_unsupported()
1426 def ns_to_ms(val):
1427 return float(val) * 0.000001
1429 def ms_to_ns(val):
1430 return (float(val) / 0.000001)
1432 def print_sedf(info):
1433 info['period'] = ns_to_ms(info['period'])
1434 info['slice'] = ns_to_ms(info['slice'])
1435 info['latency'] = ns_to_ms(info['latency'])
1436 print( ("%(name)-32s %(domid)5d %(period)9.1f %(slice)9.1f" +
1437 " %(latency)7.1f %(extratime)6d %(weight)6d") % info)
1439 check_sched_type('sedf')
1441 # we want to just display current info if no parameters are passed
1442 if len(args) == 0:
1443 domid = None
1444 else:
1445 # we expect at least a domain id (name or number)
1446 # and at most a domid up to 5 options with values
1447 arg_check(args, "sched-sedf", 1, 11)
1448 domid = args[0]
1449 # drop domid from args since get_opt doesn't recognize it
1450 args = args[1:]
1452 opts = {}
1453 try:
1454 (options, params) = getopt.gnu_getopt(args, 'p:s:l:e:w:',
1455 ['period=', 'slice=', 'latency=', 'extratime=', 'weight='])
1456 except getopt.GetoptError, opterr:
1457 err(opterr)
1458 usage('sched-sedf')
1460 # convert to nanoseconds if needed
1461 for (k, v) in options:
1462 if k in ['-p', '--period']:
1463 opts['period'] = ms_to_ns(v)
1464 elif k in ['-s', '--slice']:
1465 opts['slice'] = ms_to_ns(v)
1466 elif k in ['-l', '--latency']:
1467 opts['latency'] = ms_to_ns(v)
1468 elif k in ['-e', '--extratime']:
1469 opts['extratime'] = v
1470 elif k in ['-w', '--weight']:
1471 opts['weight'] = v
1473 doms = filter(lambda x : domid_match(domid, x),
1474 [parse_doms_info(dom)
1475 for dom in getDomains(None, 'running')])
1476 if domid is not None and doms == []:
1477 err("Domain '%s' does not exist." % domid)
1478 usage('sched-sedf')
1480 # print header if we aren't setting any parameters
1481 if len(opts.keys()) == 0:
1482 print '%-33s %4s %-4s %-4s %-7s %-5s %-6s' % \
1483 ('Name','ID','Period(ms)', 'Slice(ms)', 'Lat(ms)',
1484 'Extra','Weight')
1486 for d in doms:
1487 # fetch current values so as not to clobber them
1488 try:
1489 sedf_raw = server.xend.domain.cpu_sedf_get(d['domid'])
1490 except xmlrpclib.Fault:
1491 # domain does not support sched-sedf?
1492 sedf_raw = {}
1494 sedf_info = parse_sedf_info(sedf_raw)
1495 sedf_info['name'] = d['name']
1496 # update values in case of call to set
1497 if len(opts.keys()) > 0:
1498 for k in opts.keys():
1499 sedf_info[k]=opts[k]
1501 # send the update, converting user input
1502 v = map(int, [sedf_info['period'], sedf_info['slice'],
1503 sedf_info['latency'],sedf_info['extratime'],
1504 sedf_info['weight']])
1505 rv = server.xend.domain.cpu_sedf_set(d['domid'], *v)
1506 if int(rv) != 0:
1507 err("Failed to set sedf parameters (rv=%d)."%(rv))
1509 # not setting values, display info
1510 else:
1511 print_sedf(sedf_info)
1513 def xm_sched_credit(args):
1514 """Get/Set options for Credit Scheduler."""
1516 check_sched_type('credit')
1518 try:
1519 opts, params = getopt.getopt(args, "d:w:c:",
1520 ["domain=", "weight=", "cap="])
1521 except getopt.GetoptError, opterr:
1522 err(opterr)
1523 usage('sched-credit')
1525 domid = None
1526 weight = None
1527 cap = None
1529 for o, a in opts:
1530 if o in ["-d", "--domain"]:
1531 domid = a
1532 elif o in ["-w", "--weight"]:
1533 weight = int(a)
1534 elif o in ["-c", "--cap"]:
1535 cap = int(a);
1537 doms = filter(lambda x : domid_match(domid, x),
1538 [parse_doms_info(dom)
1539 for dom in getDomains(None, 'all')])
1541 if weight is None and cap is None:
1542 if domid is not None and doms == []:
1543 err("Domain '%s' does not exist." % domid)
1544 usage('sched-credit')
1545 # print header if we aren't setting any parameters
1546 print '%-33s %4s %6s %4s' % ('Name','ID','Weight','Cap')
1548 for d in doms:
1549 try:
1550 if serverType == SERVER_XEN_API:
1551 info = server.xenapi.VM_metrics.get_VCPUs_params(
1552 server.xenapi.VM.get_metrics(
1553 get_single_vm(d['name'])))
1554 else:
1555 info = server.xend.domain.sched_credit_get(d['name'])
1556 except xmlrpclib.Fault:
1557 pass
1559 if 'weight' not in info or 'cap' not in info:
1560 # domain does not support sched-credit?
1561 info = {'weight': -1, 'cap': -1}
1563 info['weight'] = int(info['weight'])
1564 info['cap'] = int(info['cap'])
1566 info['name'] = d['name']
1567 info['domid'] = str(d['domid'])
1568 print( ("%(name)-32s %(domid)5s %(weight)6d %(cap)4d") % info)
1569 else:
1570 if domid is None:
1571 # place holder for system-wide scheduler parameters
1572 err("No domain given.")
1573 usage('sched-credit')
1575 if serverType == SERVER_XEN_API:
1576 if doms[0]['domid']:
1577 server.xenapi.VM.add_to_VCPUs_params_live(
1578 get_single_vm(domid),
1579 "weight",
1580 weight)
1581 server.xenapi.VM.add_to_VCPUs_params_live(
1582 get_single_vm(domid),
1583 "cap",
1584 cap)
1585 else:
1586 server.xenapi.VM.add_to_VCPUs_params(
1587 get_single_vm(domid),
1588 "weight",
1589 weight)
1590 server.xenapi.VM.add_to_VCPUs_params(
1591 get_single_vm(domid),
1592 "cap",
1593 cap)
1594 else:
1595 result = server.xend.domain.sched_credit_set(domid, weight, cap)
1596 if result != 0:
1597 err(str(result))
1599 def xm_info(args):
1600 arg_check(args, "info", 0, 1)
1602 try:
1603 (options, params) = getopt.gnu_getopt(args, 'c', ['config'])
1604 except getopt.GetoptError, opterr:
1605 err(opterr)
1606 usage('info')
1608 show_xend_config = 0
1609 for (k, v) in options:
1610 if k in ['-c', '--config']:
1611 show_xend_config = 1
1613 if show_xend_config:
1614 for name, obj in inspect.getmembers(xoptions):
1615 if not inspect.ismethod(obj):
1616 if name == "config":
1617 for x in obj[1:]:
1618 if len(x) < 2:
1619 print "%-38s: (none)" % x[0]
1620 else:
1621 print "%-38s:" % x[0], x[1]
1622 else:
1623 print "%-38s:" % name, obj
1624 return
1626 if serverType == SERVER_XEN_API:
1628 # Need to fake out old style xm info as people rely on parsing it
1630 host_record = server.xenapi.host.get_record(
1631 server.xenapi.session.get_this_host(server.getSession()))
1633 host_cpu_records = map(server.xenapi.host_cpu.get_record, host_record["host_CPUs"])
1635 host_metrics_record = server.xenapi.host_metrics.get_record(host_record["metrics"])
1637 def getVal(keys, default=""):
1638 data = host_record
1639 for key in keys:
1640 if key in data:
1641 data = data[key]
1642 else:
1643 return default
1644 return data
1646 def getCpuMhz():
1647 cpu_speeds = [int(host_cpu_record["speed"])
1648 for host_cpu_record in host_cpu_records
1649 if "speed" in host_cpu_record]
1650 if len(cpu_speeds) > 0:
1651 return sum(cpu_speeds) / len(cpu_speeds)
1652 else:
1653 return 0
1655 getCpuMhz()
1657 def getCpuFeatures():
1658 if len(host_cpu_records) > 0:
1659 return host_cpu_records[0].get("features", "")
1660 else:
1661 return ""
1663 info = {
1664 "host": getVal(["name_label"]),
1665 "release": getVal(["software_version", "release"]),
1666 "version": getVal(["software_version", "version"]),
1667 "machine": getVal(["software_version", "machine"]),
1668 "nr_cpus": getVal(["cpu_configuration", "nr_cpus"]),
1669 "nr_nodes": getVal(["cpu_configuration", "nr_nodes"]),
1670 "cores_per_socket": getVal(["cpu_configuration", "cores_per_socket"]),
1671 "threads_per_core": getVal(["cpu_configuration", "threads_per_core"]),
1672 "cpu_mhz": getCpuMhz(),
1673 "hw_caps": getCpuFeatures(),
1674 "total_memory": int(host_metrics_record["memory_total"])/1024/1024,
1675 "free_memory": int(host_metrics_record["memory_free"])/1024/1024,
1676 "xen_major": getVal(["software_version", "xen_major"]),
1677 "xen_minor": getVal(["software_version", "xen_minor"]),
1678 "xen_extra": getVal(["software_version", "xen_extra"]),
1679 "xen_caps": " ".join(getVal(["capabilities"], [])),
1680 "xen_scheduler": getVal(["sched_policy"]),
1681 "xen_pagesize": getVal(["other_config", "xen_pagesize"]),
1682 "platform_params": getVal(["other_config", "platform_params"]),
1683 "xen_changeset": getVal(["software_version", "xen_changeset"]),
1684 "cc_compiler": getVal(["software_version", "cc_compiler"]),
1685 "cc_compile_by": getVal(["software_version", "cc_compile_by"]),
1686 "cc_compile_domain": getVal(["software_version", "cc_compile_domain"]),
1687 "cc_compile_date": getVal(["software_version", "cc_compile_date"]),
1688 "xend_config_format":getVal(["software_version", "xend_config_format"])
1691 sorted = info.items()
1692 sorted.sort(lambda (x1,y1), (x2,y2): -cmp(x1,x2))
1694 for (k, v) in sorted:
1695 print "%-23s:" % k, v
1696 else:
1697 info = server.xend.node.info()
1698 for x in info[1:]:
1699 if len(x) < 2:
1700 print "%-23s: (none)" % x[0]
1701 else:
1702 print "%-23s:" % x[0], x[1]
1704 def xm_console(args):
1705 arg_check(args, "console", 1, 2)
1707 quiet = False;
1709 try:
1710 (options, params) = getopt.gnu_getopt(args, 'q', ['quiet'])
1711 except getopt.GetoptError, opterr:
1712 err(opterr)
1713 usage('console')
1715 for (k, v) in options:
1716 if k in ['-q', '--quiet']:
1717 quiet = True
1718 else:
1719 assert False
1721 if len(params) != 1:
1722 err('No domain given')
1723 usage('console')
1725 dom = params[0]
1727 try:
1728 if serverType == SERVER_XEN_API:
1729 domid = int(server.xenapi.VM.get_domid(get_single_vm(dom)))
1730 else:
1731 info = server.xend.domain(dom)
1732 domid = int(sxp.child_value(info, 'domid', '-1'))
1733 except:
1734 if quiet:
1735 sys.exit(1)
1736 else:
1737 raise
1739 if domid == -1:
1740 if quiet:
1741 sys.exit(1)
1742 else:
1743 raise xmlrpclib.Fault(0, "Domain '%s' is not started" % dom)
1745 console.execConsole(domid)
1748 def xm_uptime(args):
1749 short_mode = 0
1751 try:
1752 (options, params) = getopt.gnu_getopt(args, 's', ['short'])
1753 except getopt.GetoptError, opterr:
1754 err(opterr)
1755 usage('uptime')
1757 for (k, v) in options:
1758 if k in ['-s', '--short']:
1759 short_mode = 1
1761 doms = getDomains(params, 'all')
1763 if short_mode == 0:
1764 print '%-33s %4s %s ' % ('Name','ID','Uptime')
1766 for dom in doms:
1767 d = parse_doms_info(dom)
1768 if d['domid'] == '':
1769 uptime = 0
1770 elif int(d['domid']) > 0:
1771 uptime = int(round(d['up_time']))
1772 else:
1773 f=open('/proc/uptime', 'r')
1774 upfile = f.read()
1775 uptime = int(round(float(upfile.split(' ')[0])))
1776 f.close()
1778 days = int(uptime / 86400)
1779 uptime -= (days * 86400)
1780 hours = int(uptime / 3600)
1781 uptime -= (hours * 3600)
1782 minutes = int(uptime / 60)
1783 uptime -= (minutes * 60)
1784 seconds = uptime
1786 upstring = ""
1787 if days > 0:
1788 upstring += str(days) + " day"
1789 if days > 1:
1790 upstring += "s"
1791 upstring += ", "
1792 upstring += '%(hours)2d:%(minutes)02d' % vars()
1794 if short_mode:
1795 now = datetime.datetime.now()
1796 upstring = now.strftime(" %H:%M:%S") + " up " + upstring
1797 upstring += ", " + d['name'] + " (" + d['domid'] + ")"
1798 else:
1799 upstring += ':%(seconds)02d' % vars()
1800 upstring = ("%(name)-32s %(domid)5s " % d) + upstring
1802 print upstring
1804 def xm_sysrq(args):
1805 arg_check(args, "sysrq", 2)
1806 dom = args[0]
1807 req = args[1]
1808 if serverType == SERVER_XEN_API:
1809 server.xenapi.VM.send_sysrq(get_single_vm(dom), req)
1810 else:
1811 server.xend.domain.send_sysrq(dom, req)
1813 def xm_trigger(args):
1814 vcpu = 0
1816 arg_check(args, "trigger", 2, 3)
1817 dom = args[0]
1818 trigger = args[1]
1819 if len(args) == 3:
1820 vcpu = int(args[2])
1822 if serverType == SERVER_XEN_API:
1823 server.xenapi.VM.send_trigger(get_single_vm(dom), trigger, vcpu)
1824 else:
1825 server.xend.domain.send_trigger(dom, trigger, vcpu)
1827 def xm_debug_keys(args):
1828 arg_check(args, "debug-keys", 1)
1830 keys = str(args[0])
1832 if serverType == SERVER_XEN_API:
1833 server.xenapi.host.send_debug_keys(
1834 server.xenapi.session.get_this_host(server.getSession()),
1835 keys)
1836 else:
1837 server.xend.node.send_debug_keys(keys)
1839 def xm_top(args):
1840 arg_check(args, "top", 0)
1842 os.system('xentop')
1844 def xm_dmesg(args):
1845 arg_check(args, "dmesg", 0, 1)
1847 try:
1848 (options, params) = getopt.gnu_getopt(args, 'c', ['clear'])
1849 except getopt.GetoptError, opterr:
1850 err(opterr)
1851 usage('dmesg')
1853 use_clear = 0
1854 for (k, v) in options:
1855 if k in ['-c', '--clear']:
1856 use_clear = 1
1858 if len(params) :
1859 err("No parameter required")
1860 usage('dmesg')
1862 if serverType == SERVER_XEN_API:
1863 host = server.xenapi.session.get_this_host(server.getSession())
1864 if use_clear:
1865 print server.xenapi.host.dmesg_clear(host),
1866 else:
1867 print server.xenapi.host.dmesg(host),
1868 else:
1869 if not use_clear:
1870 print server.xend.node.dmesg.info(),
1871 else:
1872 print server.xend.node.dmesg.clear(),
1874 def xm_log(args):
1875 arg_check(args, "log", 0)
1877 if serverType == SERVER_XEN_API:
1878 print server.xenapi.host.get_log(
1879 server.xenapi.session.get_this_host(server.getSession()))
1880 else:
1881 print server.xend.node.log()
1883 def xm_serve(args):
1884 if serverType == SERVER_XEN_API:
1885 print "Not supported with XenAPI"
1886 sys.exit(-1)
1888 arg_check(args, "serve", 0)
1890 from fcntl import fcntl, F_SETFL
1892 s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
1893 s.connect(XendClient.XML_RPC_SOCKET)
1894 fcntl(sys.stdin, F_SETFL, os.O_NONBLOCK)
1896 while True:
1897 iwtd, owtd, ewtd = select([sys.stdin, s], [], [])
1898 if s in iwtd:
1899 data = s.recv(4096)
1900 if len(data) > 0:
1901 sys.stdout.write(data)
1902 sys.stdout.flush()
1903 else:
1904 break
1905 if sys.stdin in iwtd:
1906 data = sys.stdin.read(4096)
1907 if len(data) > 0:
1908 s.sendall(data)
1909 else:
1910 break
1911 s.close()
1913 def parse_dev_info(info):
1914 def get_info(n, t, d):
1915 i = 0
1916 while i < len(info):
1917 if (info[i][0] == n):
1918 return t(info[i][1])
1919 i = i + 1
1920 return t(d)
1921 return {
1922 #common
1923 'backend-id' : get_info('backend-id', int, -1),
1924 'handle' : get_info('handle', int, 0),
1925 'state' : get_info('state', int, -1),
1926 'be-path' : get_info('backend', str, '??'),
1927 'event-ch' : get_info('event-channel',int, -1),
1928 #network specific
1929 'virtual-device' : get_info('virtual-device', str, '??'),
1930 'tx-ring-ref': get_info('tx-ring-ref', int, -1),
1931 'rx-ring-ref': get_info('rx-ring-ref', int, -1),
1932 'mac' : get_info('mac', str, '??'),
1933 #block-device specific
1934 'ring-ref' : get_info('ring-ref', int, -1),
1937 def arg_check_for_resource_list(args, name):
1938 use_long = 0
1939 try:
1940 (options, params) = getopt.gnu_getopt(args, 'l', ['long'])
1941 except getopt.GetoptError, opterr:
1942 err(opterr)
1943 sys.exit(1)
1945 for (k, v) in options:
1946 if k in ['-l', '--long']:
1947 use_long = 1
1949 if len(params) == 0:
1950 print 'No domain parameter given'
1951 usage(name)
1952 if len(params) > 1:
1953 print 'No multiple domain parameters allowed'
1954 usage(name)
1956 return (use_long, params)
1958 def xm_network_list(args):
1959 (use_long, params) = arg_check_for_resource_list(args, "network-list")
1961 dom = params[0]
1963 if serverType == SERVER_XEN_API:
1964 vif_refs = server.xenapi.VM.get_VIFs(get_single_vm(dom))
1965 vif_properties = \
1966 map(server.xenapi.VIF.get_runtime_properties, vif_refs)
1967 devs = map(lambda (handle, properties): [handle, map2sxp(properties)],
1968 zip(range(len(vif_properties)), vif_properties))
1969 else:
1970 devs = server.xend.domain.getDeviceSxprs(dom, 'vif')
1972 if use_long:
1973 map(PrettyPrint.prettyprint, devs)
1974 else:
1975 hdr = 0
1976 for x in devs:
1977 if hdr == 0:
1978 print 'Idx BE MAC Addr. handle state evt-ch tx-/rx-ring-ref BE-path'
1979 hdr = 1
1980 ni = parse_dev_info(x[1])
1981 ni['idx'] = int(x[0])
1982 print ("%(idx)-3d "
1983 "%(backend-id)-3d"
1984 "%(mac)-17s "
1985 "%(handle)-3d "
1986 "%(state)-3d "
1987 "%(event-ch)-3d "
1988 "%(tx-ring-ref)-5d/%(rx-ring-ref)-5d "
1989 "%(be-path)-30s "
1990 % ni)
1992 def xm_block_list(args):
1993 (use_long, params) = arg_check_for_resource_list(args, "block-list")
1995 dom = params[0]
1997 if serverType == SERVER_XEN_API:
1998 vbd_refs = server.xenapi.VM.get_VBDs(get_single_vm(dom))
1999 vbd_properties = \
2000 map(server.xenapi.VBD.get_runtime_properties, vbd_refs)
2001 vbd_devs = \
2002 map(server.xenapi.VBD.get_device, vbd_refs)
2003 vbd_devids = \
2004 map(blkdev_name_to_number, vbd_devs)
2005 devs = map(lambda (devid, prop): [devid, map2sxp(prop)],
2006 zip(vbd_devids, vbd_properties))
2007 else:
2008 devs = server.xend.domain.getDeviceSxprs(dom, 'vbd')
2010 if use_long:
2011 map(PrettyPrint.prettyprint, devs)
2012 else:
2013 hdr = 0
2014 for x in devs:
2015 if hdr == 0:
2016 print 'Vdev BE handle state evt-ch ring-ref BE-path'
2017 hdr = 1
2018 ni = parse_dev_info(x[1])
2019 ni['idx'] = int(x[0])
2020 print ("%(idx)-3d "
2021 "%(backend-id)-3d "
2022 "%(handle)-3d "
2023 "%(state)-3d "
2024 "%(event-ch)-3d "
2025 "%(ring-ref)-5d "
2026 "%(be-path)-30s "
2027 % ni)
2029 def xm_vtpm_list(args):
2030 (use_long, params) = arg_check_for_resource_list(args, "vtpm-list")
2032 dom = params[0]
2034 if serverType == SERVER_XEN_API:
2035 vtpm_refs = server.xenapi.VM.get_VTPMs(get_single_vm(dom))
2036 vtpm_properties = \
2037 map(server.xenapi.VTPM.get_runtime_properties, vtpm_refs)
2038 devs = map(lambda (handle, properties): [handle, map2sxp(properties)],
2039 zip(range(len(vtpm_properties)), vtpm_properties))
2040 else:
2041 devs = server.xend.domain.getDeviceSxprs(dom, 'vtpm')
2043 if use_long:
2044 map(PrettyPrint.prettyprint, devs)
2045 else:
2046 hdr = 0
2047 for x in devs:
2048 if hdr == 0:
2049 print 'Idx BE handle state evt-ch ring-ref BE-path'
2050 hdr = 1
2051 ni = parse_dev_info(x[1])
2052 ni['idx'] = int(x[0])
2053 print ("%(idx)-3d "
2054 "%(backend-id)-3d "
2055 "%(handle)-3d "
2056 "%(state)-3d "
2057 "%(event-ch)-3d "
2058 "%(ring-ref)-5d "
2059 "%(be-path)-30s "
2060 % ni)
2063 def xm_pci_list(args):
2064 (use_long, params) = arg_check_for_resource_list(args, "pci-list")
2066 dom = params[0]
2068 devs = server.xend.domain.getDeviceSxprs(dom, 'pci')
2070 if len(devs) == 0:
2071 return
2073 has_vslt = devs[0].has_key('vslt')
2074 if has_vslt:
2075 hdr_str = 'VSlt domain bus slot func'
2076 fmt_str = "%(vslt)-3s %(domain)-3s %(bus)-3s %(slot)-3s %(func)-3s "
2077 else:
2078 hdr_str = 'domain bus slot func'
2079 fmt_str = "%(domain)-3s %(bus)-3s %(slot)-3s %(func)-3s "
2080 hdr = 0
2082 for x in devs:
2083 if hdr == 0:
2084 print (hdr_str)
2085 hdr = 1
2086 print ( fmt_str % x )
2088 def parse_block_configuration(args):
2089 dom = args[0]
2091 if args[1].startswith('tap:'):
2092 cls = 'tap'
2093 else:
2094 cls = 'vbd'
2096 vbd = [cls,
2097 ['uname', args[1]],
2098 ['dev', args[2]],
2099 ['mode', args[3]]]
2100 if len(args) == 5:
2101 vbd.append(['backend', args[4]])
2103 return (dom, vbd)
2106 def xm_block_attach(args):
2107 arg_check(args, 'block-attach', 4, 5)
2109 if serverType == SERVER_XEN_API:
2110 dom = args[0]
2111 uname = args[1]
2112 dev = args[2]
2113 mode = args[3]
2115 # First create new VDI
2116 vdi_record = {
2117 "name_label": "vdi" + str(uname.__hash__()),
2118 "name_description": "",
2119 "SR": get_default_SR(),
2120 "virtual_size": 0,
2121 "sector_size": 512,
2122 "type": "system",
2123 "sharable": False,
2124 "read_only": mode!="w",
2125 "other_config": {"location": uname}
2128 vdi_ref = server.xenapi.VDI.create(vdi_record)
2130 # Now create new VBD
2132 vbd_record = {
2133 "VM": get_single_vm(dom),
2134 "VDI": vdi_ref,
2135 "device": dev,
2136 "bootable": True,
2137 "mode": mode=="w" and "RW" or "RO",
2138 "type": "Disk",
2139 "qos_algorithm_type": "",
2140 "qos_algorithm_params": {}
2143 server.xenapi.VBD.create(vbd_record)
2145 else:
2146 (dom, vbd) = parse_block_configuration(args)
2147 server.xend.domain.device_create(dom, vbd)
2150 def xm_block_configure(args):
2151 arg_check(args, 'block-configure', 4, 5)
2153 (dom, vbd) = parse_block_configuration(args)
2154 server.xend.domain.device_configure(dom, vbd)
2157 def xm_network_attach(args):
2158 arg_check(args, 'network-attach', 1, 11)
2160 dom = args[0]
2161 vif = ['vif']
2162 vif_params = ['type', 'mac', 'bridge', 'ip', 'script', \
2163 'backend', 'vifname', 'rate', 'model', 'accel']
2165 if serverType == SERVER_XEN_API:
2166 vif_record = {
2167 "device": "eth0",
2168 "network": get_default_Network(),
2169 "VM": get_single_vm(dom),
2170 "MAC": "",
2171 "MTU": "",
2172 "qos_algorithm_type": "",
2173 "qos_algorithm_params": {},
2174 "other_config": {}
2177 def set(keys, val):
2178 record = vif_record
2179 for key in keys[:-1]:
2180 record = record[key]
2181 record[keys[-1]] = val
2183 def get_net_from_bridge(bridge):
2184 # In OSS, we just assert network.name_label == bridge name
2185 networks = dict([(record['name_label'], ref)
2186 for ref, record in server.xenapi.network
2187 .get_all_records().items()])
2188 if bridge not in networks.keys():
2189 raise "Unknown bridge name!"
2190 return networks[bridge]
2192 vif_conv = {
2193 'type':
2194 lambda x: None,
2195 'mac':
2196 lambda x: set(['MAC'], x),
2197 'bridge':
2198 lambda x: set(['network'], get_net_from_bridge(x)),
2199 'ip':
2200 lambda x: set(['other_config', 'ip'], x),
2201 'script':
2202 lambda x: set(['other_config', 'script'], x),
2203 'backend':
2204 lambda x: set(['other_config', 'backend'], x),
2205 'vifname':
2206 lambda x: set(['device'], x),
2207 'rate':
2208 lambda x: set(['qos_algorithm_params', 'rate'], x),
2209 'model':
2210 lambda x: None,
2211 'accel':
2212 lambda x: set(['other_config', 'accel'], x)
2215 for a in args[1:]:
2216 vif_param = a.split("=")
2217 if len(vif_param) != 2 or vif_param[1] == '' or \
2218 vif_param[0] not in vif_params:
2219 err("Invalid argument: %s" % a)
2220 usage('network-attach')
2221 else:
2222 vif_conv[vif_param[0]](vif_param[1])
2224 server.xenapi.VIF.create(vif_record)
2225 else:
2226 for a in args[1:]:
2227 vif_param = a.split("=")
2228 if len(vif_param) != 2 or vif_param[1] == '' or \
2229 vif_param[0] not in vif_params:
2230 err("Invalid argument: %s" % a)
2231 usage('network-attach')
2232 vif.append(vif_param)
2233 server.xend.domain.device_create(dom, vif)
2235 def parse_pci_configuration(args):
2236 dom = args[0]
2238 if len(args) == 6:
2239 vslt = args[5]
2240 else:
2241 vslt = '0x0' #chose a free virtual PCI slot
2243 pci = ['pci',
2244 ['devs',
2245 [{'domain': "0x%x" % int(args[1], 16),
2246 'bus': "0x%x" % int(args[2], 16),
2247 'slot': "0x%x" % int(args[3], 16),
2248 'func': "0x%x" % int(args[4], 16),
2249 'vslt': "0x%x" % int(vslt, 16)}]
2250 ]]
2252 return (dom, pci)
2254 def xm_pci_attach(args):
2255 arg_check(args, 'pci-attach', 5, 6)
2256 (dom, pci) = parse_pci_configuration(args)
2257 server.xend.domain.device_create(dom, pci)
2259 def detach(args, deviceClass):
2260 rm_cfg = True
2261 dom = args[0]
2262 dev = args[1]
2263 try:
2264 force = args[2]
2265 if (force != "--force") and (force != "-f"):
2266 print "Ignoring option %s"%(force)
2267 force = None
2268 except IndexError:
2269 force = None
2271 server.xend.domain.destroyDevice(dom, deviceClass, dev, force, rm_cfg)
2274 def xm_block_detach(args):
2275 if serverType == SERVER_XEN_API:
2276 arg_check(args, "block-detach", 2, 3)
2277 dom = args[0]
2278 dev = args[1]
2279 vbd_refs = server.xenapi.VM.get_VBDs(get_single_vm(dom))
2280 vbd_refs = [vbd_ref for vbd_ref in vbd_refs
2281 if server.xenapi.VBD.get_device(vbd_ref) == dev]
2282 if len(vbd_refs) > 0:
2283 vbd_ref = vbd_refs[0]
2284 vdi_ref = server.xenapi.VBD.get_VDI(vbd_ref)
2286 server.xenapi.VBD.destroy(vbd_ref)
2288 if len(server.xenapi.VDI.get_VBDs(vdi_ref)) <= 0:
2289 server.xenapi.VDI.destroy(vdi_ref)
2290 else:
2291 raise OptionError("Cannot find device '%s' in domain '%s'"
2292 % (dev,dom))
2293 else:
2294 arg_check(args, 'block-detach', 2, 3)
2295 dom = args[0]
2296 dev = args[1]
2297 dc = server.xend.domain.getBlockDeviceClass(dom, dev)
2298 if dc == "tap":
2299 detach(args, 'tap')
2300 else:
2301 detach(args, 'vbd')
2303 def xm_network_detach(args):
2304 if serverType == SERVER_XEN_API:
2305 arg_check(args, "network-detach", 2, 3)
2306 dom = args[0]
2307 devid = args[1]
2308 vif_refs = server.xenapi.VM.get_VIFs(get_single_vm(dom))
2309 vif_refs = [vif_ref for vif_ref in vif_refs
2310 if server.xenapi.VIF.\
2311 get_runtime_properties(vif_ref)["handle"] == devid]
2312 if len(vif_refs) > 0:
2313 vif_ref = vif_refs[0]
2315 server.xenapi.VIF.destroy(vif_ref)
2316 else:
2317 print "Cannot find device '%s' in domain '%s'" % (devid,dom)
2318 else:
2319 arg_check(args, 'network-detach', 2, 3)
2320 detach(args, 'vif')
2323 def xm_pci_detach(args):
2324 arg_check(args, 'pci-detach', 2)
2325 dom = args[0]
2326 dev = args[1]
2327 server.xend.domain.destroyDevice(dom, 'dpci', dev)
2329 def xm_vnet_list(args):
2330 xenapi_unsupported()
2331 try:
2332 (options, params) = getopt.gnu_getopt(args, 'l', ['long'])
2333 except getopt.GetoptError, opterr:
2334 err(opterr)
2335 usage('vnet-list')
2337 use_long = 0
2338 for (k, v) in options:
2339 if k in ['-l', '--long']:
2340 use_long = 1
2342 if params:
2343 use_long = 1
2344 vnets = params
2345 else:
2346 vnets = server.xend_vnets()
2348 for vnet in vnets:
2349 try:
2350 if use_long:
2351 info = server.xend_vnet(vnet)
2352 PrettyPrint.prettyprint(info)
2353 else:
2354 print vnet
2355 except Exception, ex:
2356 print vnet, ex
2358 def xm_vnet_create(args):
2359 xenapi_unsupported()
2360 arg_check(args, "vnet-create", 1)
2361 conf = args[0]
2362 if not os.access(conf, os.R_OK):
2363 print "File not found: %s" % conf
2364 sys.exit(1)
2366 server.xend_vnet_create(conf)
2368 def xm_vnet_delete(args):
2369 xenapi_unsupported()
2370 arg_check(args, "vnet-delete", 1)
2371 vnet = args[0]
2372 server.xend_vnet_delete(vnet)
2374 def xm_network_new(args):
2375 xenapi_only()
2376 arg_check(args, "network-new", 1)
2377 network = args[0]
2379 record = {
2380 "name_label": network,
2381 "name_description": "",
2382 "other_config": {},
2383 "default_gateway": "",
2384 "default_netmask": ""
2387 server.xenapi.network.create(record)
2389 def xm_network_del(args):
2390 xenapi_only()
2391 arg_check(args, "network-del", 1)
2392 network = args[0]
2394 networks = dict([(record['name_label'], ref)
2395 for ref, record in
2396 server.xenapi.network.get_all_records().items()])
2398 if network not in networks.keys():
2399 raise ValueError("'%s' is not a valid network name" % network)
2401 server.xenapi.network.destroy(networks[network])
2403 def xm_network_show(args):
2404 xenapi_only()
2405 arg_check(args, "network-show", 0)
2407 networks = server.xenapi.network.get_all_records()
2408 pifs = server.xenapi.PIF.get_all_records()
2409 vifs = server.xenapi.VIF.get_all_records()
2411 print '%-20s %-40s %-10s' % \
2412 ('Name', 'VIFs', 'PIFs')
2414 format2 = "%(name_label)-20s %(vif)-40s %(pif)-10s"
2416 for network_ref, network in networks.items():
2417 for i in range(max(len(network['PIFs']),
2418 len(network['VIFs']), 1)):
2419 if i < len(network['PIFs']):
2420 pif_uuid = network['PIFs'][i]
2421 else:
2422 pif_uuid = None
2424 if i < len(network['VIFs']):
2425 vif_uuid = network['VIFs'][i]
2426 else:
2427 vif_uuid = None
2429 pif = pifs.get(pif_uuid, None)
2430 vif = vifs.get(vif_uuid, None)
2432 if vif:
2433 dom_name = server.xenapi.VM.get_name_label(vif['VM'])
2434 vif = "%s.%s" % (dom_name, vif['device'])
2435 else:
2436 vif = ''
2438 if pif:
2439 if int(pif['VLAN']) > -1:
2440 pif = '%s.%s' % (pif['device'], pif['VLAN'])
2441 else:
2442 pif = pif['device']
2443 else:
2444 pif = ''
2446 if i == 0:
2447 r = {'name_label':network['name_label'],
2448 'vif':vif, 'pif':pif}
2449 else:
2450 r = {'name_label':'', 'vif':vif, 'pif':pif}
2452 print format2 % r
2455 commands = {
2456 "shell": xm_shell,
2457 "event-monitor": xm_event_monitor,
2458 # console commands
2459 "console": xm_console,
2460 # xenstat commands
2461 "top": xm_top,
2462 # domain commands
2463 "delete": xm_delete,
2464 "destroy": xm_destroy,
2465 "domid": xm_domid,
2466 "domname": xm_domname,
2467 "dump-core": xm_dump_core,
2468 "reboot": xm_reboot,
2469 "rename": xm_rename,
2470 "restore": xm_restore,
2471 "resume": xm_resume,
2472 "save": xm_save,
2473 "shutdown": xm_shutdown,
2474 "start": xm_start,
2475 "sysrq": xm_sysrq,
2476 "trigger": xm_trigger,
2477 "uptime": xm_uptime,
2478 "suspend": xm_suspend,
2479 "list": xm_list,
2480 # memory commands
2481 "mem-max": xm_mem_max,
2482 "mem-set": xm_mem_set,
2483 # cpu commands
2484 "vcpu-pin": xm_vcpu_pin,
2485 "vcpu-list": xm_vcpu_list,
2486 "vcpu-set": xm_vcpu_set,
2487 # special
2488 "pause": xm_pause,
2489 "unpause": xm_unpause,
2490 # host commands
2491 "debug-keys": xm_debug_keys,
2492 "dmesg": xm_dmesg,
2493 "info": xm_info,
2494 "log": xm_log,
2495 "serve": xm_serve,
2496 # scheduler
2497 "sched-sedf": xm_sched_sedf,
2498 "sched-credit": xm_sched_credit,
2499 # block
2500 "block-attach": xm_block_attach,
2501 "block-detach": xm_block_detach,
2502 "block-list": xm_block_list,
2503 "block-configure": xm_block_configure,
2504 # network (AKA vifs)
2505 "network-attach": xm_network_attach,
2506 "network-detach": xm_network_detach,
2507 "network-list": xm_network_list,
2508 # network (as in XenAPI)
2509 "network-new": xm_network_new,
2510 "network-del": xm_network_del,
2511 "network-show": xm_network_show,
2512 # vnet
2513 "vnet-list": xm_vnet_list,
2514 "vnet-create": xm_vnet_create,
2515 "vnet-delete": xm_vnet_delete,
2516 # vtpm
2517 "vtpm-list": xm_vtpm_list,
2518 #pci
2519 "pci-attach": xm_pci_attach,
2520 "pci-detach": xm_pci_detach,
2521 "pci-list": xm_pci_list,
2524 ## The commands supported by a separate argument parser in xend.xm.
2525 IMPORTED_COMMANDS = [
2526 'create',
2527 'new',
2528 'migrate',
2529 'labels',
2530 'dumppolicy',
2531 'addlabel',
2532 'rmlabel',
2533 'getlabel',
2534 'dry-run',
2535 'resources',
2536 'getpolicy',
2537 'setpolicy',
2538 'resetpolicy',
2541 for c in IMPORTED_COMMANDS:
2542 commands[c] = eval('lambda args: xm_importcommand("%s", args)' % c)
2544 aliases = {
2545 "balloon": "mem-set",
2546 "set-vcpus": "vcpu-set",
2547 "vif-list": "network-list",
2548 "vbd-create": "block-attach",
2549 "vbd-destroy": "block-detach",
2550 "vbd-list": "block-list",
2554 def xm_lookup_cmd(cmd):
2555 if commands.has_key(cmd):
2556 return commands[cmd]
2557 elif aliases.has_key(cmd):
2558 deprecated(cmd,aliases[cmd])
2559 return commands[aliases[cmd]]
2560 elif cmd == 'help':
2561 longHelp()
2562 sys.exit(0)
2563 else:
2564 # simulate getopt's prefix matching behaviour
2565 if len(cmd) > 1:
2566 same_prefix_cmds = [commands[c] for c in commands.keys() \
2567 if c[:len(cmd)] == cmd]
2568 # only execute if there is only 1 match
2569 if len(same_prefix_cmds) == 1:
2570 return same_prefix_cmds[0]
2571 return None
2573 def deprecated(old,new):
2574 print >>sys.stderr, (
2575 "Command %s is deprecated. Please use xm %s instead." % (old, new))
2577 def main(argv=sys.argv):
2578 if len(argv) < 2:
2579 usage()
2581 # intercept --help(-h) and output our own help
2582 for help in ['--help', '-h']:
2583 if help in argv[1:]:
2584 if help == argv[1]:
2585 longHelp()
2586 sys.exit(0)
2587 else:
2588 usage(argv[1])
2590 cmd_name = argv[1]
2591 cmd = xm_lookup_cmd(cmd_name)
2592 if cmd:
2593 # strip off prog name and subcmd
2594 args = argv[2:]
2595 _, rc = _run_cmd(cmd, cmd_name, args)
2596 sys.exit(rc)
2597 else:
2598 err('Subcommand %s not found!' % cmd_name)
2599 usage()
2601 def _run_cmd(cmd, cmd_name, args):
2602 global server
2604 try:
2605 if server is None:
2606 if serverType == SERVER_XEN_API:
2607 server = XenAPI.Session(serverURI)
2608 username, password = parseAuthentication()
2609 server.login_with_password(username, password)
2610 def logout():
2611 try:
2612 server.xenapi.session.logout()
2613 except:
2614 pass
2615 atexit.register(logout)
2616 else:
2617 server = ServerProxy(serverURI)
2619 return True, cmd(args)
2620 except socket.error, ex:
2621 if os.geteuid() != 0:
2622 err("Most commands need root access. Please try again as root.")
2623 else:
2624 err("Unable to connect to xend: %s. Is xend running?" % ex[1])
2625 except KeyboardInterrupt:
2626 print "Interrupted."
2627 return True, ''
2628 except IOError, ex:
2629 if os.geteuid() != 0:
2630 err("Most commands need root access. Please try again as root.")
2631 else:
2632 err("Unable to connect to xend: %s." % ex[1])
2633 except SystemExit, code:
2634 return code == 0, code
2635 except XenAPI.Failure, exn:
2636 for line in [''] + wrap(str(exn), 80) + ['']:
2637 print >>sys.stderr, line
2638 except xmlrpclib.Fault, ex:
2639 if ex.faultCode == XendClient.ERROR_INVALID_DOMAIN:
2640 err("Domain '%s' does not exist." % ex.faultString)
2641 else:
2642 err(ex.faultString)
2643 _usage(cmd_name)
2644 except xmlrpclib.ProtocolError, ex:
2645 if ex.errcode == -1:
2646 print >>sys.stderr, (
2647 "Xend has probably crashed! Invalid or missing HTTP "
2648 "status code.")
2649 else:
2650 print >>sys.stderr, (
2651 "Xend has probably crashed! ProtocolError(%d, %s)." %
2652 (ex.errcode, ex.errmsg))
2653 except (ValueError, OverflowError):
2654 err("Invalid argument.")
2655 _usage(cmd_name)
2656 except OptionError, e:
2657 err(str(e))
2658 _usage(cmd_name)
2659 print e.usage
2660 except XenAPIUnsupportedException, e:
2661 err(str(e))
2662 except XSMError, e:
2663 err(str(e))
2664 except Exception, e:
2665 if serverType != SERVER_XEN_API:
2666 import xen.util.xsm.xsm as security
2667 if isinstance(e, security.XSMError):
2668 err(str(e))
2669 return False, 1
2670 print "Unexpected error:", sys.exc_info()[0]
2671 print
2672 print "Please report to xen-devel@lists.xensource.com"
2673 raise
2675 return False, 1
2677 if __name__ == "__main__":
2678 main()