ia64/xen-unstable

changeset 11576:ad22c711ccb7

[XM] Error handling cleanup

Introducing an OptionError exception to be used by all xm subcommands
to signal an error in the arguments. "xm" will catch these and output
the appropriate error and usage message.

Detailed Changes:

main.py:
* Cleaned up imports and moved warning filter outside of
import block.
* Converted usage parameters and description to a python
dict rather than strings to enable better usage help
formatting.
* Removed unused list_label domain command.
* Added cmdHelp() prints out usage message for any command
* Added shortHelp() prints out the default help message when
xm is invoked with no arguments.
* Added longHelp() prints out long help message when invoked
with xm --help or xm help.
* Added extra optional paramter to getDomains() so we can
tell Xend not to poll devices. This will speed up xm list.
(PENDING changes to Xend itself.)
* Changed all references where 'dom' actually means 'domid'
to use the correct name.
* Changed 'xm list' header format to use printf formatting style.
* Renamed xm_subcommand to xm_importcommand so it is more
clear what it is doing (all xm commands are subcommands!)
* Moved cpu_make_map() inside xm_vcpu_pin as an anonymous func.
* Use OptionError whenever an invalid option is detected in xm.
* Added proper catch and error printing for XendError and
OptionErrors in main().

addlabel.py:
cfgbootpolicy.py:
dry-run.py:
dump-policy.py:
get-label.py:
labels.py:
loadpolicy.py:
makepolicy.py:
rmlabel.py:
resources.py:
* Replaced usage() with help() that is called from main.py
* Replaced usage() invokation with raising OptionError

opts.py:
* Added very simple wrap() function that behaves differently
to textwrap.wrap()
* Added OptionError()
* Replaced the string representation of Opt, Opts to output
a nicely formatted usage message.
* Changed class Opts itself will throw approriate OptionErrors.
* Changed set_bool to recognise 'y' and 'n' as valid input

create.py:
* Some whitespace and column width cleanup.
* throws OptionError if encounters option error.

migrate.py:
* Replace usage() message with the string representation of
gopts.

sysrq.py:
* Replace usage message with throwing OptionErrors

Signed-off-by: Alastair Tse <atse@xensource.com>
author atse@norwich.uk.xensource.com
date Fri Sep 22 11:37:31 2006 +0100 (2006-09-22)
parents a753630a6456
children 3236311a23a5
files tools/python/xen/xm/addlabel.py tools/python/xen/xm/cfgbootpolicy.py tools/python/xen/xm/console.py tools/python/xen/xm/create.py tools/python/xen/xm/dry-run.py tools/python/xen/xm/dumppolicy.py tools/python/xen/xm/getlabel.py tools/python/xen/xm/labels.py tools/python/xen/xm/loadpolicy.py tools/python/xen/xm/main.py tools/python/xen/xm/makepolicy.py tools/python/xen/xm/migrate.py tools/python/xen/xm/opts.py tools/python/xen/xm/resources.py tools/python/xen/xm/rmlabel.py tools/python/xen/xm/sysrq.py
line diff
     1.1 --- a/tools/python/xen/xm/addlabel.py	Fri Sep 22 11:33:03 2006 +0100
     1.2 +++ b/tools/python/xen/xm/addlabel.py	Fri Sep 22 11:37:31 2006 +0100
     1.3 @@ -19,19 +19,23 @@
     1.4  
     1.5  """Labeling a domain configuration file or a resoruce.
     1.6  """
     1.7 -import sys, os
     1.8 +import os
     1.9 +import sys
    1.10 +
    1.11  from xen.util import dictio
    1.12  from xen.util import security
    1.13 +from xen.xm.opts import OptionError
    1.14  
    1.15 -def usage():
    1.16 -    print "\nUsage: xm addlabel <label> dom <configfile> [<policy>]"
    1.17 -    print "       xm addlabel <label> res <resource> [<policy>]\n"
    1.18 -    print "  This program adds an acm_label entry into the 'configfile'"
    1.19 -    print "  for a domain or to the global resource label file for a"
    1.20 -    print "  resource. It derives the policy from the running hypervisor"
    1.21 -    print "  if it is not given (optional parameter). If a label already"
    1.22 -    print "  exists for the given domain or resource, then addlabel fails.\n"
    1.23 -    security.err("Usage")
    1.24 +def help():
    1.25 +    return """
    1.26 +    Format: xm addlabel <label> dom <configfile> [<policy>]
    1.27 +            xm addlabel <label> res <resource> [<policy>]
    1.28 +    
    1.29 +    This program adds an acm_label entry into the 'configfile'
    1.30 +    for a domain or to the global resource label file for a
    1.31 +    resource. It derives the policy from the running hypervisor
    1.32 +    if it is not given (optional parameter). If a label already
    1.33 +    exists for the given domain or resource, then addlabel fails."""
    1.34  
    1.35  
    1.36  def validate_config_file(configfile):
    1.37 @@ -114,9 +118,8 @@ def add_domain_label(label, configfile, 
    1.38  def main (argv):
    1.39      try:
    1.40          policyref = None
    1.41 -        if len(argv) not in [4,5]:
    1.42 -            usage()
    1.43 -            return
    1.44 +        if len(argv) not in (4, 5):
    1.45 +            raise OptionError('Needs either 2 or 3 arguments')
    1.46  
    1.47          label = argv[1]
    1.48  
    1.49 @@ -135,20 +138,20 @@ def main (argv):
    1.50                      if os.path.isfile(configfile):
    1.51                          break
    1.52              if not validate_config_file(configfile):
    1.53 -                usage()
    1.54 +                raise OptionError('Invalid config file')
    1.55              else:
    1.56                  add_domain_label(label, configfile, policyref)
    1.57          elif argv[2].lower() == "res":
    1.58              resource = argv[3]
    1.59              add_resource_label(label, resource, policyref)
    1.60          else:
    1.61 -            usage()
    1.62 -
    1.63 +            raise OptionError('Need to specify either "dom" or "res" as object to add label to.')
    1.64 +            
    1.65      except security.ACMError:
    1.66          sys.exit(-1)
    1.67  
    1.68 -
    1.69  if __name__ == '__main__':
    1.70      main(sys.argv)
    1.71 +    
    1.72  
    1.73  
     2.1 --- a/tools/python/xen/xm/cfgbootpolicy.py	Fri Sep 22 11:33:03 2006 +0100
     2.2 +++ b/tools/python/xen/xm/cfgbootpolicy.py	Fri Sep 22 11:37:31 2006 +0100
     2.3 @@ -28,20 +28,17 @@ from xen.util.security import ACMError, 
     2.4  from xen.util.security import policy_dir_prefix, boot_filename, xen_title_re
     2.5  from xen.util.security import any_title_re, xen_kernel_re, kernel_ver_re, any_module_re
     2.6  from xen.util.security import empty_line_re, binary_name_re, policy_name_re
     2.7 -
     2.8 +from xen.xm.opts import OptionError
     2.9  
    2.10 -def usage():
    2.11 -    print "\nUsage: xm cfgbootpolicy <policy> [<kernelversion>]\n"
    2.12 -    print "  Adds a 'module' line to the Xen grub.conf entry"
    2.13 -    print "  so that xen boots into a specific access control"
    2.14 -    print "  policy. If kernelversion is not given, then this"
    2.15 -    print "  script tries to determine it by looking for a grub"
    2.16 -    print "  entry with a line kernel xen.* If there are multiple"
    2.17 -    print "  Xen entries, then it must be called with an explicit"
    2.18 -    print "  version (it will fail otherwise).\n"
    2.19 -    err("Usage")
    2.20 -
    2.21 -
    2.22 +def help():
    2.23 +    return """
    2.24 +    Adds a 'module' line to the Xen grub.conf entry
    2.25 +    so that xen boots into a specific access control
    2.26 +    policy. If kernelversion is not given, then this
    2.27 +    script tries to determine it by looking for a grub
    2.28 +    entry with a line kernel xen.* If there are multiple
    2.29 +    Xen entries, then it must be called with an explicit
    2.30 +    version (it will fail otherwise).\n"""
    2.31  
    2.32  def determine_kernelversion(user_specified):
    2.33      within_xen_title = 0
    2.34 @@ -152,7 +149,7 @@ def main(argv):
    2.35              policy = argv[1]
    2.36              user_kver = argv[2]
    2.37          else:
    2.38 -            usage()
    2.39 +            raise OptionError('Invalid number of arguments')
    2.40  
    2.41          if not policy_name_re.match(policy):
    2.42              err("Illegal policy name \'" + policy + "\'")
     3.1 --- a/tools/python/xen/xm/console.py	Fri Sep 22 11:33:03 2006 +0100
     3.2 +++ b/tools/python/xen/xm/console.py	Fri Sep 22 11:37:31 2006 +0100
     3.3 @@ -18,9 +18,7 @@
     3.4  
     3.5  XENCONSOLE = "xenconsole"
     3.6  
     3.7 -
     3.8  import xen.util.auxbin
     3.9  
    3.10 -
    3.11  def execConsole(domid):
    3.12      xen.util.auxbin.execute(XENCONSOLE, [str(domid)])
     4.1 --- a/tools/python/xen/xm/create.py	Fri Sep 22 11:33:03 2006 +0100
     4.2 +++ b/tools/python/xen/xm/create.py	Fri Sep 22 11:37:31 2006 +0100
     4.3 @@ -25,7 +25,6 @@ import sys
     4.4  import socket
     4.5  import re
     4.6  import xmlrpclib
     4.7 -import traceback
     4.8  
     4.9  from xen.xend import sxp
    4.10  from xen.xend import PrettyPrint
    4.11 @@ -65,35 +64,36 @@ gopts.opt('quiet', short='q',
    4.12  
    4.13  gopts.opt('path', val='PATH',
    4.14            fn=set_value, default='.:/etc/xen',
    4.15 -          use="""Search path for configuration scripts.
    4.16 -         The value of PATH is a colon-separated directory list.""")
    4.17 +          use="Search path for configuration scripts. "
    4.18 +          "The value of PATH is a colon-separated directory list.")
    4.19  
    4.20  gopts.opt('defconfig', short='f', val='FILE',
    4.21            fn=set_value, default='xmdefconfig',
    4.22 -          use="""Use the given Python configuration script.
    4.23 -          The configuration script is loaded after arguments have been processed.
    4.24 -          Each command-line option sets a configuration variable named after
    4.25 -          its long option name, and these variables are placed in the
    4.26 -          environment of the script before it is loaded.
    4.27 -          Variables for options that may be repeated have list values.
    4.28 -          Other variables can be set using VAR=VAL on the command line.
    4.29 -        
    4.30 -          After the script is loaded, option values that were not set on the
    4.31 -          command line are replaced by the values set in the script.""")
    4.32 +          use="Use the given Python configuration script."
    4.33 +          "The configuration script is loaded after arguments have been "
    4.34 +          "processed. Each command-line option sets a configuration "
    4.35 +          "variable named after its long option name, and these "
    4.36 +          "variables are placed in the environment of the script before "
    4.37 +          "it is loaded. Variables for options that may be repeated have "
    4.38 +          "list values. Other variables can be set using VAR=VAL on the "
    4.39 +          "command line. "     
    4.40 +          "After the script is loaded, option values that were not set "
    4.41 +          "on the command line are replaced by the values set in the script.")
    4.42  
    4.43  gopts.default('defconfig')
    4.44  
    4.45  gopts.opt('config', short='F', val='FILE',
    4.46            fn=set_value, default=None,
    4.47 -          use="""Domain configuration to use (SXP).
    4.48 -          SXP is the underlying configuration format used by Xen.
    4.49 -          SXP configurations can be hand-written or generated from Python configuration
    4.50 -          scripts, using the -n (dryrun) option to print the configuration.""")
    4.51 +          use="Domain configuration to use (SXP).\n"
    4.52 +          "SXP is the underlying configuration format used by Xen.\n"
    4.53 +          "SXP configurations can be hand-written or generated from Python "
    4.54 +          "configuration scripts, using the -n (dryrun) option to print\n"
    4.55 +          "the configuration.")
    4.56  
    4.57  gopts.opt('dryrun', short='n',
    4.58            fn=set_true, default=0,
    4.59 -          use="""Dry run - print the configuration but don't create the domain.
    4.60 -          Loads the configuration script, creates the SXP configuration and prints it.""")
    4.61 +          use="Dry run - prints the resulting configuration in SXP but "
    4.62 +          "does not create the domain.")
    4.63  
    4.64  gopts.opt('paused', short='p',
    4.65            fn=set_true, default=0,
    4.66 @@ -105,18 +105,16 @@ gopts.opt('console_autoconnect', short='
    4.67  
    4.68  gopts.var('vncviewer', val='no|yes',
    4.69            fn=set_bool, default=None,
    4.70 -          use="""Spawn a vncviewer listening for a vnc server in the domain.
    4.71 -          The address of the vncviewer is passed to the domain on the kernel command
    4.72 -          line using 'VNC_SERVER=<host>:<port>'. The port used by vnc is 5500 + DISPLAY.
    4.73 -          A display value with a free port is chosen if possible.
    4.74 -          Only valid when vnc=1.
    4.75 -          """)
    4.76 +           use="Spawn a vncviewer listening for a vnc server in the domain.\n"
    4.77 +           "The address of the vncviewer is passed to the domain on the "
    4.78 +           "kernel command line using 'VNC_SERVER=<host>:<port>'. The port "
    4.79 +           "used by vnc is 5500 + DISPLAY. A display value with a free port "
    4.80 +           "is chosen if possible.\nOnly valid when vnc=1.")
    4.81  
    4.82  gopts.var('vncconsole', val='no|yes',
    4.83            fn=set_bool, default=None,
    4.84 -          use="""Spawn a vncviewer process for the domain's graphical console.
    4.85 -          Only valid when vnc=1.
    4.86 -          """)
    4.87 +          use="Spawn a vncviewer process for the domain's graphical console.\n"
    4.88 +          "Only valid when vnc=1.")
    4.89  
    4.90  gopts.var('name', val='NAME',
    4.91            fn=set_value, default=None,
    4.92 @@ -440,7 +438,6 @@ gopts.var('uuid', val='',
    4.93            addresses for virtual network interfaces.  This must be a unique 
    4.94            value across the entire cluster.""")
    4.95  
    4.96 -
    4.97  def err(msg):
    4.98      """Print an error to stderr and exit.
    4.99      """
   4.100 @@ -490,7 +487,6 @@ def configure_disks(config_devs, vals):
   4.101      """Create the config for disks (virtual block devices).
   4.102      """
   4.103      for (uname, dev, mode, backend) in vals.disk:
   4.104 -
   4.105          if uname.startswith('tap:'):
   4.106              cls = 'tap'
   4.107          else:
   4.108 @@ -851,7 +847,6 @@ def choose_vnc_display():
   4.109          if port in ports: continue
   4.110          return d
   4.111      return None
   4.112 -
   4.113  vncpid = None
   4.114  
   4.115  def daemonize(prog, args):
   4.116 @@ -885,7 +880,6 @@ def daemonize(prog, args):
   4.117              w.write(str(pid2 or 0))
   4.118              w.close()
   4.119              os._exit(0)
   4.120 -
   4.121      os.close(w)
   4.122      r = os.fdopen(r)
   4.123      daemon_pid = int(r.read())
   4.124 @@ -904,6 +898,7 @@ def spawn_vnc(display):
   4.125      vncpid = daemonize("vncviewer", vncargs)
   4.126      if vncpid == 0:
   4.127          return 0
   4.128 +
   4.129      return VNC_BASE_PORT + display
   4.130  
   4.131  def preprocess_vnc(vals):
   4.132 @@ -1091,7 +1086,6 @@ def check_domain_label(config, verbose):
   4.133  
   4.134      return answer
   4.135  
   4.136 -
   4.137  def config_security_check(config, verbose):
   4.138      """Checks each resource listed in the config to see if the active
   4.139         policy will permit creation of a new domain using the config.
   4.140 @@ -1145,7 +1139,6 @@ def config_security_check(config, verbos
   4.141  
   4.142      return answer
   4.143  
   4.144 -
   4.145  def create_security_check(config):
   4.146      passed = 0
   4.147      try:
   4.148 @@ -1158,7 +1151,9 @@ def create_security_check(config):
   4.149          sys.exit(-1)
   4.150  
   4.151      return passed
   4.152 -
   4.153 +  
   4.154 +def help():
   4.155 +    return str(gopts)
   4.156  
   4.157  def main(argv):
   4.158      try:
   4.159 @@ -1176,11 +1171,11 @@ def main(argv):
   4.160          PrettyPrint.prettyprint(config)
   4.161      else:
   4.162          if not create_security_check(config):
   4.163 -            err("Security configuration prevents domain from starting.")
   4.164 +            raise OptionError('Security Configuration prevents domain from starting')
   4.165          else:
   4.166              dom = make_domain(opts, config)
   4.167              if opts.vals.console_autoconnect:
   4.168 -                console.execConsole(dom)
   4.169 -        
   4.170 +                console.execConsole(dom)        
   4.171 +             
   4.172  if __name__ == '__main__':
   4.173      main(sys.argv)
     5.1 --- a/tools/python/xen/xm/dry-run.py	Fri Sep 22 11:33:03 2006 +0100
     5.2 +++ b/tools/python/xen/xm/dry-run.py	Fri Sep 22 11:37:31 2006 +0100
     5.3 @@ -22,20 +22,18 @@ import sys
     5.4  from xen.util import security
     5.5  from xen.xm import create
     5.6  from xen.xend import sxp
     5.7 +from xen.xm.opts import OptionError
     5.8  
     5.9 -def usage():
    5.10 -    print "\nUsage: xm dry-run <configfile>\n"
    5.11 -    print "This program checks each resource listed in the configfile"
    5.12 -    print "to see if the domain created by the configfile can access"
    5.13 -    print "the resources.  The status of each resource is listed"
    5.14 -    print "individually along with the final security decision.\n"
    5.15 -    security.err("Usage")
    5.16 -
    5.17 +def help():
    5.18 +    return """
    5.19 +    This program checks each resource listed in the configfile
    5.20 +    to see if the domain created by the configfile can access
    5.21 +    the resources.  The status of each resource is listed
    5.22 +    individually along with the final security decision."""
    5.23  
    5.24  def main (argv):
    5.25 -    try:
    5.26 -        if len(argv) != 2:
    5.27 -            usage()
    5.28 +    if len(argv) != 2:
    5.29 +        raise OptionError('Invalid number of arguments')
    5.30  
    5.31          passed = 0
    5.32          (opts, config) = create.parseCommandLine(argv)
     6.1 --- a/tools/python/xen/xm/dumppolicy.py	Fri Sep 22 11:33:03 2006 +0100
     6.2 +++ b/tools/python/xen/xm/dumppolicy.py	Fri Sep 22 11:37:31 2006 +0100
     6.3 @@ -21,12 +21,10 @@ import sys
     6.4  from xen.util.security import ACMError, err, dump_policy
     6.5  
     6.6  
     6.7 -def usage():
     6.8 -    print "\nUsage: xm dumppolicy\n"
     6.9 -    print " Retrieve and print currently enforced"
    6.10 -    print " hypervisor policy information (low-level).\n"
    6.11 -    err("Usage")
    6.12 -
    6.13 +def help():
    6.14 +    return """
    6.15 +    Retrieve and print currently enforced hypervisor policy information
    6.16 +    (low-level)."""
    6.17  
    6.18  def main(argv):
    6.19      try:
    6.20 @@ -34,7 +32,6 @@ def main(argv):
    6.21              usage()
    6.22  
    6.23          dump_policy()
    6.24 -
    6.25      except ACMError:
    6.26          sys.exit(-1)
    6.27  
     7.1 --- a/tools/python/xen/xm/getlabel.py	Fri Sep 22 11:33:03 2006 +0100
     7.2 +++ b/tools/python/xen/xm/getlabel.py	Fri Sep 22 11:37:31 2006 +0100
     7.3 @@ -21,13 +21,13 @@
     7.4  import sys, os, re
     7.5  from xen.util import dictio
     7.6  from xen.util import security
     7.7 +from xen.xm.opts import OptionError
     7.8  
     7.9 -def usage():
    7.10 -    print "\nUsage: xm getlabel dom <configfile>"
    7.11 -    print "       xm getlabel res <resource>\n"
    7.12 -    print "  This program shows the label for a domain or resource.\n"
    7.13 -    security.err("Usage")
    7.14 -
    7.15 +def help():
    7.16 +    return """
    7.17 +    Usage: xm getlabel dom <configfile>"
    7.18 +           xm getlabel res <resource>\n"
    7.19 +    This program shows the label for a domain or resource."""
    7.20  
    7.21  def get_resource_label(resource):
    7.22      """Gets the resource label
    7.23 @@ -90,21 +90,17 @@ def get_domain_label(configfile):
    7.24  
    7.25  
    7.26  def main (argv):
    7.27 -    try:
    7.28 -        if len(argv) != 3:
    7.29 -            usage()
    7.30 +    if len(argv) != 3:
    7.31 +        raise OptionError('Requires 2 arguments')
    7.32  
    7.33 -        if argv[1].lower() == "dom":
    7.34 -            configfile = argv[2]
    7.35 -            get_domain_label(configfile)
    7.36 -        elif argv[1].lower() == "res":
    7.37 -            resource = argv[2]
    7.38 -            get_resource_label(resource)
    7.39 -        else:
    7.40 -            usage()
    7.41 -
    7.42 -    except security.ACMError:
    7.43 -        sys.exit(-1)
    7.44 +    if argv[1].lower() == "dom":
    7.45 +        configfile = argv[2]
    7.46 +        get_domain_label(configfile)
    7.47 +    elif argv[1].lower() == "res":
    7.48 +        resource = argv[2]
    7.49 +        get_resource_label(resource)
    7.50 +    else:
    7.51 +        raise OptionError('First subcommand argument must be "dom" or "res"')
    7.52  
    7.53  if __name__ == '__main__':
    7.54      main(sys.argv)
     8.1 --- a/tools/python/xen/xm/labels.py	Fri Sep 22 11:33:03 2006 +0100
     8.2 +++ b/tools/python/xen/xm/labels.py	Fri Sep 22 11:37:31 2006 +0100
     8.3 @@ -23,49 +23,46 @@ import traceback
     8.4  import string
     8.5  from xen.util.security import ACMError, err, list_labels, active_policy
     8.6  from xen.util.security import vm_label_re, res_label_re, all_label_re
     8.7 +from xen.xm.opts import OptionError
     8.8  
     8.9 -def usage():
    8.10 -    print "\nUsage: xm labels [<policy>] [<type=dom|res|any>]\n"
    8.11 -    print " Prints labels of the specified type (default is dom)"
    8.12 -    print " that are defined in policy (default is current"
    8.13 -    print " hypervisor policy).\n"
    8.14 -    err("Usage")
    8.15  
    8.16 +def help():
    8.17 +    return """
    8.18 +    Prints labels of the specified type (default is dom)
    8.19 +    that are defined in policy (default is current hypervisor policy)."""
    8.20  
    8.21  def main(argv):
    8.22 +    policy = None
    8.23 +    ptype = None
    8.24 +    for arg in argv[1:]:
    8.25 +        key_val = arg.split('=')
    8.26 +        if len(key_val) == 2 and key_val[0] == 'type':
    8.27 +            if ptype:
    8.28 +                raise OptionError('type is definied twice')
    8.29 +            ptype = key_val[1].lower()
    8.30 +
    8.31 +        elif len(key_val) == 1:
    8.32 +            if policy:
    8.33 +                raise OptionError('policy is defined twice')
    8.34 +            policy = arg
    8.35 +        else:
    8.36 +            raise OptionError('Unrecognised option: %s' % arg)
    8.37 +
    8.38 +    if not policy:
    8.39 +        policy = active_policy
    8.40 +        if active_policy in ['NULL', 'INACTIVE', 'DEFAULT']:
    8.41 +            raise OptionError('No policy active, you must specify a <policy>')
    8.42 +
    8.43 +    if not ptype or ptype == 'dom':
    8.44 +        condition = vm_label_re
    8.45 +    elif ptype == 'res':
    8.46 +        condition = res_label_re
    8.47 +    elif ptype == 'any':
    8.48 +        condition = all_label_re
    8.49 +    else:
    8.50 +        err("Unknown label type \'" + ptype + "\'")
    8.51 +
    8.52      try:
    8.53 -        policy = None
    8.54 -        type = None
    8.55 -        for i in argv[1:]:
    8.56 -            i_s = string.split(i, '=')
    8.57 -            if len(i_s) > 1:
    8.58 -                if (i_s[0] == 'type') and (len(i_s) == 2):
    8.59 -                    if not type:
    8.60 -                        type = i_s[1]
    8.61 -                    else:
    8.62 -                        usage()
    8.63 -                else:
    8.64 -                    usage()
    8.65 -            else:
    8.66 -                if not policy:
    8.67 -                    policy = i
    8.68 -                else:
    8.69 -                    usage()
    8.70 -
    8.71 -        if not policy:
    8.72 -            policy = active_policy
    8.73 -            if active_policy in ['NULL', 'INACTIVE', 'DEFAULT']:
    8.74 -                err("No policy active. Please specify the <policy> parameter.")
    8.75 -
    8.76 -        if not type or (type in ['DOM', 'dom']):
    8.77 -            condition = vm_label_re
    8.78 -        elif type in ['RES', 'res']:
    8.79 -            condition = res_label_re
    8.80 -        elif type in ['ANY', 'any']:
    8.81 -            condition = all_label_re
    8.82 -        else:
    8.83 -            err("Unknown label type \'" + type + "\'")
    8.84 -
    8.85          labels = list_labels(policy, condition)
    8.86          labels.sort()
    8.87          for label in labels:
    8.88 @@ -74,9 +71,7 @@ def main(argv):
    8.89      except ACMError:
    8.90          sys.exit(-1)
    8.91      except:
    8.92 -        traceback.print_exc(limit=1)
    8.93 -        sys.exit(-1)
    8.94 -
    8.95 +        traceback.print_exc(limit = 1)
    8.96  
    8.97  if __name__ == '__main__':
    8.98      main(sys.argv)
     9.1 --- a/tools/python/xen/xm/loadpolicy.py	Fri Sep 22 11:33:03 2006 +0100
     9.2 +++ b/tools/python/xen/xm/loadpolicy.py	Fri Sep 22 11:37:31 2006 +0100
     9.3 @@ -21,26 +21,23 @@
     9.4  import sys
     9.5  import traceback
     9.6  from xen.util.security import ACMError, err, load_policy
     9.7 -
     9.8 +from xen.xm.opts import OptionError
     9.9  
    9.10 -def usage():
    9.11 -    print "\nUsage: xm loadpolicy <policy>\n"
    9.12 -    print " Load the compiled binary (.bin) policy"
    9.13 -    print " into the running hypervisor.\n"
    9.14 -    err("Usage")
    9.15 +def help():
    9.16 +    return """Load the compiled binary (.bin) policy into the running
    9.17 +    hypervisor."""
    9.18  
    9.19  def main(argv):
    9.20 +    if len(argv) != 2:
    9.21 +        raise OptionError('No policy defined')
    9.22 +    
    9.23      try:
    9.24 -        if len(argv) != 2:
    9.25 -            usage()
    9.26          load_policy(argv[1])
    9.27  
    9.28      except ACMError:
    9.29          sys.exit(-1)
    9.30      except:
    9.31 -        traceback.print_exc(limit=1)
    9.32 -        sys.exit(-1)
    9.33 -
    9.34 +        traceback.print_exc(limit = 1)
    9.35  
    9.36  if __name__ == '__main__':
    9.37      main(sys.argv)
    10.1 --- a/tools/python/xen/xm/main.py	Fri Sep 22 11:33:03 2006 +0100
    10.2 +++ b/tools/python/xen/xm/main.py	Fri Sep 22 11:37:31 2006 +0100
    10.3 @@ -22,28 +22,27 @@
    10.4  """Grand unified management application for Xen.
    10.5  """
    10.6  import os
    10.7 -import os.path
    10.8  import sys
    10.9  import re
   10.10  import getopt
   10.11  import socket
   10.12 -import warnings
   10.13 -warnings.filterwarnings('ignore', category=FutureWarning)
   10.14 +import traceback
   10.15  import xmlrpclib
   10.16  import traceback
   10.17  import datetime
   10.18 +from select import select
   10.19  
   10.20 -import xen.xend.XendProtocol
   10.21 +import warnings
   10.22 +warnings.filterwarnings('ignore', category=FutureWarning)
   10.23  
   10.24  from xen.xend import PrettyPrint
   10.25  from xen.xend import sxp
   10.26 -from xen.xm.opts import *
   10.27 +from xen.xend import XendClient
   10.28 +from xen.xend.XendClient import server
   10.29  
   10.30 -import console
   10.31 -import xen.xend.XendClient
   10.32 -from xen.xend.XendClient import server
   10.33 +from xen.xm.opts import OptionError, Opts, wrap, set_true
   10.34 +from xen.xm import console
   10.35  from xen.util import security
   10.36 -from select import select
   10.37  
   10.38  # getopt.gnu_getopt is better, but only exists in Python 2.3+.  Use
   10.39  # getopt.getopt if gnu_getopt is not available.  This will mean that options
   10.40 @@ -51,93 +50,148 @@ from select import select
   10.41  if not hasattr(getopt, 'gnu_getopt'):
   10.42      getopt.gnu_getopt = getopt.getopt
   10.43  
   10.44 +# General help message
   10.45  
   10.46 -# Strings for shorthelp
   10.47 -console_help = "console <DomId>                  Attach to domain DomId's console."
   10.48 -create_help =  """create [-c] <ConfigFile>
   10.49 -               [Name=Value]..       Create a domain based on Config File"""
   10.50 -destroy_help = "destroy <DomId>                  Terminate a domain immediately"
   10.51 -dump_core_help =   """dump-core [-L|--live][-C|--crash]
   10.52 -            <DomId> [FileName]      Dump core of the specified domain"""
   10.53 +USAGE_HELP = "Usage: xm <subcommand> [args]\n\n" \
   10.54 +             "Control, list, and manipulate Xen guest instances.\n"
   10.55  
   10.56 -help_help =    "help                             Display this message"
   10.57 -list_help =    "list [--long] [DomId, ...]       List information about domains"
   10.58 -list_label_help = "list [--label] [DomId, ...]      List information about domains including their labels"
   10.59 +USAGE_FOOTER = '<Domain> can either be the Domain Name or Id.\n' \
   10.60 +               'For more help on \'xm\' see the xm(1) man page.\n' \
   10.61 +               'For more help on \'xm create\' see the xmdomain.cfg(5) '\
   10.62 +               ' man page.\n'
   10.63 +
   10.64 +# Help strings are indexed by subcommand name in this way:
   10.65 +# 'subcommand': (argstring, description)
   10.66  
   10.67 -mem_max_help = "mem-max <DomId> <Mem>            Set maximum memory reservation for a domain"
   10.68 -mem_set_help = "mem-set <DomId> <Mem>            Adjust the current memory usage for a domain"
   10.69 -migrate_help = "migrate <DomId> <Host>           Migrate a domain to another machine"
   10.70 -pause_help =   "pause <DomId>                    Pause execution of a domain"
   10.71 -reboot_help =  "reboot <DomId> [-w][-a]          Reboot a domain"
   10.72 -restore_help = "restore <File>                   Create a domain from a saved state file"
   10.73 -save_help =    "save <DomId> <File>              Save domain state (and config) to file"
   10.74 -shutdown_help ="shutdown <DomId> [-w][-a][-R|-H] Shutdown a domain"
   10.75 -top_help =     "top                              Monitor system and domains in real-time"
   10.76 -unpause_help = "unpause <DomId>                  Unpause a paused domain"
   10.77 -uptime_help  = "uptime [-s|--short] [DomId, ...] List uptime for domains"
   10.78 +SUBCOMMAND_HELP = {
   10.79 +    # common commands
   10.80 +    
   10.81 +    'console'     : ('<Domain>',
   10.82 +                     'Attach to <Domain>\'s console.'),
   10.83 +    'create'      : ('<ConfigFile> [options] [vars]',
   10.84 +                     'Create a domain based on <ConfigFile>.'),
   10.85 +    'destroy'     : ('<Domain>',
   10.86 +                     'Terminate a domain immediately.'),
   10.87 +    'help'        : ('', 'Display this message.'),
   10.88 +    'list'        : ('[options] [Domain, ...]',
   10.89 +                     'List information about all/some domains.'),
   10.90 +    'mem-max'     : ('<Domain> <Mem>',
   10.91 +                     'Set the maximum amount reservation for a domain.'),
   10.92 +    'mem-set'     : ('<Domain> <Mem>',
   10.93 +                     'Set the current memory usage for a domain.'),
   10.94 +    'migrate'     : ('<Domain> <Host>',
   10.95 +                     'Migrate a domain to another machine.'),
   10.96 +    'pause'       : ('<Domain>', 'Pause execution of a domain.'),
   10.97 +    'reboot'      : ('<Domain> [-wa]', 'Reboot a domain.'),
   10.98 +    'restore'     : ('<CheckpointFile>',
   10.99 +                     'Restore a domain from a saved state.'),
  10.100 +    'save'        : ('<Domain> <CheckpointFile>',
  10.101 +                     'Save a domain state to restore later.'),
  10.102 +    'shutdown'    : ('<Domain> [-waRH]', 'Shutdown a domain.'),
  10.103 +    'top'         : ('', 'Monitor a host and the domains in real time.'),
  10.104 +    'unpause'     : ('<Domain>', 'Unpause a paused domain.'),
  10.105 +    'uptime'      : ('[-s] <Domain>', 'Print uptime for a domain.'),
  10.106  
  10.107 -help_spacer = """
  10.108 -   """
  10.109 +    # less used commands
  10.110 +
  10.111 +    'dmesg'       : ('[-c|--clear]',
  10.112 +                     'Read and/or clear Xend\'s message buffer.'),
  10.113 +    'domid'       : ('<DomainName>', 'Convert a domain name to domain id.'),
  10.114 +    'domname'     : ('<DomId>', 'Convert a domain id to domain name.'),
  10.115 +    'dump-core'   : ('[-L|--live] [-C|--crash] <Domain> [Filename]',
  10.116 +                     'Dump core for a specific domain.'),
  10.117 +    'info'        : ('', 'Get information about Xen host.'),
  10.118 +    'log'         : ('', 'Print Xend log'),
  10.119 +    'rename'      : ('<Domain> <NewDomainName>', 'Rename a domain.'),
  10.120 +    'sched-sedf'  : ('<Domain> [options]', 'Get/set EDF parameters.'),
  10.121 +    'sched-credit': ('-d <Domain> [-w[=WEIGHT]|-c[=CAP]]',
  10.122 +                     'Get/set credit scheduler parameters.'),
  10.123 +    'sysrq'       : ('<Domain> <letter>', 'Send a sysrq to a domain.'),
  10.124 +    'vcpu-list'   : ('[<Domain>]',
  10.125 +                     'List the VCPUs for a domain or all domains.'),
  10.126 +    'vcpu-pin'    : ('<Domain> <VCPU> <CPUs>',
  10.127 +                     'Set which CPUs a VCPU can use.'),
  10.128 +    'vcpu-set'    : ('<Domain> <vCPUs>',
  10.129 +                     'Set the number of active VCPUs for allowed for the'
  10.130 +                     ' domain.'),
  10.131 +
  10.132 +    # device commands
  10.133  
  10.134 -# Strings for longhelp
  10.135 -sysrq_help =   "sysrq   <DomId> <letter>         Send a sysrq to a domain"
  10.136 -domid_help =   "domid <DomName>                  Converts a domain name to a domain id"
  10.137 -domname_help = "domname <DomId>                  Convert a domain id to a domain name"
  10.138 -vcpu_set_help = """vcpu-set <DomId> <VCPUs>         Set the number of active VCPUs for a domain
  10.139 -                                    within the range allowed by the domain
  10.140 -                                    configuration"""
  10.141 -vcpu_list_help = "vcpu-list <DomId>                List the VCPUs for a domain (or all domains)"
  10.142 -vcpu_pin_help = "vcpu-pin <DomId> <VCPU> <CPUs>   Set which cpus a VCPU can use" 
  10.143 -dmesg_help =   "dmesg [-c|--clear]               Read or clear Xen's message buffer"
  10.144 -info_help =    "info                             Get information about the xen host"
  10.145 -rename_help =  "rename <DomId> <New Name>        Rename a domain"
  10.146 -log_help =     "log                              Print the xend log"
  10.147 -sched_sedf_help = "sched-sedf [DOM] [OPTIONS]       Show|Set simple EDF parameters\n" + \
  10.148 -"              -p, --period          Relative deadline(ms).\n\
  10.149 -              -s, --slice           Worst-case execution time(ms)\n\
  10.150 -                                    (slice < period).\n\
  10.151 -              -l, --latency         scaled period(ms) in case the domain\n\
  10.152 -                                    is doing heavy I/O.\n\
  10.153 -              -e, --extra           flag (0/1) which controls whether the\n\
  10.154 -                                    domain can run in extra-time\n\
  10.155 -              -w, --weight          mutually exclusive with period/slice and\n\
  10.156 -                                    specifies another way of setting a domain's\n\
  10.157 -                                    cpu period/slice."
  10.158 +    'block-attach'  :  ('<Domain> <BackDev> <FrontDev> <Mode>',
  10.159 +                        'Create a new virtual block device.'),
  10.160 +    'block-configure': ('<Domain> <BackDev> <FrontDev> <Mode> [BackDomId]',
  10.161 +                        'Change block device configuration'),
  10.162 +    'block-detach'  :  ('<Domain> <DevId>',
  10.163 +                        'Destroy a domain\'s virtual block device.'),
  10.164 +    'block-list'    :  ('<Domain> [--long]',
  10.165 +                        'List virtual block devices for a domain.'),
  10.166 +    'network-attach':  ('<Domain> [--script=<script>] [--ip=<ip>] '
  10.167 +                        '[--mac=<mac>]',
  10.168 +                        'Create a new virtual network device.'),
  10.169 +    'network-detach':  ('<Domain> <DevId>',
  10.170 +                        'Destroy a domain\'s virtual network device.'),
  10.171 +    'network-list'  :  ('<Domain> [--long]',
  10.172 +                        'List virtual network interfaces for a domain.'),
  10.173 +    'vnet-create'   :  ('<ConfigFile>','Create a vnet from ConfigFile.'),
  10.174 +    'vnet-delete'   :  ('<VnetId>', 'Delete a Vnet.'),
  10.175 +    'vnet-list'     :  ('[-l|--long]', 'List Vnets.'),
  10.176 +    'vtpm-list'     :  ('<Domain> [--long]', 'List virtual TPM devices.'),
  10.177 +
  10.178 +    # security
  10.179  
  10.180 -sched_credit_help = "sched-credit                           Set or get credit scheduler parameters"
  10.181 -block_attach_help = """block-attach <DomId> <BackDev> <FrontDev> <Mode>
  10.182 -                [BackDomId]         Create a new virtual block device"""
  10.183 -block_detach_help = """block-detach  <DomId> <DevId>    Destroy a domain's virtual block device,
  10.184 -                                    where <DevId> may either be the device ID
  10.185 -                                    or the device name as mounted in the guest"""
  10.186 -
  10.187 -block_list_help = "block-list <DomId> [--long]      List virtual block devices for a domain"
  10.188 -block_configure_help = """block-configure <DomId> <BackDev> <FrontDev> <Mode>
  10.189 -                   [BackDomId] Change block device configuration"""
  10.190 -network_attach_help = """network-attach  <DomID> [script=<script>] [ip=<ip>] [mac=<mac>]
  10.191 -                           [bridge=<bridge>] [backend=<backDomID>]
  10.192 -                                    Create a new virtual network device """
  10.193 -network_detach_help = """network-detach  <DomId> <DevId>  Destroy a domain's virtual network
  10.194 -                                    device, where <DevId> is the device ID."""
  10.195 +    'addlabel'      :  ('<label> {dom <ConfigFile>|res <resource>} [<policy>]',
  10.196 +                        'Add security label to domain.'),
  10.197 +    'rmlabel'       :  ('{dom <ConfigFile>|res <Resource>}',
  10.198 +                        'Remove a security label from domain.'),
  10.199 +    'getlabel'      :  ('{dom <ConfigFile>|res <Resource>}',
  10.200 +                        'Show security label for domain or resource.'),
  10.201 +    'dry-run'       :  ('<ConfigFile>',
  10.202 +                        'Test if a domain can access its resources.'),
  10.203 +    'resources'     :  ('', 'Show info for each labeled resource.'),
  10.204 +    'cfgbootpolicy' :  ('<policy> [kernelversion]',
  10.205 +                        'Add policy to boot configuration.'),
  10.206 +    'dumppolicy'    :  ('', 'Print hypervisor ACM state information.'),
  10.207 +    'loadpolicy'    :  ('<policy.bin>', 'Load binary policy into hypervisor.'),
  10.208 +    'makepolicy'    :  ('<policy>', 'Build policy and create .bin/.map '
  10.209 +                        'files.'),
  10.210 +    'labels'        :  ('[policy] [type=dom|res|any]',
  10.211 +                        'List <type> labels for (active) policy.'),
  10.212 +    'serve'         :  ('', 'Proxy Xend XMLRPC over stdio.'),
  10.213 +}
  10.214  
  10.215 -network_list_help = "network-list <DomId> [--long]    List virtual network interfaces for a domain"
  10.216 -vnet_list_help = "vnet-list [-l|--long]            list vnets"
  10.217 -vnet_create_help = "vnet-create <config>             create a vnet from a config file"
  10.218 -vnet_delete_help = "vnet-delete <vnetid>             delete a vnet"
  10.219 -vtpm_list_help = "vtpm-list <DomId> [--long]       list virtual TPM devices"
  10.220 -addlabel_help =  "addlabel <label> dom <configfile> Add security label to domain\n            <label> res <resource>   or resource"
  10.221 -rmlabel_help =  "rmlabel dom <configfile>         Remove security label from domain\n           res <resource>           or resource"
  10.222 -getlabel_help =  "getlabel dom <configfile>        Show security label for domain\n            res <resource>          or resource"
  10.223 -dry_run_help =  "dry-run <configfile>             Tests if domain can access its resources"
  10.224 -resources_help =  "resources                        Show info for each labeled resource"
  10.225 -cfgbootpolicy_help = "cfgbootpolicy <policy>           Add policy to boot configuration "
  10.226 -dumppolicy_help = "dumppolicy                       Print hypervisor ACM state information"
  10.227 -loadpolicy_help = "loadpolicy <policy>              Load binary policy into hypervisor"
  10.228 -makepolicy_help = "makepolicy <policy>              Build policy and create .bin/.map files"
  10.229 -labels_help     = "labels [policy] [type=DOM|..]    List <type> labels for (active) policy."
  10.230 -serve_help      = "serve                            Proxy Xend XML-RPC over stdio"
  10.231 +SUBCOMMAND_OPTIONS = {
  10.232 +    'sched-sedf': (
  10.233 +       ('-p [MS]', '--period[=MS]', 'Relative deadline(ms)'),
  10.234 +       ('-s [MS]', '--slice[=MS]' ,
  10.235 +        'Worst-case execution time(ms). (slice < period)'),
  10.236 +       ('-l [MS]', '--latency[=MS]',
  10.237 +        'Scaled period (ms) when domain performs heavy I/O'),
  10.238 +       ('-e [FLAG]', '--extra[=FLAG]',
  10.239 +        'Flag (0 or 1) controls if domain can run in extra time.'),
  10.240 +       ('-w [FLOAT]', '--weight[=FLOAT]',
  10.241 +        'CPU Period/slice (do not set with --period/--slice)'),
  10.242 +    ),
  10.243 +    'sched-credit': (
  10.244 +       ('-d DOMAIN', '--domain=DOMAIN', 'Domain to modify'),
  10.245 +       ('-w WEIGHT', '--weight=WEIGHT', 'Weight (int)'),
  10.246 +       ('-c CAP',    '--cap=CAP',       'Cap (int)'),
  10.247 +    ),
  10.248 +    'list': (
  10.249 +       ('-l', '--long', 'Output all VM details in SXP'),
  10.250 +       ('', '--label',  'Include security labels'),
  10.251 +    ),
  10.252 +    'dmesg': (
  10.253 +       ('-c', '--clear', 'Clear dmesg buffer'),
  10.254 +    ),
  10.255 +    'vnet-list': (
  10.256 +       ('-l', '--long', 'List Vnets as SXP'),
  10.257 +    ),
  10.258 +    'network-list': (
  10.259 +       ('-l', '--long', 'List resources as SXP'),
  10.260 +    ),
  10.261 +}
  10.262  
  10.263 -short_command_list = [
  10.264 +common_commands = [
  10.265      "console",
  10.266      "create",
  10.267      "destroy",
  10.268 @@ -165,7 +219,6 @@ domain_commands = [
  10.269      "domname",
  10.270      "dump-core",
  10.271      "list",
  10.272 -    "list_label",
  10.273      "mem-max",
  10.274      "mem-set",
  10.275      "migrate",
  10.276 @@ -223,67 +276,105 @@ acm_commands = [
  10.277      "makepolicy",
  10.278      "loadpolicy",
  10.279      "cfgbootpolicy",
  10.280 -    "dumppolicy"
  10.281 +    "dumppolicy",
  10.282      ]
  10.283  
  10.284  all_commands = (domain_commands + host_commands + scheduler_commands +
  10.285                  device_commands + vnet_commands + acm_commands)
  10.286  
  10.287 -
  10.288 -def commandToHelp(cmd):
  10.289 -    return eval(cmd.replace("-", "_") + "_help")
  10.290 -
  10.291 -
  10.292 -shorthelp = """Usage: xm <subcommand> [args]
  10.293 -    Control, list, and manipulate Xen guest instances
  10.294 -
  10.295 -xm common subcommands:
  10.296 -   """  + help_spacer.join(map(commandToHelp, short_command_list))  + """
  10.297 -
  10.298 -<DomName> can be substituted for <DomId> in xm subcommands.
  10.299 +####################################################################
  10.300 +#
  10.301 +#  Help/usage printing functions
  10.302 +#
  10.303 +####################################################################
  10.304  
  10.305 -For a complete list of subcommands run 'xm help --long'
  10.306 -For more help on xm see the xm(1) man page
  10.307 -For more help on xm create, see the xmdomain.cfg(5) man page"""
  10.308 -
  10.309 -longhelp = """Usage: xm <subcommand> [args]
  10.310 -    Control, list, and manipulate Xen guest instances
  10.311 -
  10.312 -xm full list of subcommands:
  10.313 -
  10.314 -  Domain Commands:
  10.315 -   """ + help_spacer.join(map(commandToHelp,  domain_commands)) + """
  10.316 -
  10.317 -  Xen Host Commands:
  10.318 -   """ + help_spacer.join(map(commandToHelp,  host_commands)) + """
  10.319 +def cmdHelp(cmd):
  10.320 +    """Print help for a specific subcommand."""
  10.321 +    
  10.322 +    try:
  10.323 +        args, desc = SUBCOMMAND_HELP[cmd]
  10.324 +    except KeyError:
  10.325 +        shortHelp()
  10.326 +        return
  10.327 +    
  10.328 +    print 'Usage: xm %s %s' % (cmd, args)
  10.329 +    print
  10.330 +    print desc
  10.331 +    
  10.332 +    try:
  10.333 +        # If options help message is defined, print this.
  10.334 +        for shortopt, longopt, desc in SUBCOMMAND_OPTIONS[cmd]:
  10.335 +            if shortopt and longopt:
  10.336 +                optdesc = '%s, %s' % (shortopt, longopt)
  10.337 +            elif shortopt:
  10.338 +                optdesc = shortopt
  10.339 +            elif longopt:
  10.340 +                optdesc = longopt
  10.341  
  10.342 -  Scheduler Commands:
  10.343 -   """ + help_spacer.join(map(commandToHelp,  scheduler_commands)) + """
  10.344 -
  10.345 -  Virtual Device Commands:
  10.346 -   """  + help_spacer.join(map(commandToHelp, device_commands)) + """
  10.347 -
  10.348 -  Vnet commands:
  10.349 -   """ + help_spacer.join(map(commandToHelp,  vnet_commands)) + """
  10.350 -
  10.351 -  Access Control commands:
  10.352 -   """ + help_spacer.join(map(commandToHelp,  acm_commands)) + """
  10.353 -
  10.354 -<DomName> can be substituted for <DomId> in xm subcommands.
  10.355 +            wrapped_desc = wrap(desc, 43)   
  10.356 +            print '  %-30s %-43s' % (optdesc, wrapped_desc[0])
  10.357 +            for line in wrapped_desc[1:]:
  10.358 +                print ' ' * 33 + line
  10.359 +        print
  10.360 +    except KeyError:
  10.361 +        # if the command is an external module, we grab usage help
  10.362 +        # from the module itself.
  10.363 +        if cmd in IMPORTED_COMMANDS:
  10.364 +            try:
  10.365 +                cmd_module =  __import__(cmd, globals(), locals(), 'xen.xm')
  10.366 +                cmd_usage = getattr(cmd_module, "help", None)
  10.367 +                if cmd_usage:
  10.368 +                    print cmd_usage()
  10.369 +            except ImportError:
  10.370 +                pass
  10.371 +        
  10.372 +def shortHelp():
  10.373 +    """Print out generic help when xm is called without subcommand."""
  10.374 +    
  10.375 +    print USAGE_HELP
  10.376 +    print 'Common \'xm\' commands:\n'
  10.377 +    
  10.378 +    for command in common_commands:
  10.379 +        try:
  10.380 +            args, desc = SUBCOMMAND_HELP[command]
  10.381 +        except KeyError:
  10.382 +            continue
  10.383 +        wrapped_desc = wrap(desc, 50)
  10.384 +        print ' %-20s %-50s' % (command, wrapped_desc[0])
  10.385 +        for line in wrapped_desc[1:]:
  10.386 +            print ' ' * 22 + line
  10.387  
  10.388 -For a short list of subcommands run 'xm help'
  10.389 -For more help on xm see the xm(1) man page
  10.390 -For more help on xm create, see the xmdomain.cfg(5) man page"""
  10.391 +    print
  10.392 +    print USAGE_FOOTER
  10.393 +    print 'For a complete list of subcommands run \'xm help\'.'
  10.394 +    
  10.395 +def longHelp():
  10.396 +    """Print out full help when xm is called with xm --help or xm help"""
  10.397 +    
  10.398 +    print USAGE_HELP
  10.399 +    print 'xm full list of subcommands:\n'
  10.400 +    
  10.401 +    for command in all_commands:
  10.402 +        try:
  10.403 +            args, desc = SUBCOMMAND_HELP[command]
  10.404 +        except KeyError:
  10.405 +            continue
  10.406  
  10.407 -# array for xm help <command>
  10.408 -help = {
  10.409 -    "--long": longhelp
  10.410 -    }
  10.411 +        wrapped_desc = wrap(desc, 50)
  10.412 +        print ' %-20s %-50s' % (command, wrapped_desc[0])
  10.413 +        for line in wrapped_desc[1:]:
  10.414 +            print ' ' * 22 + line        
  10.415 +
  10.416 +    print
  10.417 +    print USAGE_FOOTER        
  10.418  
  10.419 -for command in all_commands:
  10.420 -    # create is handled specially
  10.421 -    if (command != 'create'):
  10.422 -        help[command] = commandToHelp(command)
  10.423 +def usage(cmd = None):
  10.424 +    """ Print help usage information and exits """
  10.425 +    if cmd:
  10.426 +        cmdHelp(cmd)
  10.427 +    else:
  10.428 +        shortHelp()
  10.429 +    sys.exit(1)
  10.430  
  10.431  
  10.432  ####################################################################
  10.433 @@ -298,7 +389,7 @@ def arg_check(args, name, lo, hi = -1):
  10.434      if hi == -1:
  10.435          if n != lo:
  10.436              err("'xm %s' requires %d argument%s.\n" % (name, lo,
  10.437 -                                                       lo > 1 and 's' or ''))
  10.438 +                                                       lo == 1 and '' or 's'))
  10.439              usage(name)
  10.440      else:
  10.441          if n < lo or n > hi:
  10.442 @@ -345,14 +436,19 @@ def err(msg):
  10.443  def xm_save(args):
  10.444      arg_check(args, "save", 2)
  10.445  
  10.446 -    dom = args[0] # TODO: should check if this exists
  10.447 +    try:
  10.448 +        dominfo = parse_doms_info(server.xend.domain(args[0]))
  10.449 +    except xmlrpclib.Fault, ex:
  10.450 +        raise ex
  10.451 +    
  10.452 +    domid = dominfo['domid']
  10.453      savefile = os.path.abspath(args[1])
  10.454  
  10.455      if not os.access(os.path.dirname(savefile), os.W_OK):
  10.456          err("xm save: Unable to create file %s" % savefile)
  10.457          sys.exit(1)
  10.458      
  10.459 -    server.xend.domain.save(dom, savefile)
  10.460 +    server.xend.domain.save(domid, savefile)
  10.461      
  10.462  def xm_restore(args):
  10.463      arg_check(args, "restore", 1)
  10.464 @@ -366,9 +462,9 @@ def xm_restore(args):
  10.465      server.xend.domain.restore(savefile)
  10.466  
  10.467  
  10.468 -def getDomains(domain_names):
  10.469 +def getDomains(domain_names, full = 0):
  10.470      if domain_names:
  10.471 -        return map(server.xend.domain, domain_names)
  10.472 +        return [server.xend.domain(dom) for dom in domain_names]
  10.473      else:
  10.474          return server.xend.domains(1)
  10.475  
  10.476 @@ -378,9 +474,11 @@ def xm_list(args):
  10.477      show_vcpus = 0
  10.478      show_labels = 0
  10.479      try:
  10.480 -        (options, params) = getopt.gnu_getopt(args, 'lv', ['long','vcpus','label'])
  10.481 +        (options, params) = getopt.gnu_getopt(args, 'lv',
  10.482 +                                              ['long','vcpus','label'])
  10.483      except getopt.GetoptError, opterr:
  10.484          err(opterr)
  10.485 +        usage('list')
  10.486          sys.exit(1)
  10.487      
  10.488      for (k, v) in options:
  10.489 @@ -397,7 +495,7 @@ def xm_list(args):
  10.490          xm_vcpu_list(params)
  10.491          return
  10.492  
  10.493 -    doms = getDomains(params)
  10.494 +    doms = getDomains(params, use_long)
  10.495  
  10.496      if use_long:
  10.497          map(PrettyPrint.prettyprint, doms)
  10.498 @@ -412,7 +510,7 @@ def parse_doms_info(info):
  10.499          return t(sxp.child_value(info, n, d))
  10.500      
  10.501      return {
  10.502 -        'dom'      : get_info('domid',        int,   -1),
  10.503 +        'domid'    : get_info('domid',        int,   -1),
  10.504          'name'     : get_info('name',         str,   '??'),
  10.505          'mem'      : get_info('memory',       int,   0),
  10.506          'vcpus'    : get_info('online_vcpus', int,   0),
  10.507 @@ -428,7 +526,7 @@ def parse_sedf_info(info):
  10.508          return t(sxp.child_value(info, n, d))
  10.509  
  10.510      return {
  10.511 -        'dom'      : get_info('domain',        int,   -1),
  10.512 +        'domid'    : get_info('domid',         int,   -1),
  10.513          'period'   : get_info('period',        int,   -1),
  10.514          'slice'    : get_info('slice',         int,   -1),
  10.515          'latency'  : get_info('latency',       int,   -1),
  10.516 @@ -436,34 +534,40 @@ def parse_sedf_info(info):
  10.517          'weight'   : get_info('weight',        int,   -1),
  10.518          }
  10.519  
  10.520 -
  10.521  def xm_brief_list(doms):
  10.522 -    print 'Name                              ID Mem(MiB) VCPUs State  Time(s)'
  10.523 -    for dom in doms:
  10.524 -        d = parse_doms_info(dom)
  10.525 -        print ("%(name)-32s %(dom)3d %(mem)8d %(vcpus)5d %(state)5s %(cpu_time)7.1f" % d)
  10.526 -
  10.527 -
  10.528 -def xm_label_list(doms):
  10.529 -    output = []
  10.530 -    print 'Name                              ID Mem(MiB) VCPUs State  Time(s)  Label'
  10.531 +    print '%-40s %3s %8s %5s %5s %9s' % \
  10.532 +          ('Name', 'ID', 'Mem(MiB)', 'VCPUs', 'State', 'Time(s)')
  10.533 +    
  10.534 +    format = "%(name)-40s %(domid)3d %(mem)8d %(vcpus)5d %(state)5s " \
  10.535 +             "%(cpu_time)8.1f"
  10.536 +    
  10.537      for dom in doms:
  10.538          d = parse_doms_info(dom)
  10.539 -        l = "%(name)-32s %(dom)3d %(mem)8d %(vcpus)5d %(state)5s %(cpu_time)7.1f  " % d
  10.540 +        print format % d
  10.541 +
  10.542 +def xm_label_list(doms):
  10.543 +    print '%-32s %3s %8s %5s %5s %9s %-8s' % \
  10.544 +          ('Name', 'ID', 'Mem(MiB)', 'VCPUs', 'State', 'Time(s)', 'Label')
  10.545 +    
  10.546 +    output = []
  10.547 +    format = '%(name)-32s %(domid)3d %(mem)8d %(vcpus)5d %(state)5s ' \
  10.548 +             '%(cpu_time)8.1f %(seclabel)9s'
  10.549 +    
  10.550 +    for dom in doms:
  10.551 +        d = parse_doms_info(dom)
  10.552          if security.active_policy not in ['INACTIVE', 'NULL', 'DEFAULT']:
  10.553 -            if d['seclabel']:
  10.554 -                line = (l, d['seclabel'])
  10.555 -            else:
  10.556 -                line = (l, "ERROR")
  10.557 +            if not d['seclabel']:
  10.558 +                d['seclabel'] = 'ERROR'
  10.559          elif security.active_policy in ['DEFAULT']:
  10.560 -            line = (l, "DEFAULT")
  10.561 +            d['seclabel'] = 'DEFAULT'
  10.562          else:
  10.563 -            line = (l, "INACTIVE")
  10.564 -        output.append(line)
  10.565 +            d['seclabel'] = 'INACTIVE'
  10.566 +        output.append((format % d, d['seclabel']))
  10.567 +        
  10.568      #sort by labels
  10.569      output.sort(lambda x,y: cmp( x[1].lower(), y[1].lower()))
  10.570 -    for l in output:
  10.571 -        print l[0] + l[1]
  10.572 +    for line, label in output:
  10.573 +        print line
  10.574  
  10.575  
  10.576  def xm_vcpu_list(args):
  10.577 @@ -474,7 +578,11 @@ def xm_vcpu_list(args):
  10.578          doms = server.xend.domains(False)
  10.579          dominfo = map(server.xend.domain.getVCPUInfo, doms)
  10.580  
  10.581 -    print 'Name                              ID  VCPU  CPU  State  Time(s)  CPU Affinity'
  10.582 +    print '%-32s %3s %5s %5s %5s %9s %s' % \
  10.583 +          ('Name', 'ID', 'VCPUs', 'CPU', 'State', 'Time(s)', 'CPU Affinity')
  10.584 +
  10.585 +    format = '%(name)-32s %(domid)3d %(number)5d %(c)5s %(s)5s ' \
  10.586 +             ' %(cpu_time)8.1f %(cpumap)s'
  10.587  
  10.588      for dom in dominfo:
  10.589          def get_info(n):
  10.590 @@ -568,10 +676,7 @@ def xm_vcpu_list(args):
  10.591                  c = "-"
  10.592                  s = "--p"
  10.593  
  10.594 -            print (
  10.595 -                "%(name)-32s %(domid)3d  %(number)4d  %(c)3s   %(s)-3s   %(cpu_time)7.1f  %(cpumap)s" %
  10.596 -                locals())
  10.597 -
  10.598 +            print format % locals()
  10.599  
  10.600  def xm_reboot(args):
  10.601      arg_check(args, "reboot", 1, 3)
  10.602 @@ -634,31 +739,31 @@ def xm_dump_core(args):
  10.603  
  10.604  def xm_rename(args):
  10.605      arg_check(args, "rename", 2)
  10.606 -
  10.607 +        
  10.608      server.xend.domain.setName(args[0], args[1])
  10.609  
  10.610 -def xm_subcommand(command, args):
  10.611 +def xm_importcommand(command, args):
  10.612      cmd = __import__(command, globals(), locals(), 'xen.xm')
  10.613      cmd.main([command] + args)
  10.614  
  10.615  
  10.616  #############################################################
  10.617  
  10.618 -def cpu_make_map(cpulist):
  10.619 -    cpus = []
  10.620 -    for c in cpulist.split(','):
  10.621 -        if c.find('-') != -1:
  10.622 -            (x,y) = c.split('-')
  10.623 -            for i in range(int(x),int(y)+1):
  10.624 -                cpus.append(int(i))
  10.625 -        else:
  10.626 -            cpus.append(int(c))
  10.627 -    cpus.sort()
  10.628 -    return cpus
  10.629 -
  10.630  def xm_vcpu_pin(args):
  10.631      arg_check(args, "vcpu-pin", 3)
  10.632  
  10.633 +    def cpu_make_map(cpulist):
  10.634 +        cpus = []
  10.635 +        for c in cpulist.split(','):
  10.636 +            if c.find('-') != -1:
  10.637 +                (x,y) = c.split('-')
  10.638 +                for i in range(int(x),int(y)+1):
  10.639 +                    cpus.append(int(i))
  10.640 +            else:
  10.641 +                cpus.append(int(c))
  10.642 +        cpus.sort()
  10.643 +        return cpus
  10.644 +
  10.645      dom  = args[0]
  10.646      vcpu = int(args[1])
  10.647      cpumap = cpu_make_map(args[2])
  10.648 @@ -719,11 +824,12 @@ def xm_sched_sedf(args):
  10.649          info['period']  = ns_to_ms(info['period'])
  10.650          info['slice']   = ns_to_ms(info['slice'])
  10.651          info['latency'] = ns_to_ms(info['latency'])
  10.652 -        print( ("%(name)-32s %(dom)3d %(period)9.1f %(slice)9.1f" +
  10.653 +        print( ("%(name)-32s %(domid)3d %(period)9.1f %(slice)9.1f" +
  10.654                  " %(latency)7.1f %(extratime)6d %(weight)6d") % info)
  10.655  
  10.656      def domid_match(domid, info):
  10.657 -        return domid is None or domid == info['name'] or domid == str(info['dom'])
  10.658 +        return domid is None or domid == info['name'] or \
  10.659 +               domid == str(info['domid'])
  10.660  
  10.661      # we want to just display current info if no parameters are passed
  10.662      if len(args) == 0:
  10.663 @@ -757,20 +863,25 @@ def xm_sched_sedf(args):
  10.664          elif k in ['-w', '--weight']:
  10.665              opts['weight'] = v
  10.666  
  10.667 +    doms = filter(lambda x : domid_match(domid, x),
  10.668 +                        [parse_doms_info(dom) for dom in getDomains("")])
  10.669 +
  10.670      # print header if we aren't setting any parameters
  10.671      if len(opts.keys()) == 0:
  10.672 -        print '%-33s %-2s %-4s %-4s %-7s %-5s %-6s'%('Name','ID','Period(ms)',
  10.673 -                                                     'Slice(ms)', 'Lat(ms)',
  10.674 -                                                     'Extra','Weight')
  10.675 -
  10.676 -    doms = filter(lambda x : domid_match(domid, x),
  10.677 -                        [parse_doms_info(dom) for dom in getDomains("")])
  10.678 +        print '%-33s %-2s %-4s %-4s %-7s %-5s %-6s' % \
  10.679 +              ('Name','ID','Period(ms)', 'Slice(ms)', 'Lat(ms)',
  10.680 +               'Extra','Weight')
  10.681 +    
  10.682      for d in doms:
  10.683          # fetch current values so as not to clobber them
  10.684 -        sedf_info = \
  10.685 -            parse_sedf_info(server.xend.domain.cpu_sedf_get(d['dom']))
  10.686 +        try:
  10.687 +            sedf_raw = server.xend.domain.cpu_sedf_get(d['domid'])
  10.688 +        except xmlrpclib.Fault:
  10.689 +            # domain does not support sched-sedf?
  10.690 +            sedf_raw = {}
  10.691 +
  10.692 +        sedf_info = parse_sedf_info(sedf_raw)
  10.693          sedf_info['name'] = d['name']
  10.694 -
  10.695          # update values in case of call to set
  10.696          if len(opts.keys()) > 0:
  10.697              for k in opts.keys():
  10.698 @@ -780,7 +891,7 @@ def xm_sched_sedf(args):
  10.699              v = map(int, [sedf_info['period'], sedf_info['slice'],
  10.700                            sedf_info['latency'],sedf_info['extratime'], 
  10.701                            sedf_info['weight']])
  10.702 -            rv = server.xend.domain.cpu_sedf_set(d['dom'], *v)
  10.703 +            rv = server.xend.domain.cpu_sedf_set(d['domid'], *v)
  10.704              if int(rv) != 0:
  10.705                  err("Failed to set sedf parameters (rv=%d)."%(rv))
  10.706  
  10.707 @@ -789,17 +900,14 @@ def xm_sched_sedf(args):
  10.708              print_sedf(sedf_info)
  10.709  
  10.710  def xm_sched_credit(args):
  10.711 -    usage_msg = """sched-credit:     Set or get credit scheduler parameters
  10.712 - Usage:
  10.713 -
  10.714 -        sched-credit -d domain [-w weight] [-c cap]
  10.715 -    """
  10.716 +    """Get/Set options for Credit Scheduler."""
  10.717 +    
  10.718      try:
  10.719 -        opts, args = getopt.getopt(args[0:], "d:w:c:",
  10.720 +        opts, params = getopt.getopt(args, "d:w:c:",
  10.721              ["domain=", "weight=", "cap="])
  10.722 -    except getopt.GetoptError:
  10.723 -        # print help information and exit:
  10.724 -        print usage_msg
  10.725 +    except getopt.GetoptError, opterr:
  10.726 +        err(opterr)
  10.727 +        usage('sched-credit')
  10.728          sys.exit(1)
  10.729  
  10.730      domain = None
  10.731 @@ -816,15 +924,16 @@ def xm_sched_credit(args):
  10.732  
  10.733      if domain is None:
  10.734          # place holder for system-wide scheduler parameters
  10.735 -        print usage_msg
  10.736 +        err("No domain given.")
  10.737 +        usage('sched-credit')
  10.738          sys.exit(1)
  10.739  
  10.740      if weight is None and cap is None:
  10.741          print server.xend.domain.sched_credit_get(domain)
  10.742      else:
  10.743 -        err = server.xend.domain.sched_credit_set(domain, weight, cap)
  10.744 -        if err != 0:
  10.745 -            print err
  10.746 +        result = server.xend.domain.sched_credit_set(domain, weight, cap)
  10.747 +        if result != 0:
  10.748 +            err(str(result))
  10.749  
  10.750  def xm_info(args):
  10.751      arg_check(args, "info", 0)
  10.752 @@ -843,6 +952,8 @@ def xm_console(args):
  10.753      dom = args[0]
  10.754      info = server.xend.domain(dom)
  10.755      domid = int(sxp.child_value(info, 'domid', '-1'))
  10.756 +    if domid == -1:
  10.757 +        raise Exception("Domain is not started")
  10.758      console.execConsole(domid)
  10.759  
  10.760  def xm_uptime(args):
  10.761 @@ -920,8 +1031,11 @@ its contents if the [-c|--clear] flag is
  10.762      myargs = args
  10.763      myargs.insert(0, 'dmesg')
  10.764      gopts.parse(myargs)
  10.765 -    if not (1 <= len(myargs) <= 2):
  10.766 +    
  10.767 +    if len(myargs) not in (1, 2):
  10.768          err('Invalid arguments: ' + str(myargs))
  10.769 +        usage('dmesg')
  10.770 +        sys.exit(1)
  10.771  
  10.772      if not gopts.vals.clear:
  10.773          print server.xend.node.dmesg.info()
  10.774 @@ -939,7 +1053,7 @@ def xm_serve(args):
  10.775      from fcntl import fcntl, F_SETFL
  10.776      
  10.777      s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
  10.778 -    s.connect(xen.xend.XendClient.XML_RPC_SOCKET)
  10.779 +    s.connect(XendClient.XML_RPC_SOCKET)
  10.780      fcntl(sys.stdin, F_SETFL, os.O_NONBLOCK)
  10.781  
  10.782      while True:
  10.783 @@ -1085,7 +1199,7 @@ def parse_block_configuration(args):
  10.784          cls = 'tap'
  10.785      else:
  10.786          cls = 'vbd'
  10.787 -        
  10.788 +
  10.789      vbd = [cls,
  10.790             ['uname', args[1]],
  10.791             ['dev',   args[2]],
  10.792 @@ -1094,19 +1208,12 @@ def parse_block_configuration(args):
  10.793          vbd.append(['backend', args[4]])
  10.794  
  10.795      # verify that policy permits attaching this resource
  10.796 -    try:
  10.797 -        if security.on():
  10.798 -            dominfo = server.xend.domain(dom)
  10.799 -            label = security.get_security_printlabel(dominfo)
  10.800 -        else:
  10.801 -            label = None
  10.802 +    if security.on():
  10.803 +        dominfo = server.xend.domain(dom)
  10.804 +        label = security.get_security_printlabel(dominfo)
  10.805 +    else:
  10.806 +        label = None
  10.807          security.res_security_check(args[1], label)
  10.808 -    except security.ACMError, e:
  10.809 -        print e.value
  10.810 -        sys.exit(1)
  10.811 -    except:
  10.812 -        traceback.print_exc(limit=1)
  10.813 -        sys.exit(1)
  10.814  
  10.815      return (dom, vbd)
  10.816  
  10.817 @@ -1206,10 +1313,10 @@ commands = {
  10.818      "domid": xm_domid,
  10.819      "domname": xm_domname,
  10.820      "dump-core": xm_dump_core,
  10.821 +    "reboot": xm_reboot,    
  10.822      "rename": xm_rename,
  10.823      "restore": xm_restore,
  10.824      "save": xm_save,
  10.825 -    "reboot": xm_reboot,
  10.826      "shutdown": xm_shutdown,
  10.827      "uptime": xm_uptime,
  10.828      "list": xm_list,
  10.829 @@ -1249,24 +1356,24 @@ commands = {
  10.830      }
  10.831  
  10.832  ## The commands supported by a separate argument parser in xend.xm.
  10.833 -subcommands = [
  10.834 +IMPORTED_COMMANDS = [
  10.835      'create',
  10.836      'migrate',
  10.837      'sysrq',
  10.838      'labels',
  10.839      'addlabel',
  10.840 +    'cfgbootpolicy',
  10.841 +    'makepolicy',
  10.842 +    'loadpolicy',
  10.843 +    'dumppolicy'
  10.844      'rmlabel',
  10.845      'getlabel',
  10.846      'dry-run',
  10.847      'resources',
  10.848 -    'cfgbootpolicy',
  10.849 -    'makepolicy',
  10.850 -    'loadpolicy',
  10.851 -    'dumppolicy'
  10.852      ]
  10.853  
  10.854 -for c in subcommands:
  10.855 -    commands[c] = eval('lambda args: xm_subcommand("%s", args)' % c)
  10.856 +for c in IMPORTED_COMMANDS:
  10.857 +    commands[c] = eval('lambda args: xm_importcommand("%s", args)' % c)
  10.858  
  10.859  aliases = {
  10.860      "balloon": "mem-set",
  10.861 @@ -1284,11 +1391,18 @@ def xm_lookup_cmd(cmd):
  10.862      elif aliases.has_key(cmd):
  10.863          deprecated(cmd,aliases[cmd])
  10.864          return commands[aliases[cmd]]
  10.865 +    elif cmd == 'help':
  10.866 +        longHelp()
  10.867 +        sys.exit(0)
  10.868      else:
  10.869 -        if len( cmd ) > 1:
  10.870 -            matched_commands = filter( lambda (command, func): command[ 0:len(cmd) ] == cmd, commands.iteritems() )
  10.871 -            if len( matched_commands ) == 1:
  10.872 -		        return matched_commands[0][1]
  10.873 +        # simulate getopt's prefix matching behaviour
  10.874 +        if len(cmd) > 1:
  10.875 +            same_prefix_cmds = [commands[c] for c in commands.keys() \
  10.876 +                                if c[:len(cmd)] == cmd]
  10.877 +            # only execute if there is only 1 match
  10.878 +            if len(same_prefix_cmds) == 1:
  10.879 +                return same_prefix_cmds[0]
  10.880 +            
  10.881          err('Sub Command %s not found!' % cmd)
  10.882          usage()
  10.883  
  10.884 @@ -1296,27 +1410,17 @@ def deprecated(old,new):
  10.885      print >>sys.stderr, (
  10.886          "Command %s is deprecated.  Please use xm %s instead." % (old, new))
  10.887  
  10.888 -def usage(cmd=None):
  10.889 -    if cmd == 'create':
  10.890 -        mycmd = xm_lookup_cmd(cmd)
  10.891 -        mycmd( ['--help'] )
  10.892 -        sys.exit(1)
  10.893 -    if help.has_key(cmd):
  10.894 -        print "   " + help[cmd]
  10.895 -    else:
  10.896 -        print shorthelp
  10.897 -    sys.exit(1)
  10.898 -
  10.899  def main(argv=sys.argv):
  10.900      if len(argv) < 2:
  10.901          usage()
  10.902 -    
  10.903 -    if re.compile('-*help').match(argv[1]):
  10.904 -	if len(argv) > 2:
  10.905 -	    usage(argv[2])
  10.906 -	else:
  10.907 -	    usage()
  10.908 -	sys.exit(0)
  10.909 +
  10.910 +    # intercept --help and output our own help
  10.911 +    if '--help' in argv[1:]:
  10.912 +        if '--help' == argv[1]:
  10.913 +            longHelp()
  10.914 +        else:
  10.915 +            usage(argv[1])
  10.916 +        sys.exit(0)
  10.917  
  10.918      cmd = xm_lookup_cmd(argv[1])
  10.919  
  10.920 @@ -1329,9 +1433,9 @@ def main(argv=sys.argv):
  10.921                  usage()
  10.922          except socket.error, ex:
  10.923              if os.geteuid() != 0:
  10.924 -                err("Most commands need root access.  Please try again as root.")
  10.925 +                err("Most commands need root access. Please try again as root.")
  10.926              else:
  10.927 -                err("Error connecting to xend: %s.  Is xend running?" % ex[1])
  10.928 +                err("Unable to connect to xend: %s. Is xend running?" % ex[1])
  10.929              sys.exit(1)
  10.930          except KeyboardInterrupt:
  10.931              print "Interrupted."
  10.932 @@ -1340,16 +1444,16 @@ def main(argv=sys.argv):
  10.933              if os.geteuid() != 0:
  10.934                  err("Most commands need root access.  Please try again as root.")
  10.935              else:
  10.936 -                err("Error connecting to xend: %s." % ex[1])
  10.937 +                err("Unable to connect to xend: %s." % ex[1])
  10.938              sys.exit(1)
  10.939          except SystemExit:
  10.940              sys.exit(1)
  10.941          except xmlrpclib.Fault, ex:
  10.942 -            if ex.faultCode == xen.xend.XendClient.ERROR_INVALID_DOMAIN:
  10.943 -                print  >>sys.stderr, (
  10.944 -                    "Error: the domain '%s' does not exist." % ex.faultString)
  10.945 +            if ex.faultCode == XendClient.ERROR_INVALID_DOMAIN:
  10.946 +                err("Domain '%s' does not exist." % ex.faultString)
  10.947              else:
  10.948 -                print  >>sys.stderr, "Error: %s" % ex.faultString
  10.949 +                err(ex.faultString)
  10.950 +            usage(argv[1])
  10.951              sys.exit(1)
  10.952          except xmlrpclib.ProtocolError, ex:
  10.953              if ex.errcode == -1:
  10.954 @@ -1364,6 +1468,10 @@ def main(argv=sys.argv):
  10.955          except (ValueError, OverflowError):
  10.956              err("Invalid argument.")
  10.957              usage(argv[1])
  10.958 +        except OptionError, e:
  10.959 +            err(str(e))
  10.960 +            usage(argv[1])
  10.961 +            print e.usage()
  10.962          except:
  10.963              print "Unexpected error:", sys.exc_info()[0]
  10.964              print
    11.1 --- a/tools/python/xen/xm/makepolicy.py	Fri Sep 22 11:33:03 2006 +0100
    11.2 +++ b/tools/python/xen/xm/makepolicy.py	Fri Sep 22 11:37:31 2006 +0100
    11.3 @@ -20,7 +20,7 @@
    11.4  import sys
    11.5  import traceback
    11.6  from xen.util.security import ACMError, err, make_policy
    11.7 -
    11.8 +from xen.xm.opts import OptionError
    11.9  
   11.10  def usage():
   11.11      print "\nUsage: xm makepolicy <policy>\n"
   11.12 @@ -29,13 +29,12 @@ def usage():
   11.13      err("Usage")
   11.14  
   11.15  
   11.16 +def main(argv):
   11.17 +    if len(argv) != 2:
   11.18 +        raise OptionError('No XML policy file specified')
   11.19  
   11.20 -def main(argv):
   11.21      try:
   11.22 -        if len(argv) != 2:
   11.23 -            usage()
   11.24          make_policy(argv[1])
   11.25 -
   11.26      except ACMError:
   11.27          sys.exit(-1)
   11.28      except:
   11.29 @@ -43,7 +42,6 @@ def main(argv):
   11.30          sys.exit(-1)
   11.31  
   11.32  
   11.33 -
   11.34  if __name__ == '__main__':
   11.35      main(sys.argv)
   11.36  
    12.1 --- a/tools/python/xen/xm/migrate.py	Fri Sep 22 11:33:03 2006 +0100
    12.2 +++ b/tools/python/xen/xm/migrate.py	Fri Sep 22 11:37:31 2006 +0100
    12.3 @@ -46,19 +46,17 @@ gopts.opt('resource', short='r', val='MB
    12.4            fn=set_int, default=0,
    12.5            use="Set level of resource usage for migration.")
    12.6  
    12.7 -def help(argv):
    12.8 -    gopts.argv = argv
    12.9 -    gopts.usage()
   12.10 +def help():
   12.11 +    return str(gopts)
   12.12      
   12.13  def main(argv):
   12.14      opts = gopts
   12.15      args = opts.parse(argv)
   12.16 -    if opts.vals.help:
   12.17 -        opts.usage()
   12.18 -        return
   12.19 +    
   12.20      if len(args) != 2:
   12.21 -        opts.usage()
   12.22 -        sys.exit(1)
   12.23 +        raise OptionError('Invalid number of arguments')
   12.24 +
   12.25      dom = args[0]
   12.26      dst = args[1]
   12.27 -    server.xend.domain.migrate(dom, dst, opts.vals.live, opts.vals.resource, opts.vals.port)
   12.28 +    server.xend.domain.migrate(dom, dst, opts.vals.live, opts.vals.resource,
   12.29 +                               opts.vals.port)
    13.1 --- a/tools/python/xen/xm/opts.py	Fri Sep 22 11:33:03 2006 +0100
    13.2 +++ b/tools/python/xen/xm/opts.py	Fri Sep 22 11:37:31 2006 +0100
    13.3 @@ -24,6 +24,46 @@ import os.path
    13.4  import sys
    13.5  import types
    13.6  
    13.7 +def wrap(text, width = 70):
    13.8 +    """ Really basic textwrap. Useful because textwrap is not available
    13.9 +    for Python 2.2, and textwrap.wrap ignores newlines in Python 2.3+.
   13.10 +    """
   13.11 +    import string
   13.12 +    
   13.13 +    if len(text) < width:
   13.14 +        return [text]
   13.15 +    
   13.16 +    lines = []
   13.17 +    for line in text.split('\n'):
   13.18 +        line = line.strip()
   13.19 +        if len(line) < width:
   13.20 +            lines.append(line)
   13.21 +            continue
   13.22 +        
   13.23 +        pos = 0
   13.24 +        while pos <= len(line):
   13.25 +            wline = line[pos:pos+width].strip()
   13.26 +            if len(wline) < 2:
   13.27 +                break
   13.28 +            
   13.29 +            if wline[-1] in tuple(string.punctuation):
   13.30 +                pos += width
   13.31 +            else:
   13.32 +                lastword = wline.split()[-1]
   13.33 +                wline = wline[:-len(lastword)]
   13.34 +                pos += width - len(lastword)
   13.35 +            lines.append(wline)
   13.36 +                
   13.37 +    return lines
   13.38 +
   13.39 +class OptionError(Exception):
   13.40 +    """Denotes an error in option parsing."""
   13.41 +    def __init__(self, message, usage = ''):
   13.42 +        self.message = message
   13.43 +        self.usage = usage
   13.44 +    def __str__(self):
   13.45 +        return self.message
   13.46 +
   13.47  class Opt:
   13.48      """An individual option.
   13.49      """
   13.50 @@ -72,7 +112,21 @@ class Opt:
   13.51      def __repr__(self):
   13.52          return self.name + '=' + str(self.specified_val)
   13.53  
   13.54 -    __str__ = __repr__
   13.55 +    def __str__(self):
   13.56 +        """ Formats the option into:
   13.57 +        '-k, --key     description'
   13.58 +        """
   13.59 +        PARAM_WIDTH = 20
   13.60 +        if self.val:
   13.61 +            keys = ', '.join(['%s=%s' % (k, self.val) for k in self.optkeys])
   13.62 +        else:
   13.63 +            keys = ', '.join(self.optkeys)
   13.64 +        desc = wrap(self.use, 55)
   13.65 +        if len(keys) > PARAM_WIDTH:
   13.66 +            desc = [''] + desc
   13.67 +            
   13.68 +        wrapped = ('\n' + ' ' * (PARAM_WIDTH + 1)).join(desc)
   13.69 +        return keys.ljust(PARAM_WIDTH + 1) + wrapped
   13.70  
   13.71      def set(self, value):
   13.72          """Set the option value.
   13.73 @@ -243,7 +297,19 @@ class Opts:
   13.74      def __repr__(self):
   13.75          return '\n'.join(map(str, self.options))
   13.76  
   13.77 -    __str__ = __repr__
   13.78 +    def __str__(self):
   13.79 +        options = [s for s in self.options if s.optkeys[0][0] == '-']
   13.80 +        optvals = [s for s in self.options if s.optkeys[0][0] != '-']
   13.81 +        output = ''
   13.82 +        if options:
   13.83 +            output += '\nOptions:\n\n'
   13.84 +            output += '\n'.join([str(o) for o in options])
   13.85 +            output += '\n'
   13.86 +        if optvals:
   13.87 +            output += '\nValues:\n\n'
   13.88 +            output += '\n'.join([str(o) for o in optvals])
   13.89 +            output += '\n'
   13.90 +        return output
   13.91  
   13.92      def opt(self, name, **args):
   13.93          """Add an option.
   13.94 @@ -338,14 +404,14 @@ class Opts:
   13.95                                                self.short_opts(),
   13.96                                                self.long_opts())
   13.97              except getopt.GetoptError, err:
   13.98 -                self.err(str(err))
   13.99 +                raise OptionError(str(err), self.use)
  13.100 +            #self.err(str(err))
  13.101                  
  13.102              for (k, v) in xvals:
  13.103                  for opt in self.options:
  13.104                      if opt.specify(k, v): break
  13.105                  else:
  13.106 -                    print >>sys.stderr, "Error: Unknown option:", k
  13.107 -                    self.usage()
  13.108 +                    raise OptionError('Unknown option: %s' % k, self.use)
  13.109  
  13.110              if not args:
  13.111                  break
  13.112 @@ -390,10 +456,10 @@ class Opts:
  13.113      def usage(self):
  13.114          print 'Usage: ', self.argv[0], self.use or 'OPTIONS'
  13.115          print
  13.116 -        for opt in self.options:
  13.117 -            opt.show()
  13.118 -            print
  13.119          if self.options:
  13.120 +            for opt in self.options:
  13.121 +                opt.show()
  13.122 +                print
  13.123              print
  13.124  
  13.125      def var_usage(self):
  13.126 @@ -427,7 +493,9 @@ class Opts:
  13.127                  self.load(p, help)
  13.128                  break
  13.129          else:
  13.130 -            self.err('Cannot open config file "%s"' % self.vals.defconfig)
  13.131 +            raise OptionError('Unable to open config file: %s' % \
  13.132 +                              self.vals.defconfig,
  13.133 +                              self.use)
  13.134  
  13.135      def load(self, defconfig, help):
  13.136          """Load a defconfig file. Local variables in the file
  13.137 @@ -478,9 +546,9 @@ def set_false(opt, k, v):
  13.138  def set_bool(opt, k, v):
  13.139      """Set a boolean option.
  13.140      """
  13.141 -    if v in ['yes']:
  13.142 +    if v in ('yes', 'y'):
  13.143          opt.set(1)
  13.144 -    elif v in ['no']:
  13.145 +    elif v in ('no', 'n'):
  13.146          opt.set(0)
  13.147      else:
  13.148          opt.opts.err('Invalid value:' +v)
    14.1 --- a/tools/python/xen/xm/resources.py	Fri Sep 22 11:33:03 2006 +0100
    14.2 +++ b/tools/python/xen/xm/resources.py	Fri Sep 22 11:37:31 2006 +0100
    14.3 @@ -21,13 +21,12 @@
    14.4  import sys
    14.5  from xen.util import dictio
    14.6  from xen.util import security
    14.7 +from xen.xm.opts import OptionError
    14.8  
    14.9 -def usage():
   14.10 -    print "\nUsage: xm resource\n"
   14.11 -    print "  This program lists information for each resource in the"
   14.12 -    print "  global resource label file\n"
   14.13 -    security.err("Usage")
   14.14 -
   14.15 +def help():
   14.16 +    return """Usage: xm resource
   14.17 +    This program lists information for each resource in the
   14.18 +    global resource label file."""
   14.19  
   14.20  def print_resource_data(access_control):
   14.21      """Prints out a resource dictionary to stdout
   14.22 @@ -38,11 +37,16 @@ def print_resource_data(access_control):
   14.23          print "    policy: "+policy
   14.24          print "    label:  "+label
   14.25  
   14.26 -
   14.27  def main (argv):
   14.28 +    if len(argv) > 1:
   14.29 +        raise OptionError("No arguments required")
   14.30 +    
   14.31      try:
   14.32 -        if len(argv) != 1:
   14.33 -            usage()
   14.34 +        filename = security.res_label_filename
   14.35 +        access_control = dictio.dict_read("resources", filename)
   14.36 +    except:
   14.37 +        print "Resource file not found."
   14.38 +        return
   14.39  
   14.40          try:
   14.41              file = security.res_label_filename
   14.42 @@ -52,9 +56,6 @@ def main (argv):
   14.43  
   14.44          print_resource_data(access_control)
   14.45  
   14.46 -    except security.ACMError:
   14.47 -        sys.exit(-1)
   14.48 -
   14.49  if __name__ == '__main__':
   14.50      main(sys.argv)
   14.51  
    15.1 --- a/tools/python/xen/xm/rmlabel.py	Fri Sep 22 11:33:03 2006 +0100
    15.2 +++ b/tools/python/xen/xm/rmlabel.py	Fri Sep 22 11:37:31 2006 +0100
    15.3 @@ -21,15 +21,17 @@
    15.4  import sys, os, re
    15.5  from xen.util import dictio
    15.6  from xen.util import security
    15.7 +from xen.xm.opts import OptionError
    15.8  
    15.9 -def usage():
   15.10 -    print "\nUsage: xm rmlabel dom <configfile>"
   15.11 -    print "       xm rmlabel res <resource>\n"
   15.12 -    print "  This program removes an acm_label entry from the 'configfile'"
   15.13 -    print "  for a domain or from the global resource label file for a"
   15.14 -    print "  resource. If the label does not exist for the given domain or"
   15.15 -    print "  resource, then rmlabel fails.\n"
   15.16 -    security.err("Usage")
   15.17 +def help():
   15.18 +    return """
   15.19 +    Example: xm rmlabel dom <configfile>
   15.20 +             xm rmlabel res <resource>
   15.21 +
   15.22 +    This program removes an acm_label entry from the 'configfile'
   15.23 +    for a domain or from the global resource label file for a
   15.24 +    resource. If the label does not exist for the given domain or
   15.25 +    resource, then rmlabel fails."""
   15.26  
   15.27  
   15.28  def rm_resource_label(resource):
   15.29 @@ -93,23 +95,23 @@ def rm_domain_label(configfile):
   15.30  
   15.31  
   15.32  def main (argv):
   15.33 +
   15.34 +    if len(argv) != 3:
   15.35 +        raise OptionError('Requires 2 arguments')
   15.36 +    
   15.37 +    if argv[1].lower() not in ('dom', 'res'):
   15.38 +        raise OptionError('Unrecognised type argument: %s' % argv[1])
   15.39 +
   15.40      try:
   15.41 -        if len(argv) != 3:
   15.42 -            usage()
   15.43 -
   15.44          if argv[1].lower() == "dom":
   15.45              configfile = argv[2]
   15.46              rm_domain_label(configfile)
   15.47          elif argv[1].lower() == "res":
   15.48              resource = argv[2]
   15.49              rm_resource_label(resource)
   15.50 -        else:
   15.51 -            usage()
   15.52 -
   15.53      except security.ACMError:
   15.54          sys.exit(-1)
   15.55  
   15.56 -
   15.57  if __name__ == '__main__':
   15.58      main(sys.argv)
   15.59  
    16.1 --- a/tools/python/xen/xm/sysrq.py	Fri Sep 22 11:33:03 2006 +0100
    16.2 +++ b/tools/python/xen/xm/sysrq.py	Fri Sep 22 11:37:31 2006 +0100
    16.3 @@ -19,14 +19,12 @@ gopts.opt('help', short='h',
    16.4  def main(argv):
    16.5      opts = gopts
    16.6      args = opts.parse(argv)
    16.7 -    if opts.vals.help:
    16.8 -        opts.usage()
    16.9 -        return
   16.10 -        
   16.11 -    # no options for the moment
   16.12 -    if len(args) != 2:
   16.13 -        opts.usage()
   16.14 -        sys.exit(1)
   16.15 +
   16.16 +    if len(args) < 1:
   16.17 +        raise OptionError('Missing domain argument')
   16.18 +    if len(args) < 2:
   16.19 +        raise OptionError('Missing sysrq character')
   16.20 +
   16.21      dom = args[0]
   16.22      req = ord(args[1][0])
   16.23      server.xend.domain.send_sysrq(dom, req)