source: trunk/packages/xen-3.1/xen-3.1/tools/python/xen/xm/main.py @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

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