The following patch is a major restructuring of main.py to be more straight
forward, and remove as much code as possible. It does a number of things:
* It implements the standardized options proposed via my RFC for xm
* It restructures the calling of these functions to be function pointers out
of a dictionary, instead of subclasses found through inspection
* It consolidates all help info, making it easier to see that the help
screen looks consistent across commands
* It moves object importing into the functions that require them only,
allowing commands like "xm help" to be runable as non root
* It adds command aliasing to provide backwards compatibility with many
commands (i.e. xm balloon)
* It provides more useful error messages is most fail cases
* It implements a short help by default (which takes < 24 screen lines) as
requested by Mark W at OLS
* It attempts to trap more exceptions than before and provide useful errors
based on them (this requires more testing)
It also has the added benefit of dropping the total size of main.py from
935 lines to 694 lines.
This patch makes no changes to any other elements of xen/xm, and works with
all other objects and libraries as is.
Signed-off-by: Sean Dague <sean@xxxxxxxxx>
Diffstat output:
main.py | 1471 ++++++++++++++++++++++++++--------------------------------------
1 files changed, 615 insertions(+), 856 deletions(-)
--- xen-unstable.hg/tools/python/xen/xm/main.py 2005-07-29 15:35:02.000000000
-0400
+++ xen-unstable.sean/tools/python/xen/xm/main.py 2005-08-01
14:57:23.000000000 -0400
@@ -1,27 +1,115 @@
-# Copyright (C) 2004 Mike Wray <mike.wray@xxxxxx>
+# (C) Copyright IBM Corp. 2005
+# Copyright (C) 2004 Mike Wray
+#
+# Authors:
+# Sean Dague <sean at dague dot net>
+# Mike Wray <mike dot wray at hp dot com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License v2. Full details on license
+# terms and conditions are included with this distribution
+
"""Grand unified management application for Xen.
"""
import os
import os.path
import sys
+import re
from getopt import getopt
import socket
import warnings
warnings.filterwarnings('ignore', category=FutureWarning)
-
from xen.xend import PrettyPrint
from xen.xend import sxp
-# this is a nasty place to stick this in, but required because
-# log file access is set up via a 5 deep import chain. This
-# ensures the user sees a useful message instead of a stack trace
-if os.getuid() != 0:
- print "xm requires root access to execute, please try again as root"
- sys.exit(1)
-
-from xen.xend.XendClient import XendError, server
-from xen.xend.XendClient import main as xend_client_main
-from xen.xm import create, destroy, migrate, shutdown, sysrq
from xen.xm.opts import *
+shorthelp = """Usage: xm <subcommand> [args]
+ Control, list, and manipulate Xen guest instances
+
+xm common subcommands:
+ console <DomId> attach to console of DomId
+ create <CfgFile> create a domain based on Config File
+ destroy <DomId> terminate a domain immediately
+ help display this message
+ list [DomId, ...] list information about domains
+ mem-max <DomId> <Mem> set the maximum memory reservation for a domain
+ mem-set <DomId> <Mem> adjust the current memory usage for a domain
+ migrate <DomId> <Host> migrate a domain to another machine
+ pause <DomId> pause execution of a domain
+ reboot <DomId> reboot a domain
+ restore <File> create a domain from a saved state file
+ save <DomId> <File> save domain state (and config) to file
+ shutdown <DomId> shutdown a domain
+ unpause <DomId> unpause a paused domain
+
+For a complete list of subcommands run 'xm help --long'
+For more help on xm see the xm(1) man page
+For more help on xm create, see the xmdomain.cfg(5) man page"""
+
+longhelp = """Usage: xm <subcommand> [args]
+ Control, list, and manipulate Xen guest instances
+
+xm full list of subcommands:
+
+ Console Commands:
+ console <DomId> attach to console of DomId
+ console-list list available consoles
+
+ Domain Commands:
+ create <ConfigFile> create a domain
+ cpus-set <DomId> <VCpu> <CPUS> set which cpus a VCPU can use.
+ cpus-list <DomId> <VCpu> get the list of cpus for a VCPU
+ destroy <DomId> terminate a domain immediately
+ domid <DomName> convert a domain name to a domain id
+ domname <DomId> convert a domain id to a domain name
+ list list information about domains
+ mem-max <DomId> <Mem> set domain maximum memory limit
+ mem-set <DomId> <Mem> set the domain's memory dynamically
+ migrate <DomId> <Host> migrate a domain to another machine
+ pause <DomId> pause execution of a domain
+ reboot [-w|-a] <DomId> reboot a domain
+ restore <File> create a domain from a saved state file
+ save <DomId> <File> save domain state (and config) to file
+ shutdown [-w|-a] <DomId> shutdown a domain
+ sysrq <DomId> <letter> send a sysrq to a domain
+ unpause <DomId> unpause a paused domain
+ vcpu-enable <DomId> <VCPU> disable VCPU in a domain
+ vcpu-disable <DomId> <VCPU> enable VCPU in a domain
+ vcpu-list <DomId> get the list of VCPUs for a domain
+
+ Xen Host Commands:
+ dmesg [--clear] read or clear Xen's message buffer
+ info get information about the xen host
+ log print the xend log
+
+ Scheduler Commands:
+ bvt <options> set BVT scheduler parameters
+ bvt_ctxallow <Allow> set the BVT scheduler context switch allowance
+ sedf <options> set simple EDF parameters
+
+ Virtual Device Commands:
+ block-create <DomId> <BackDev> <FrontDev> <Mode> [BackDomId]
+ Create a new virtual block device
+ block-destroy <DomId> <DevId> Destroy a domain's virtual block device
+ block-list <DomId> List virtual block devices for a domain
+ block-refresh <DomId> <DevId> Refresh a virtual block device for a domain
+ network-limit <DomId> <Vif> <Credit> <Period>
+ Limit the transmission rate of a virtual network interface
+ network-list <DomId> List virtual network interfaces for a domain
+
+For a short list of subcommands run 'xm help'
+For more help on xm see the xm(1) man page
+For more help on xm create, see the xmdomain.cfg(5) man page"""
+
+####################################################################
+#
+# Utility functions
+#
+####################################################################
+
+def arg_check(args,num,name):
+ if len(args) < num:
+ err("'xm %s' requires %s argument(s)!\n" % (name, num))
+ usage(name)
def unit(c):
if not c.isalpha():
@@ -48,724 +136,342 @@
else:
return value * (base / dst_base)
-class Group:
+def err(msg):
+ print >>sys.stderr, "Error:", msg
- name = ""
- info = ""
+def handle_xend_error(cmd, dom, ex):
+ error = str(ex)
+ if error == "Not found" and dom != None:
+ err("Domain '%s' not found when running 'xm %s'" % (dom, cmd))
+ sys.exit(1)
+ else:
+ raise ex
- def __init__(self, xm):
- self.xm = xm
- self.progs = {}
-
- def addprog(self, prog):
- self.progs[prog.name] = prog
-
- def getprog(self, name):
- return self.progs.get(name)
-
- def proglist(self):
- kl = self.progs.keys()
- kl.sort()
- return [ self.getprog(k) for k in kl ]
-
- def help(self, args):
- if self.info:
- print
- print self.info
- print
- else:
- print
-
- def shortHelp(self, args):
- self.help(args)
- for p in self.proglist():
- p.shortHelp(args)
-
-class Prog:
- """Base class for sub-programs.
- """
-
- """Program group it belongs to"""
- group = 'all'
- """Program name."""
- name = '??'
- """Short program info."""
- info = ''
-
- def __init__(self, xm):
- self.xm = xm
-
- def err(self, msg):
- self.xm.err(msg)
- def help(self, args):
- self.shortHelp(args)
+#########################################################################
+#
+# Main xm functions
+#
+#########################################################################
+
+def xm_create(args):
+ from xen.xm import create
+ # ugly hack because the opt parser apparently wants
+ # the subcommand name just to throw it away!
+ args.insert(0,"bogus")
+ create.main(args)
- def shortHelp(self, args):
- print "%-14s %s" % (self.name, self.info)
+def xm_save(args):
+ arg_check(args,2,"save")
- def main(self, args):
- """Program main entry point.
- """
- pass
-
-
-class ProgUnknown(Prog):
-
- name = 'unknown'
- info = ''
+ dom = args[0] # TODO: should check if this exists
+ savefile = os.path.abspath(args[1])
- def help(self, args):
- self.xm.err("Unknown command: %s\nTry '%s help' for more information."
- % (args[0], self.xm.name))
-
- main = help
-
-class Xm:
- """Main application.
- """
-
- def __init__(self):
- self.name = 'xm'
- self.unknown = ProgUnknown(self)
- self.progs = {}
- self.groups = {}
-
- def err(self, msg):
- print >>sys.stderr, "Error:", msg
- sys.exit(1)
-
- def main(self, args):
- try:
- self.main_call(args)
- except socket.error, ex:
- print >>sys.stderr, ex
- self.err("Error connecting to xend, is xend running?")
- except XendError, ex:
- self.err(str(ex))
-
- def main_call(self, args):
- """Main entry point. Dispatches to the progs.
- """
- self.name = args[0]
- if len(args) < 2:
- args.append('help')
- help = self.helparg(args)
- p = self.getprog(args[1], self.unknown)
- if help or len(args) < 2:
- p.help(args[1:])
- else:
- p.main(args[1:])
+ from xen.xend.XendClient import server
+ server.xend_domain_save(dom, savefile)
+
+def xm_restore(args):
+ arg_check(args,1,"restore")
- def helparg(self, args):
- for a in args:
- if a in ['-h', '--help']:
- return 1
- return 0
+ savefile = os.path.abspath(args[0])
- def prog(self, pklass):
- """Add a sub-program.
+ from xen.xend.XendClient import server
+ info = server.xend_domain_restore(savefile)
+ PrettyPrint.prettyprint(info)
+ id = sxp.child_value(info, 'id')
+ if id is not None:
+ server.xend_domain_unpause(id)
+
+def xm_migrate(args):
+ # TODO: arg_check
+ from xen.xm import migrate
+ # ugly hack because the opt parser apparently wants
+ # the subcommand name just to throw it away!
+ args.insert(0,"bogus")
+ migrate.main(args)
+
+def xm_list(args):
+ use_long = 0
+ show_vcpus = 0
+ (options, params) = getopt(args, 'lv', ['long','vcpus'])
+
+ n = len(params)
+ for (k, v) in options:
+ if k in ['-l', '--long']:
+ use_long = 1
+ if k in ['-v', '--vcpus']:
+ show_vcpus = 1
+
+ domsinfo = []
+ from xen.xend.XendClient import server
+ if n == 0:
+ doms = server.xend_domains()
+ doms.sort()
+ else:
+ doms = params
+ for dom in doms:
+ info = server.xend_domain(dom)
+ domsinfo.append(parse_doms_info(info))
+
+ if use_long:
+ # this actually seems like a bad idea, as it just dumps sexp out
+ PrettyPrint.prettyprint(info)
+ elif show_vcpus:
+ xm_show_vcpus(domsinfo)
+ else:
+ xm_brief_list(domsinfo)
- pklass program class (Prog subclass)
- """
- p = pklass(self)
- self.progs[p.name] = p
- self.getgroup(p.group).addprog(p)
- return p
-
- def getprog(self, name, val=None):
- """Get a sub-program.
- name Name of the sub-program (or optionally, an unambiguous
- prefix of its name)
- val Default return value if no (unique) match is found
- """
-
- match = None
- for progname in self.progs.keys():
- if progname == name:
- match = progname
- break
- if progname.startswith(name):
- if not match:
- match = progname
- else:
- return val # name is ambiguous - bail out
-
- return self.progs.get(match, val)
-
- def group(self, klass):
- g = klass(self)
- self.groups[g.name] = g
- return g
-
- def getgroup(self, name):
- return self.groups[name]
-
- def grouplist(self):
- kl = self.groups.keys()
- kl.sort()
- return [ self.getgroup(k) for k in kl ]
+def parse_doms_info(info):
+ dominfo = {}
+ dominfo['dom'] = int(sxp.child_value(info, 'id', '-1'))
+ dominfo['name'] = sxp.child_value(info, 'name', '??')
+ dominfo['mem'] = int(sxp.child_value(info, 'memory', '0'))
+ dominfo['cpu'] = str(sxp.child_value(info, 'cpu', '0'))
+ dominfo['vcpus'] = int(sxp.child_value(info, 'vcpus', '0'))
+ # if there is more than 1 cpu, the value doesn't mean much
+ if dominfo['vcpus'] > 1:
+ dominfo['cpu'] = '-'
+ dominfo['state'] = sxp.child_value(info, 'state', '??')
+ dominfo['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
+ # get the console
+ console = sxp.child(info, 'console')
+ if console:
+ dominfo['port'] = sxp.child_value(console, 'console_port')
+ else:
+ dominfo['port'] = ''
+ # security identifiers
+ if ((int(sxp.child_value(info, 'ssidref', '0'))) != 0):
+ dominfo['ssidref1'] = int(sxp.child_value(info, 'ssidref', '0')) &
0xffff
+ dominfo['ssidref2'] = (int(sxp.child_value(info, 'ssidref', '0')) >>
16) & 0xffff
+ # get out the vcpu information
+ dominfo['vcpulist'] = []
+ vcpu_to_cpu = sxp.child_value(info, 'vcpu_to_cpu', '-1').split('|')
+ cpumap = sxp.child_value(info, 'cpumap', [])
+ mask = ((int(sxp.child_value(info, 'vcpus', '0')))**2) - 1
+ count = 0
+ for cpu in vcpu_to_cpu:
+ vcpuinfo = {}
+ vcpuinfo['name'] = sxp.child_value(info, 'name', '??')
+ vcpuinfo['dom'] = int(sxp.child_value(info, 'id', '-1'))
+ vcpuinfo['vcpu'] = int(count)
+ vcpuinfo['cpu'] = int(cpu)
+ vcpuinfo['cpumap'] = int(cpumap[count])&mask
+ count = count + 1
+ dominfo['vcpulist'].append(vcpuinfo)
+ return dominfo
-# Create the application object, then add the sub-program classes.
-xm = Xm()
-
-class GroupAll(Group):
-
- name = "all"
- info = ""
-
-xm.group(GroupAll)
+def xm_brief_list(domsinfo):
+ print 'Name Id Mem(MB) CPU VCPU(s) State Time(s) Console'
+ for dominfo in domsinfo:
+ print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3s %(vcpus)5d
%(state)5s %(cpu_time)7.1f %(port)4s" % dominfo)
+
+def xm_show_vcpus(domsinfo):
+ print 'Name Id VCPU CPU CPUMAP'
+ for dominfo in domsinfo:
+ for vcpuinfo in dominfo['vcpulist']:
+ print ("%(name)-16s %(dom)3d %(vcpu)4d %(cpu)3d 0x%(cpumap)x" %
+ vcpuinfo)
+
+def xm_vcpu_list(args):
+ args.insert(0,"-v")
+ xm_list(args)
+
+def xm_destroy(args):
+ arg_check(args,1,"destroy")
+
+ from xen.xm import destroy
+ # ugly hack because the opt parser apparently wants
+ # the subcommand name just to throw it away!
+ args.insert(0,"bogus")
+ destroy.main(args)
+
+# TODO: make reboot do the right thing, right now
+# reboot and shutdown are exactly the same
+def xm_reboot(args):
+ arg_check(args,1,"reboot")
+ # ugly hack because the opt parser apparently wants
+ # the subcommand name just to throw it away!
+ args.insert(0,"bogus")
+ from xen.xm import shutdown
+ shutdown.main(args)
+
+def xm_shutdown(args):
+ arg_check(args,1,"shutdown")
+
+ # ugly hack because the opt parser apparently wants
+ # the subcommand name just to throw it away!
+ args.insert(0,"bogus")
+ from xen.xm import shutdown
+ shutdown.main(args)
+
+def xm_sysrq(args):
+ from xen.xm import sysrq
+ # ugly hack because the opt parser apparently wants
+ # the subcommand name just to throw it away!
+ args.insert(0,"bogus")
+ sysrq.main(args)
+
+def xm_pause(args):
+ arg_check(args, 1, "pause")
+ dom = args[0]
+
+ from xen.xend.XendClient import server
+ server.xend_domain_pause(dom)
+
+def xm_unpause(args):
+ arg_check(args, 1, "unpause")
+ dom = args[0]
+
+ from xen.xend.XendClient import server
+ server.xend_domain_unpause(dom)
+
+#############################################################
+
+def cpu_make_map(cpulist):
+ cpus = []
+ cpumap = 0
+ for c in cpulist.split(','):
+ if c.find('-') != -1:
+ (x,y) = c.split('-')
+ for i in range(int(x),int(y)+1):
+ cpus.append(int(i))
+ else:
+ cpus.append(int(c))
+ cpus.sort()
+ for c in cpus:
+ cpumap = cpumap | 1<<c
-class GroupDomain(Group):
+ return cpumap
- name = "domain"
- info = "Commands on domains:"
+def xm_cpus_set(args):
+ arg_check(args, 3, "cpus-set")
-xm.group(GroupDomain)
-
-class GroupScheduler(Group):
-
- name = "scheduler"
- info = "Comands controlling scheduling:"
-
-xm.group(GroupScheduler)
-
-class GroupHost(Group):
-
- name = "host"
- info = "Commands related to the xen host (node):"
-
-xm.group(GroupHost)
-
-class GroupConsole(Group):
-
- name = "console"
- info = "Commands related to consoles:"
-
-xm.group(GroupConsole)
-
-class GroupVbd(Group):
-
- name = "vbd"
- info = "Commands related to virtual block devices:"
-
-xm.group(GroupVbd)
-
-class GroupVif(Group):
-
- name = "vif"
- info = "Commands related to virtual network interfaces:"
-
-xm.group(GroupVif)
-
-class ProgHelp(Prog):
-
- name = "help"
- info = "Print help."
+ dom = args[0]
+ vcpu = int(args[1])
+ cpumap = cpu_make_map(args[2])
- def help(self, args):
- if len(args) == 2:
- name = args[1]
- p = self.xm.getprog(name)
- if p:
- p.help(args[1:])
- else:
- print '%s: Unknown command: %s' % (self.name, name)
- else:
- for g in self.xm.grouplist():
- g.shortHelp(args)
- print "\nTry '%s help CMD' for help on CMD" % self.xm.name
-
- main = help
-
-xm.prog(ProgHelp)
+ from xen.xend.XendClient import server
+ server.xend_domain_pincpu(dom, vcpu, cpumap)
-class ProgCreate(Prog):
+def xm_mem_max(args):
+ arg_check(args, 2, "mem-max")
+
+ dom = args[0]
+ mem = int_unit(args[1], 'm')
- group = 'domain'
- name = "create"
- info = """Create a domain."""
+ from xen.xend.XendClient import server
+ server.xend_domain_maxmem_set(dom, mem)
+
+def xm_mem_set(args):
+ arg_check(args, 2, "mem-set")
+
+ dom = args[0]
+ mem_target = int_unit(args[1], 'm')
- def help(self, args):
- create.main([args[0], '-h'])
+ from xen.xend.XendClient import server
+ server.xend_domain_mem_target_set(dom, mem_target)
+
+# TODO: why does this lookup by name? and what if that fails!?
+def xm_vcpu_enable(args):
+ arg_check(args, 2, "vcpu-enable")
+
+ name = args[0]
+ vcpu = int(args[1])
+
+ from xen.xend.XendClient import server
+ dom = server.xend_domain(name)
+ id = sxp.child_value(dom, 'id')
+ server.xend_domain_vcpu_hotplug(id, vcpu, 1)
- def main(self, args):
- create.main(args)
+def xm_vcpu_disable(args):
+ arg_check(args, 2, "vcpu-disable")
+
+ name = args[0]
+ vcpu = int(args[1])
+
+ from xen.xend.XendClient import server
+ dom = server.xend_domain(name)
+ id = sxp.child_value(dom, 'id')
+ server.xend_domain_vcpu_hotplug(id, vcpu, 0)
+
+def xm_domid(args):
+ name = args[0]
+
+ from xen.xend.XendClient import server
+ dom = server.xend_domain(name)
+ print sxp.child_value(dom, 'id')
+
+def xm_domname(args):
+ name = args[0]
-xm.prog(ProgCreate)
+ from xen.xend.XendClient import server
+ dom = server.xend_domain(name)
+ print sxp.child_value(dom, 'name')
+
+def xm_bvt(args):
+ arg_check(args, 6, "bvt")
+ dom = args[0]
+ v = map(long, args[1:6])
+ from xen.xend.XendClient import server
+ server.xend_domain_cpu_bvt_set(dom, *v)
+
+def xm_bvt_ctxallow(args):
+ arg_check(args, 1, "bvt_ctxallow")
+
+ slice = int(args[0])
+ from xen.xend.XendClient import server
+ server.xend_node_cpu_bvt_slice_set(slice)
-class ProgSave(Prog):
- group = 'domain'
- name = "save"
- info = """Save domain state (and config) to file."""
+def xm_sedf(args):
+ arg_check(args, 6, "sedf")
+
+ dom = args[0]
+ v = map(int, args[1:5])
+ from xen.xend.XendClient import server
+ server.xend_domain_cpu_sedf_set(dom, *v)
+
+def xm_info(args):
+ from xen.xend.XendClient import server
+ info = server.xend_node()
+
+ for x in info[1:]:
+ print "%-23s:" % x[0], x[1]
- def help(self, args):
- print args[0], "DOM FILE"
- print """\nSave domain with id DOM to FILE."""
-
- def main(self, args):
- if len(args) < 3: self.err("%s: Missing arguments" % args[0])
- dom = args[1]
- savefile = os.path.abspath(args[2])
- server.xend_domain_save(dom, savefile)
-
-xm.prog(ProgSave)
-
-class ProgRestore(Prog):
- group = 'domain'
- name = "restore"
- info = """Create a domain from a saved state."""
-
- def help(self, args):
- print args[0], "FILE"
- print "\nRestore a domain from FILE."
-
- def main(self, args):
- if len(args) < 2: self.err("%s: Missing arguments" % args[0])
- savefile = os.path.abspath(args[1])
- info = server.xend_domain_restore(savefile)
- PrettyPrint.prettyprint(info)
- id = sxp.child_value(info, 'id')
- if id is not None:
- server.xend_domain_unpause(id)
-
-xm.prog(ProgRestore)
-
-class ProgMigrate(Prog):
- group = 'domain'
- name = "migrate"
- info = """Migrate a domain to another machine."""
-
- def help(self, args):
- migrate.help([self.name] + args)
-
- def main(self, args):
- migrate.main(args)
-
-xm.prog(ProgMigrate)
-
-class ProgList(Prog):
- group = 'domain'
- name = "list"
- info = """List information about domains."""
-
- short_options = 'lv'
- long_options = ['long','vcpus']
-
- def help(self, args):
- if help:
- print args[0], '[options] [DOM...]'
- print """\nGet information about domains.
- Either all domains or the domains given.
-
- -l, --long Get more detailed information.
- -v, --vcpus Show VCPU to CPU mapping.
- """
- return
-
- def main(self, args):
- use_long = 0
- show_vcpus = 0
- (options, params) = getopt(args[1:],
- self.short_options,
- self.long_options)
- n = len(params)
- for (k, v) in options:
- if k in ['-l', '--long']:
- use_long = 1
- if k in ['-v', '--vcpus']:
- show_vcpus = 1
-
- if n == 0:
- doms = server.xend_domains()
- doms.sort()
+def xm_console_list(args):
+ from xen.xend.XendClient import server
+ l = server.xend_consoles()
+ print "Dom Port Id Connection"
+ for x in l:
+ info = server.xend_console(x)
+ d = {}
+ d['dom'] = sxp.child(info, 'domain', '?')[1]
+ d['port'] = sxp.child_value(info, 'console_port', '?')
+ d['id'] = sxp.child_value(info, 'id', '?')
+ connected = sxp.child(info, 'connected')
+ if connected:
+ d['conn'] = '%s:%s' % (connected[1], connected[2])
else:
- doms = params
-
- if use_long:
- self.long_list(doms)
- elif show_vcpus:
- self.show_vcpus(doms)
- else:
- self.brief_list(doms)
-
- def brief_list(self, doms):
- print 'Name Id Mem(MB) CPU VCPU(s) State Time(s)
Console'
- for dom in doms:
- info = server.xend_domain(dom)
- d = {}
- d['dom'] = int(sxp.child_value(info, 'id', '-1'))
- d['name'] = sxp.child_value(info, 'name', '??')
- d['mem'] = int(sxp.child_value(info, 'memory', '0'))
- d['cpu'] = str(sxp.child_value(info, 'cpu', '0'))
- d['vcpus'] = int(sxp.child_value(info, 'vcpus', '0'))
- d['state'] = sxp.child_value(info, 'state', '??')
- d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
- console = sxp.child(info, 'console')
- if console:
- d['port'] = sxp.child_value(console, 'console_port')
- else:
- d['port'] = ''
- if d['vcpus'] > 1:
- d['cpu'] = '-'
- if ((int(sxp.child_value(info, 'ssidref', '0'))) != 0):
- d['ssidref1'] = int(sxp.child_value(info, 'ssidref', '0')) &
0xffff
- d['ssidref2'] = (int(sxp.child_value(info, 'ssidref', '0')) >>
16) & 0xffff
- print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3s %(vcpus)5d
%(state)5s %(cpu_time)7.1f %(port)4s s:%(ssidref2)02x/p:%(ssidref1)02x"
% d)
- else:
- print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3s %(vcpus)5d
%(state)5s %(cpu_time)7.1f %(port)4s" % d)
-
- def show_vcpus(self, doms):
- print 'Name Id VCPU CPU CPUMAP'
- for dom in doms:
- info = server.xend_domain(dom)
- vcpu_to_cpu = sxp.child_value(info, 'vcpu_to_cpu', '-1').split('|')
- cpumap = sxp.child_value(info, 'cpumap', [])
- mask = ((int(sxp.child_value(info, 'vcpus', '0')))**2) - 1
- count = 0
- for cpu in vcpu_to_cpu:
- d = {}
- d['name'] = sxp.child_value(info, 'name', '??')
- d['dom'] = int(sxp.child_value(info, 'id', '-1'))
- d['vcpu'] = int(count)
- d['cpu'] = int(cpu)
- d['cpumap'] = int(cpumap[count])&mask
- count = count + 1
- print ("%(name)-16s %(dom)3d %(vcpu)4d %(cpu)3d
0x%(cpumap)x" % d)
-
- def long_list(self, doms):
- for dom in doms:
- info = server.xend_domain(dom)
- PrettyPrint.prettyprint(info)
-
-xm.prog(ProgList)
-
-class ProgDestroy(Prog):
- group = 'domain'
- name = "destroy"
- info = """Terminate a domain immediately."""
-
- def help(self, args):
- destroy.main([args[0], '-h'])
-
- def main(self, args):
- destroy.main(args)
-
-xm.prog(ProgDestroy)
-
-class ProgShutdown(Prog):
- group = 'domain'
- name = "shutdown"
- info = """Shutdown a domain."""
-
- def help(self, args):
- shutdown.main([args[0], '-h'])
-
- def main(self, args):
- shutdown.main(args)
-
-xm.prog(ProgShutdown)
-
-class ProgSysrq(Prog):
- group = 'domain'
- name = "sysrq"
- info = """Send a sysrq to a domain."""
-
- def help(self, args):
- sysrq.main([args[0], '-h'])
-
- def main(self, args):
- sysrq.main(args)
-
-xm.prog(ProgSysrq)
-
-class ProgPause(Prog):
- group = 'domain'
- name = "pause"
- info = """Pause execution of a domain."""
-
- def help(self, args):
- print args[0], 'DOM'
- print '\nPause execution of domain DOM.'
-
- def main(self, args):
- if len(args) < 2: self.err("%s: Missing domain" % args[0])
- dom = args[1]
- server.xend_domain_pause(dom)
-
-xm.prog(ProgPause)
-
-class ProgUnpause(Prog):
- group = 'domain'
- name = "unpause"
- info = """Unpause a paused domain."""
-
- def help(self, args):
- print args[0], 'DOM'
- print '\nUnpause execution of domain DOM.'
-
- def main(self, args):
- if len(args) < 2: self.err("%s: Missing domain" % args[0])
- dom = args[1]
- server.xend_domain_unpause(dom)
-
-xm.prog(ProgUnpause)
-
-class ProgPincpu(Prog):
- group = 'domain'
- name = "pincpu"
- info = """Set which cpus a VCPU can use. """
-
- def help(self, args):
- print args[0],'DOM VCPU CPUS'
- print '\nSet which cpus VCPU in domain DOM can use.'
-
- # convert list of cpus to bitmap integer value
- def make_map(self, cpulist):
- cpus = []
- cpumap = 0
- for c in cpulist.split(','):
- if c.find('-') != -1:
- (x,y) = c.split('-')
- for i in range(int(x),int(y)+1):
- cpus.append(int(i))
- else:
- cpus.append(int(c))
- cpus.sort()
- for c in cpus:
- cpumap = cpumap | 1<<c
-
- return cpumap
-
- def main(self, args):
- if len(args) != 4: self.err("%s: Invalid argument(s)" % args[0])
- dom = args[1]
- vcpu = int(args[2])
- cpumap = self.make_map(args[3]);
- server.xend_domain_pincpu(dom, vcpu, cpumap)
-
-xm.prog(ProgPincpu)
-
-class ProgMaxmem(Prog):
- group = 'domain'
- name = 'maxmem'
- info = """Set domain memory limit."""
-
- def help(self, args):
- print args[0], "DOM MEMORY"
- print "\nSet the memory limit for domain DOM to MEMORY megabytes."
-
- def main(self, args):
- if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
- dom = args[1]
- mem = int_unit(args[2], 'm')
- server.xend_domain_maxmem_set(dom, mem)
-
-xm.prog(ProgMaxmem)
-
-class ProgSetMem(Prog):
- group = 'domain'
- name = 'set-mem'
- info = """Set the domain's memory footprint using the balloon driver."""
-
- def help(self, args):
- print args[0], "DOM MEMORY_TARGET"
- print """\nRequest domain DOM to adjust its memory footprint to
-MEMORY_TARGET megabytes"""
-
- def main(self, args):
- if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
- dom = args[1]
- mem_target = int_unit(args[2], 'm')
- server.xend_domain_mem_target_set(dom, mem_target)
-
-xm.prog(ProgSetMem)
-
-class ProgVcpuhotplug(Prog):
- group = 'domain'
- name = 'vcpu-hotplug'
- info = """Enable or disable a VCPU in a domain."""
-
- def help(self, args):
- print args[0], "DOM VCPU [0|1]"
- print """\nRequest virtual processor VCPU to be disabled or enabled in
-domain DOM"""
-
- def main(self, args):
- if len(args) != 4: self.err("%s: Invalid arguments(s)" % args[0])
- name = args[1]
- vcpu = int(args[2])
- state = int(args[3])
- dom = server.xend_domain(name)
- id = sxp.child_value(dom, 'id')
- server.xend_domain_vcpu_hotplug(id, vcpu, state)
-
-xm.prog(ProgVcpuhotplug)
-
-class ProgDomid(Prog):
- group = 'domain'
- name = 'domid'
- info = 'Convert a domain name to a domain id.'
-
- def help(self, args):
- print args[0], "DOM"
- print '\nGet the domain id for the domain with name DOM.'
-
- def main (self, args):
- if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
- name = args[1]
- dom = server.xend_domain(name)
- print sxp.child_value(dom, 'id')
-
-xm.prog(ProgDomid)
-
-class ProgDomname(Prog):
- group = 'domain'
- name = 'domname'
- info = 'Convert a domain id to a domain name.'
-
- def help(self, args):
- print args[0], "DOM"
- print '\nGet the name for the domain with id DOM.'
-
- def main (self, args):
- if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
- name = args[1]
- dom = server.xend_domain(name)
- print sxp.child_value(dom, 'name')
-
-xm.prog(ProgDomname)
-
-class ProgBvt(Prog):
- group = 'scheduler'
- name = "bvt"
- info = """Set BVT scheduler parameters."""
-
- def help(self, args):
- print args[0], "DOM MCUADV WARPBACK WARPVALUE WARPL WARPU"
- print '\nSet Borrowed Virtual Time scheduler parameters.'
-
- def main(self, args):
- if len(args) != 7: self.err("%s: Invalid argument(s)" % args[0])
- dom = args[1]
- v = map(long, args[2:7])
- server.xend_domain_cpu_bvt_set(dom, *v)
-
-xm.prog(ProgBvt)
-
-class ProgBvtslice(Prog):
- group = 'scheduler'
- name = "bvt_ctxallow"
- info = """Set the BVT scheduler context switch allowance."""
-
- def help(self, args):
- print args[0], 'CTX_ALLOW'
- print '\nSet Borrowed Virtual Time scheduler context switch allowance.'
-
- def main(self, args):
- if len(args) < 2: self.err('%s: Missing context switch allowance'
- % args[0])
- slice = int(args[1])
- server.xend_node_cpu_bvt_slice_set(slice)
-
-xm.prog(ProgBvtslice)
-
-class ProgSedf(Prog):
- group = 'scheduler'
- name= "sedf"
- info = """Set simple EDF parameters."""
-
- def help(self, args):
- print args[0], "DOM PERIOD SLICE LATENCY EXTRATIME WEIGHT"
- print "\nSet simple EDF parameters."
-
- def main(self, args):
- if len(args) != 7: self.err("%s: Invalid argument(s)" % args[0])
- dom = args[1]
- v = map(int, args[2:7])
- server.xend_domain_cpu_sedf_set(dom, *v)
-
-xm.prog(ProgSedf)
-
-class ProgInfo(Prog):
- group = 'host'
- name = "info"
- info = """Get information about the xen host."""
-
- def main(self, args):
- info = server.xend_node()
- for x in info[1:]:
- print "%-23s:" % x[0], x[1]
-
-xm.prog(ProgInfo)
-
-class ProgConsoles(Prog):
- group = 'console'
- name = "consoles"
- info = """Get information about domain consoles."""
-
- def main(self, args):
- l = server.xend_consoles()
- print "Dom Port Id Connection"
- for x in l:
- info = server.xend_console(x)
- d = {}
- d['dom'] = sxp.child(info, 'domain', '?')[1]
- d['port'] = sxp.child_value(info, 'console_port', '?')
- d['id'] = sxp.child_value(info, 'id', '?')
- connected = sxp.child(info, 'connected')
- if connected:
- d['conn'] = '%s:%s' % (connected[1], connected[2])
- else:
- d['conn'] = ''
- print "%(dom)3s %(port)4s %(id)3s %(conn)s" % d
-
-xm.prog(ProgConsoles)
+ d['conn'] = ''
+ print "%(dom)3s %(port)4s %(id)3s %(conn)s" % d
-class ProgConsole(Prog):
- group = 'console'
- name = "console"
- info = """Open a console to a domain."""
-
- def help(self, args):
- print args[0], "DOM"
- print "\nOpen a console to domain DOM."
-
- def main(self, args):
- if len(args) < 2: self.err("%s: Missing domain" % args[0])
- dom = args[1]
- info = server.xend_domain(dom)
- console = sxp.child(info, "console")
- if not console:
- self.err("No console information")
- port = sxp.child_value(console, "console_port")
- from xen.util import console_client
- path = "/var/lib/xend/console-%s" % port
- console_client.connect("localhost", int(port), path=path)
-
-xm.prog(ProgConsole)
-
-class ProgCall(Prog):
- name = "call"
- info = "Call xend api functions."
-
- def help (self, args):
- print args[0], "function args..."
- print """
- Call a xend HTTP API function. The leading 'xend_' on the function
-can be omitted. See xen.xend.XendClient for the API functions.
-"""
-
- def main(self, args):
- xend_client_main(args)
-
-xm.prog(ProgCall)
-
-class ProgDmesg(Prog):
- group = 'host'
- name = "dmesg"
- info = """Read or clear Xen's message buffer."""
+# TODO: remove as soon as console server shows up
+def xm_console(args):
+ arg_check(args,1,"console")
+
+ dom = args[0]
+ from xen.xend.XendClient import server
+ info = server.xend_domain(dom)
+ console = sxp.child(info, "console")
+ if not console:
+ err("No console found for domain %s" % dom)
+ sys.exit(1)
+ port = sxp.child_value(console, "console_port")
+ from xen.util import console_client
+ path = "/var/lib/xend/console-%s" % port
+ console_client.connect("localhost", int(port), path=path)
+def xm_dmesg(args):
+
gopts = Opts(use="""[-c|--clear]
Read Xen's message buffer (boot output, warning and error messages) or clear
@@ -775,161 +481,214 @@
gopts.opt('clear', short='c',
fn=set_true, default=0,
use="Clear the contents of the Xen message buffer.")
+ # Work around for gopts
+ args.insert(0,"bogus")
+ gopts.parse(args)
+ if not (1 <= len(args) <= 2):
+ err('Invalid arguments: ' + str(args))
+
+ from xen.xend.XendClient import server
+ if not gopts.vals.clear:
+ print server.xend_node_get_dmesg()
+ else:
+ server.xend_node_clear_dmesg()
- short_options = ['-c']
- long_options = ['--clear']
-
- def help(self, args):
- self.gopts.argv = args
- self.gopts.usage()
-
- def main(self, args):
- self.gopts.parse(args)
- if not (1 <= len(args) <=2):
- self.gopts.err('Invalid arguments: ' + str(args))
-
- if not self.gopts.vals.clear:
- print server.xend_node_get_dmesg()
- else:
- server.xend_node_clear_dmesg()
-
-xm.prog(ProgDmesg)
-
-class ProgLog(Prog):
- group = 'host'
- name = "log"
- info = """Print the xend log."""
-
- def main(self, args):
- print server.xend_node_log()
-
-xm.prog(ProgLog)
-
-class ProgVifCreditLimit(Prog):
- group = 'vif'
- name= "vif-limit"
- info = """Limit the transmission rate of a virtual network interface."""
-
- def help(self, args):
- print args[0], "DOMAIN VIF CREDIT_IN_BYTES PERIOD_IN_USECS"
- print "\nSet the credit limit of a virtual network interface."
-
- def main(self, args):
- if len(args) != 5: self.err("%s: Invalid argument(s)" % args[0])
- dom = args[1]
- v = map(int, args[2:5])
- server.xend_domain_vif_limit(dom, *v)
-
-xm.prog(ProgVifCreditLimit)
-
-class ProgVifList(Prog):
- group = 'vif'
- name = 'vif-list'
- info = """List virtual network interfaces for a domain."""
-
- def help(self, args):
- print args[0], "DOM"
- print "\nList virtual network interfaces for domain DOM"
-
- def main(self, args):
- if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
- dom = args[1]
- for x in server.xend_domain_devices(dom, 'vif'):
- sxp.show(x)
- print
+def xm_log(args):
+ from xen.xend.XendClient import server
+ print server.xend_node_log()
+
+def xm_network_limit(args):
+ arg_check(args,4,"network-limit")
+ dom = args[0]
+ v = map(int, args[1:4])
+ from xen.xend.XendClient import server
+ server.xend_domain_vif_limit(dom, *v)
+
+def xm_network_list(args):
+ arg_check(args,1,"network-list")
+ dom = args[0]
+ from xen.xend.XendClient import server
+ for x in server.xend_domain_devices(dom, 'vif'):
+ sxp.show(x)
+ print
+
+def xm_block_list(args):
+ arg_check(args,1,"block-list")
+ dom = args[0]
+ from xen.xend.XendClient import server
+ for x in server.xend_domain_devices(dom, 'vbd'):
+ sxp.show(x)
+ print
+
+def xm_block_create(args):
+ n = len(args)
+ if n < 4 or n > 5:
+ err("%s: Invalid argument(s)" % args[0])
+ usage("block-create")
+
+ dom = args[0]
+ vbd = ['vbd',
+ ['uname', args[1]],
+ ['dev', args[2]],
+ ['mode', args[3]]]
+ if n == 5:
+ vbd.append(['backend', args[4]])
+
+ from xen.xend.XendClient import server
+ server.xend_domain_device_create(dom, vbd)
+
+def xm_block_refresh(args):
+ arg_check(args,2,"block-refresh")
+
+ dom = args[0]
+ dev = args[1]
+
+ from xen.xend.XendClient import server
+ server.xend_domain_device_refresh(dom, 'vbd', dev)
+
+def xm_block_destroy(args):
+ arg_check(args,2,"block-destroy")
+
+ dom = args[0]
+ dev = args[1]
+
+ from xen.xend.XendClient import server
+ server.xend_domain_device_destroy(dom, 'vbd', dev)
+
+commands = {
+ # console commands
+ "console": xm_console,
+ "console-list": xm_console_list,
+ # domain commands
+ "domid": xm_domid,
+ "domname": xm_domname,
+ "create": xm_create,
+ "destroy": xm_destroy,
+ "restore": xm_restore,
+ "save": xm_save,
+ "shutdown": xm_shutdown,
+ "reboot": xm_reboot,
+ "list": xm_list,
+ # memory commands
+ "mem-max": xm_mem_max,
+ "mem-set": xm_mem_set,
+ # cpu commands
+ "cpus-set": xm_cpus_set,
+# "cpus-list": xm_cpus_list,
+ "vcpu-enable": xm_vcpu_enable,
+ "vcpu-disable": xm_vcpu_disable,
+ "vcpu-list": xm_vcpu_list,
+ # migration
+ "migrate": xm_migrate,
+ # special
+ "sysrq": xm_sysrq,
+ "pause": xm_pause,
+ "unpause": xm_unpause,
+ # host commands
+ "dmesg": xm_dmesg,
+ "info": xm_info,
+ "log": xm_log,
+ # scheduler
+ "bvt": xm_bvt,
+ "bvt_ctxallow": xm_bvt_ctxallow,
+ "sedf": xm_sedf,
+ # block
+ "block-create": xm_block_create,
+ "block-destroy": xm_block_destroy,
+ "block-list": xm_block_list,
+ "block-refresh": xm_block_refresh,
+ # network
+ "network-limit": xm_network_limit,
+ "network-list": xm_network_list
+ }
+
+aliases = {
+ "balloon": "mem-set",
+ "vif-list": "network-list",
+ "vif-limit": "network-limit",
+ "vbd-create": "block-create",
+ "vbd-destroy": "block-destroy",
+ "vbd-list": "block-list",
+ "vbd-refresh": "block-refresh",
+ "consoles": "console-list",
+ }
+
+help = {
+ "--long": longhelp
+ }
+
+def xm_lookup_cmd(cmd):
+ if commands.has_key(cmd):
+ return commands[cmd]
+ elif aliases.has_key(cmd):
+ deprecated(cmd,aliases[cmd])
+ return commands[aliases[cmd]]
+ else:
+ err('Sub Command %s not found!' % cmd)
+ usage()
-xm.prog(ProgVifList)
+def deprecated(old,new):
+ err('Option %s is deprecated, and will be removed in future!!!' % old)
+ err('Option %s is the new replacement, see "xm help %s" for more info' %
(new, new))
+
+def usage(cmd=None):
+ if cmd == "full":
+ print fullhelp
+ elif help.has_key(cmd):
+ print help[cmd]
+ else:
+ print shorthelp
+ sys.exit(1)
-class ProgVbdList(Prog):
- group = 'vbd'
- name = 'vbd-list'
- info = """List virtual block devices for a domain."""
-
- def help(self, args):
- print args[0], "DOM"
- print "\nList virtual block devices for domain DOM"
-
- def main(self, args):
- if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
- dom = args[1]
- for x in server.xend_domain_devices(dom, 'vbd'):
- sxp.show(x)
+def main(argv=sys.argv):
+ if len(argv) < 2:
+ usage()
+
+ if re.compile('-*help').match(argv[1]):
+ if len(argv) > 2 and help.has_key(argv[2]):
+ usage(argv[2])
+ else:
+ usage()
+ sys.exit(0)
+
+ cmd = xm_lookup_cmd(argv[1])
+
+ # strip off prog name and subcmd
+ args = argv[2:]
+ if cmd:
+ try:
+ from xen.xend.XendClient import XendError
+ rc = cmd(args)
+ if rc:
+ usage()
+ except socket.error, ex:
+ print >>sys.stderr, ex
+ err("Error connecting to xend, is xend running?")
+ sys.exit(1)
+ except IOError:
+ err("Most commands need root access. Please try again as root")
+ sys.exit(1)
+ except XendError, ex:
+ if len(args) > 0:
+ handle_xend_error(argv[1], args[0], ex)
+ else:
+ print "Unexpected error:", sys.exc_info()[0]
+ print
+ print "Please report to xen-devel@xxxxxxxxxxxxxxxxxxx"
+ raise
+ except SystemExit:
+ sys.exit(1)
+ except:
+ print "Unexpected error:", sys.exc_info()[0]
print
+ print "Please report to xen-devel@xxxxxxxxxxxxxxxxxxx"
+ raise
+
+ else:
+ usage()
-xm.prog(ProgVbdList)
-
-class ProgVbdCreate(Prog):
- group = 'vbd'
- name = 'vbd-create'
- info = """Create a new virtual block device for a domain"""
-
- def help(self, args):
- print args[0], "DOM UNAME DEV MODE [BACKEND]"
- print """
-Create a virtual block device for a domain.
-
- UNAME - device to export, e.g. phy:hda2
- DEV - device name in the domain, e.g. sda1
- MODE - access mode: r for read, w for read-write
- BACKEND - backend driver domain
-"""
-
- def main(self, args):
- n = len(args)
- if n < 5 or n > 6: self.err("%s: Invalid argument(s)" % args[0])
- dom = args[1]
- vbd = ['vbd',
- ['uname', args[2]],
- ['dev', args[3]],
- ['mode', args[4]]]
- if n == 6:
- vbd.append(['backend', args[5]])
- server.xend_domain_device_create(dom, vbd)
-
-xm.prog(ProgVbdCreate)
-
-class ProgVbdRefresh(Prog):
- group = 'vbd'
- name = 'vbd-refresh'
- info = """Refresh a virtual block device for a domain"""
-
- def help(self, args):
- print args[0], "DOM DEV"
- print """
-Refresh a virtual block device for a domain.
-
- DEV - idx field in the device information
-"""
+if __name__ == "__main__":
+ main()
- def main(self, args):
- if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
- dom = args[1]
- dev = args[2]
- server.xend_domain_device_refresh(dom, 'vbd', dev)
-
-xm.prog(ProgVbdRefresh)
-
-
-class ProgVbdDestroy(Prog):
- group = 'vbd'
- name = 'vbd-destroy'
- info = """Destroy a domain's virtual block device"""
-
- def help(self, args):
- print args[0], "DOM DEV"
- print """
-Destroy vbd DEV attached to domain DOM. Detaches the device
-from the domain, but does not destroy the device contents.
-The device indentifier DEV is the idx field in the device
-information. This is visible in 'xm vbd-list'."""
-
- def main(self, args):
- if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
- dom = args[1]
- dev = args[2]
- server.xend_domain_device_destroy(dom, 'vbd', dev)
-xm.prog(ProgVbdDestroy)
-def main(args):
- xm.main(args)
-Sean
--
__________________________________________________________________
Sean Dague Mid-Hudson Valley
sean at dague dot net Linux Users Group
http://dague.net http://mhvlug.org
There is no silver bullet. Plus, werewolves make better neighbors
than zombies, and they tend to keep the vampire population down.
__________________________________________________________________
pgp79T3RF8zZR.pgp
Description: PGP signature
_______________________________________________
Xen-tools mailing list
Xen-tools@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-tools
|