diff options
author | Sol Jerome <solj@ices.utexas.edu> | 2008-09-12 21:25:16 +0000 |
---|---|---|
committer | Sol Jerome <solj@ices.utexas.edu> | 2008-09-12 21:25:16 +0000 |
commit | 01e56e153fd83c0b51760cf4ec04cc07e39bcc1b (patch) | |
tree | 8999bb657bb258d41d83244c0506c43956775512 | |
parent | cd78f764f64ea2984c6382a20b7ffd7d44345995 (diff) | |
download | bcfg2-01e56e153fd83c0b51760cf4ec04cc07e39bcc1b.tar.gz bcfg2-01e56e153fd83c0b51760cf4ec04cc07e39bcc1b.tar.bz2 bcfg2-01e56e153fd83c0b51760cf4ec04cc07e39bcc1b.zip |
Improve help messages for bcfg2-admin (and modes)
git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@4910 ce84e21b-d406-0410-9b95-82705330c041
-rw-r--r-- | src/lib/Server/Admin/Client.py | 20 | ||||
-rw-r--r-- | src/lib/Server/Admin/Compare.py | 30 | ||||
-rw-r--r-- | src/lib/Server/Admin/Fingerprint.py | 7 | ||||
-rw-r--r-- | src/lib/Server/Admin/Init.py | 25 | ||||
-rw-r--r-- | src/lib/Server/Admin/Minestruct.py | 27 | ||||
-rw-r--r-- | src/lib/Server/Admin/Pull.py | 34 | ||||
-rw-r--r-- | src/lib/Server/Admin/Query.py | 20 | ||||
-rw-r--r-- | src/lib/Server/Admin/Tidy.py | 17 | ||||
-rw-r--r-- | src/lib/Server/Admin/Viz.py | 28 | ||||
-rw-r--r-- | src/lib/Server/Admin/__init__.py | 9 | ||||
-rwxr-xr-x | src/sbin/bcfg2-admin | 12 |
11 files changed, 157 insertions, 72 deletions
diff --git a/src/lib/Server/Admin/Client.py b/src/lib/Server/Admin/Client.py index 1f784a4f2..a0b24a71b 100644 --- a/src/lib/Server/Admin/Client.py +++ b/src/lib/Server/Admin/Client.py @@ -2,20 +2,22 @@ import Bcfg2.Server.Admin from Bcfg2.Server.Plugins.Metadata import MetadataConsistencyError class Client(Bcfg2.Server.Admin.MetadataCore): - __shorthelp__ = 'bcfg2-admin client add <client> attr1=val1 attr2=val2\nbcfg2-admin client del <client>' - __longhelp__ = __shorthelp__ + '\n\tCreate or delete client entries' + __shorthelp__ = "Create or delete client entries" + __longhelp__ = (__shorthelp__ + "\n\nbcfg2-admin client add <client> " + "attr1=val1 attr2=val2\n" + "bcfg2-admin client del <client>") + __usage__ = ("bcfg2-admin client [options] [add|del] [attr=val]") + def __init__(self, configfile): - Bcfg2.Server.Admin.MetadataCore.__init__(self, configfile) + Bcfg2.Server.Admin.MetadataCore.__init__(self, configfile, + self.__usage__) def __call__(self, args): Bcfg2.Server.Admin.MetadataCore.__call__(self, args) if len(args) == 0: - self.errExit("Client mode requires at least one argument: <add> or <delete>") - if "-h" in args: - print "Usage: " - print self.__shorthelp__ - raise SystemExit(1) - if args[0] == 'add': + self.errExit("No argument specified.\n" + "Please see bcfg2-admin client help for usage.") + if args[0] == 'add': attr_d = {} for i in args[2:]: attr, val = i.split('=', 1) diff --git a/src/lib/Server/Admin/Compare.py b/src/lib/Server/Admin/Compare.py index 124c0c647..f97233b0e 100644 --- a/src/lib/Server/Admin/Compare.py +++ b/src/lib/Server/Admin/Compare.py @@ -1,13 +1,16 @@ - import lxml.etree, os import Bcfg2.Server.Admin class Compare(Bcfg2.Server.Admin.Mode): - __shorthelp__ = "bcfg2-admin compare <file1> <file2>\nbcfg2-admin compare -r <dir1> <dir2>" - __longhelp__ = __shorthelp__ + '''\n\tCompare mode determines differences between directories of client specification instances''' - - def __init__(self): - Bcfg2.Server.Admin.Mode.__init__(self) + __shorthelp__ = ("Determine differences between files or " + "directories of client specification instances") + __longhelp__ = (__shorthelp__ + "\n\nbcfg2-admin compare <file1> <file2>" + "\nbcfg2-admin compare -r <dir1> <dir2>") + __usage__ = ("bcfg2-admin compare <old> <new>\n\n" + " -r\trecursive") + + def __init__(self, configfile): + Bcfg2.Server.Admin.Mode.__init__(self, configfile) self.important = {'Package':['name', 'version'], 'Service':['name', 'status'], 'Directory':['name', 'owner', 'group', 'perms'], @@ -15,15 +18,17 @@ class Compare(Bcfg2.Server.Admin.Mode): 'ConfigFile':['name', 'owner', 'group', 'perms'], 'Permissions':['name', 'perms'], 'PostInstall':['name']} - + def compareStructures(self, new, old): for child in new.getchildren(): - equiv = old.xpath('%s[@name="%s"]' % (child.tag, child.get('name'))) + equiv = old.xpath('%s[@name="%s"]' % + (child.tag, child.get('name'))) if child.tag in self.important: print "tag type %s not handled" % (child.tag) continue if len(equiv) == 0: - print "didn't find matching %s %s" % (child.tag, child.get('name')) + print ("didn't find matching %s %s" % + (child.tag, child.get('name'))) continue elif len(equiv) >= 1: if child.tag == 'ConfigFile': @@ -106,6 +111,9 @@ class Compare(Bcfg2.Server.Admin.Mode): def __call__(self, args): Bcfg2.Server.Admin.Mode.__call__(self, args) + if len(args) == 0: + self.errExit("No argument specified.\n" + "Please see bcfg2-admin compare help for usage.") if '-r' in args: args = list(args) args.remove('-r') @@ -126,6 +134,4 @@ class Compare(Bcfg2.Server.Admin.Mode): (old, new) = args except IndexError: print self.__call__.__doc__ - raise SystemExit - - + raise SystemExit(1) diff --git a/src/lib/Server/Admin/Fingerprint.py b/src/lib/Server/Admin/Fingerprint.py index aff8d42bf..39a180d51 100644 --- a/src/lib/Server/Admin/Fingerprint.py +++ b/src/lib/Server/Admin/Fingerprint.py @@ -5,11 +5,12 @@ import Bcfg2.Server.Admin class Fingerprint(Bcfg2.Server.Admin.Mode): '''Produce server key fingerprint''' - __shorthelp__ = 'bcfg2-admin fingerprint' - __longhelp__ = __shorthelp__ + '\n\tPrint the server certificate fingerprint' + __shorthelp__ = "Print the server certificate fingerprint" + __longhelp__ = __shorthelp__ + "\n\nbcfg2-admin fingerprint" + __usage__ = "bcfg2-admin fingerprint" def __init__(self, cfile): - Bcfg2.Server.Admin.Mode.__init__(self, cfile) + Bcfg2.Server.Admin.Mode.__init__(self, cfile) def __call__(self, args): Bcfg2.Server.Admin.Mode.__call__(self, args) diff --git a/src/lib/Server/Admin/Init.py b/src/lib/Server/Admin/Init.py index c97d82133..941ef1596 100644 --- a/src/lib/Server/Admin/Init.py +++ b/src/lib/Server/Admin/Init.py @@ -70,8 +70,10 @@ os_list = [ class Init(Bcfg2.Server.Admin.Mode): - __shorthelp__ = 'bcfg2-admin init' - __longhelp__ = __shorthelp__ + '\n\tCompare two client specifications or directories of specifications' # FIXME + __shorthelp__ = ("Compare two client specifications or " + "directories of specifications") # FIXME + __longhelp__ = __shorthelp__ + "\n\nbcfg2-admin init" + __usage__ = "bcfg2-admin init" options = { 'configfile': Bcfg2.Options.CFILE, 'gens' : Bcfg2.Options.SERVER_GENERATORS, @@ -87,11 +89,13 @@ class Init(Bcfg2.Server.Admin.Mode): opts.parse([]) # FIXME don't overwrite existing bcfg2.conf file - configfile = raw_input("Store bcfg2 configuration in [%s]: " % opts['configfile']) + configfile = raw_input("Store bcfg2 configuration in [%s]: " % + opts['configfile']) if configfile == '': configfile = opts['configfile'] - repopath = raw_input("Location of bcfg2 repository [%s]: " % opts['repo']) + repopath = raw_input("Location of bcfg2 repository [%s]: " % + opts['repo']) if repopath == '': repopath = opts['repo'] @@ -112,7 +116,8 @@ class Init(Bcfg2.Server.Admin.Mode): prompt += "%d: %s\n" % (os_list.index(entry) + 1, entry[0]) prompt += ': ' os_sel = os_list[int(raw_input(prompt))-1][1] - self.initializeRepo(configfile, repopath, server, password, os_sel, opts) + self.initializeRepo(configfile, repopath, server, + password, os_sel, opts) print "Repository created successfuly in %s" % (repopath) def genPassword(self): @@ -138,11 +143,11 @@ class Init(Bcfg2.Server.Admin.Mode): except: # FIXME how to handle print "Failed to write configuration file to '%s'\n" % configfile - pass # FIXME automate ssl key generation # FIXME key generation may fail as non-root user - os.popen('openssl req -x509 -nodes -days 1000 -newkey rsa:1024 -out %s/bcfg2.key -keyout %s/bcfg2.key' % (keypath, keypath)) + os.popen('openssl req -x509 -nodes -days 1000 -newkey rsa:1024 -out' \ + '%s/bcfg2.key -keyout %s/bcfg2.key' % (keypath, keypath)) try: os.chmod('%s/bcfg2.key'% keypath, 0600) except: @@ -161,5 +166,7 @@ class Init(Bcfg2.Server.Admin.Mode): except: continue - open("%s/Metadata/groups.xml" % repo, "w").write(groups % os_selection) - open("%s/Metadata/clients.xml" % repo, "w").write(clients % socket.getfqdn()) + open("%s/Metadata/groups.xml" % + repo, "w").write(groups % os_selection) + open("%s/Metadata/clients.xml" % + repo, "w").write(clients % socket.getfqdn()) diff --git a/src/lib/Server/Admin/Minestruct.py b/src/lib/Server/Admin/Minestruct.py index 0bf7a5797..cc2a25533 100644 --- a/src/lib/Server/Admin/Minestruct.py +++ b/src/lib/Server/Admin/Minestruct.py @@ -4,22 +4,32 @@ import lxml.etree, sys, getopt class Minestruct(Bcfg2.Server.Admin.StructureMode): '''Pull extra entries out of statistics''' - __shorthelp__ = 'bcfg2-admin minestruct [-f file-name] [-g groups] client' - __longhelp__ = __shorthelp__ + '\n\tExtract extra entry lists from statistics' + __shorthelp__ = "Extract extra entry lists from statistics" + __longhelp__ = (__shorthelp__ + + "\n\nbcfg2-admin minestruct [-f filename] " + "[-g groups] client") + __usage__ = ("bcfg2-admin minestruct [options] <client>\n\n" + " %-25s%s\n" + " %-25s%s\n" % + ("-f <filename>", + "build a particular file", + "-g <groups>", + "only build config for groups")) + + def __init__(self, configfile): + Bcfg2.Server.Admin.MetadataCore.__init__(self, configfile, + self.__usage__) def __call__(self, args): Bcfg2.Server.Admin.Mode.__call__(self, args) if len(args) == 0: - self.errExit("No hostname specified (see bcfg2-admin minestruct -h for help)") + self.errExit("No argument specified.\n" + "Please see bcfg2-admin minestruct help for usage.") try: (opts, args) = getopt.getopt(args, 'f:g:h') except: self.log.error(self.__shorthelp__) raise SystemExit(1) - if "-h" in args or not args: - print "Usage:" - print self.__shorthelp__ - raise SystemExit(1) client = args[0] output = sys.stdout @@ -38,7 +48,8 @@ class Minestruct(Bcfg2.Server.Admin.StructureMode): try: extra = self.statistics.GetExtra(client) except: - self.log.error("Failed to find extra entry info for client %s" % client) + self.log.error("Failed to find extra entry info for client %s" % + client) raise SystemExit(1) root = lxml.etree.Element("Base") self.log.info("Found %d extra entries" % (len(extra))) diff --git a/src/lib/Server/Admin/Pull.py b/src/lib/Server/Admin/Pull.py index 6591cd604..6695ca715 100644 --- a/src/lib/Server/Admin/Pull.py +++ b/src/lib/Server/Admin/Pull.py @@ -1,14 +1,31 @@ - import binascii, difflib, getopt, lxml.etree, time, ConfigParser import Bcfg2.Server.Admin class Pull(Bcfg2.Server.Admin.MetadataCore): - '''Pull mode retrieves entries from clients and integrates the information into the repository''' - __shorthelp__ = 'bcfg2-admin pull [-v] [-f] [-I] <client> <entry type> <entry name>' - __longhelp__ = __shorthelp__ + '\n\tIntegrate configuration information from clients into the server repository' + ''' + Pull mode retrieves entries from clients and + integrates the information into the repository + ''' + __shorthelp__ = ("Integrate configuration information " + "from clients into the server repository") + __longhelp__ = (__shorthelp__ + "\n\nbcfg2-admin pull [-v] [-f][-I]" + "<client> <entry type> <entry name>") + __usage__ = ("bcfg2-admin pull [options] <client> <entry type> " + "<entry name>\n\n" + " %-25s%s\n" + " %-25s%s\n" + " %-25s%s\n" % + ("-v", + "be verbose", + "-f", + "force", + "-I", + "interactive")) allowed = ['Metadata', 'BB', "DBStats", "Statistics", "Cfg", "SSHbase"] + def __init__(self, configfile): - Bcfg2.Server.Admin.MetadataCore.__init__(self, configfile) + Bcfg2.Server.Admin.MetadataCore.__init__(self, configfile, + self.__usage__) self.stats = self.bcore.stats self.log = False self.mode = 'interactive' @@ -19,7 +36,7 @@ class Pull(Bcfg2.Server.Admin.MetadataCore): opts, gargs = getopt.getopt(args, 'vfI') except: print self.__shorthelp__ - raise SystemExit(0) + raise SystemExit(1) for opt in opts: if opt[0] == '-v': self.log = True @@ -37,7 +54,7 @@ class Pull(Bcfg2.Server.Admin.MetadataCore): self.stats.GetCurrentEntry(client, etype, ename) except Bcfg2.Server.Plugin.PluginExecutionError: print "Statistics plugin failure; could not fetch current state" - raise SystemExit, 1 + raise SystemExit(1) data = {'owner':owner, 'group':group, 'perms':perms, 'text':contents} for k, v in data.iteritems(): @@ -54,7 +71,8 @@ class Pull(Bcfg2.Server.Admin.MetadataCore): if choices[0].all: print " => global entry" elif choices[0].group: - print " => group entry: %s (prio %d)" % (choices[0].group, choices[0].prio) + print (" => group entry: %s (prio %d)" % + (choices[0].group, choices[0].prio)) else: print " => host entry: %s" % (choices[0].hostname) if raw_input("Use this entry? [yN]: ") in ['y', 'Y']: diff --git a/src/lib/Server/Admin/Query.py b/src/lib/Server/Admin/Query.py index 296749cf7..6df7021e5 100644 --- a/src/lib/Server/Admin/Query.py +++ b/src/lib/Server/Admin/Query.py @@ -1,8 +1,20 @@ import Bcfg2.Server.Admin, Bcfg2.Logger, logging class Query(Bcfg2.Server.Admin.Mode): - __shorthelp__ = 'bcfg2-admin query [-n] [-c] [-f filename] g=group p=profile' - __longhelp__ = __shorthelp__ + '\n\tQuery clients' + __shorthelp__ = "Query clients" + __longhelp__ = (__shorthelp__ + "\nbcfg2-admin query [-n] [-c] " + "[-f filename] g=group p=profile") + __usage__ = ("bcfg2-admin query [options] <g=group> <p=profile>\n\n" + " %-25s%s\n" + " %-25s%s\n" + " %-25s%s\n" % + ("-n", + "query results delimited with newlines", + "-c", + "query results delimited with commas", + "-f filename", + "write query to file")) + def __init__(self, cfile): logging.root.setLevel(100) Bcfg2.Logger.setup_logging(100, to_console=False, to_syslog=False) @@ -39,9 +51,9 @@ class Query(Bcfg2.Server.Admin.Mode): print "Unknown argument %s" % arg continue if k == 'p': - nc = self.meta.GetClientByProfile(v) + nc = self.meta.GetClientByProfile(v) elif k == 'g': - nc = self.meta.GetClientByGroup(v) + nc = self.meta.GetClientByGroup(v) clients = [c for c in clients if c in nc] if '-n' in args: for client in clients: diff --git a/src/lib/Server/Admin/Tidy.py b/src/lib/Server/Admin/Tidy.py index 287b34310..b53bde5ef 100644 --- a/src/lib/Server/Admin/Tidy.py +++ b/src/lib/Server/Admin/Tidy.py @@ -2,11 +2,19 @@ import Bcfg2.Server.Admin import re, os, socket class Tidy(Bcfg2.Server.Admin.Mode): - __shorthelp__ = 'bcfg2-admin tidy [-f] [-I]' - __longhelp__ = __shorthelp__ + '\n\tClean up useless files in the repo' + __shorthelp__ = "Clean up useless files in the repo" + __longhelp__ = __shorthelp__ + "\nbcfg2-admin tidy [-f] [-I]" + __usage__ = ("bcfg2-admin tidy [options]\n\n" + " %-25s%s\n" + " %-25s%s\n" + " %-25s%s\n" % + ("-f", + "force", + "-I", + "interactive")) def __init__(self, cfile): - Bcfg2.Server.Admin.Mode.__init__(self, cfile) + Bcfg2.Server.Admin.Mode.__init__(self, cfile) def __call__(self, args): Bcfg2.Server.Admin.Mode.__call__(self, args) @@ -49,7 +57,8 @@ class Tidy(Bcfg2.Server.Admin.Mode): to_remove.append("%s/SSHbase/%s" % (self.get_repo_path(), name)) else: if hostmatcher.match(name).group(1) in bad: - to_remove.append("%s/SSHbase/%s" % (self.get_repo_path(), name)) + to_remove.append("%s/SSHbase/%s" % + (self.get_repo_path(), name)) # clean up file~ # clean up files without parsable names in Cfg return to_remove diff --git a/src/lib/Server/Admin/Viz.py b/src/lib/Server/Admin/Viz.py index 0afb6a121..0a5a8b9d6 100644 --- a/src/lib/Server/Admin/Viz.py +++ b/src/lib/Server/Admin/Viz.py @@ -1,17 +1,32 @@ - -import getopt, popen2, lxml.etree +import getopt, popen2 import Bcfg2.Server.Admin class Viz(Bcfg2.Server.Admin.MetadataCore): - __shorthelp__ = '''bcfg2-admin viz [--includehosts] [--includebundles] [--includekey] [-o output.png] [--raw]''' - __longhelp__ = __shorthelp__ + '\n\tProduce graphviz diagrams of metadata structures' + __shorthelp__ = "Produce graphviz diagrams of metadata structures" + __longhelp__ = (__shorthelp__ + "\n\nbcfg2-admin viz [--includehosts] " + "[--includebundles] [--includekey] " + "[-o output.png] [--raw]") + __usage__ = ("bcfg2-admin viz [options]\n\n" + " %-25s%s\n" + " %-25s%s\n" + " %-25s%s\n" + " %-25s%s\n" % + ("-H, --includehosts", + "include hosts in the viz output", + "-b, --includebundles", + "include bundles in the viz output", + "-k, --includekey", + "show a key for different digraph shapes", + "-o, --outfile <file>", + "write viz output to an output file")) colors = ['steelblue1', 'chartreuse', 'gold', 'magenta', 'indianred1', 'limegreen', 'orange1', 'lightblue2', 'green1', 'blue1', 'yellow1', 'darkturquoise', 'gray66'] def __init__(self, cfile): - Bcfg2.Server.Admin.MetadataCore.__init__(self, cfile) + Bcfg2.Server.Admin.MetadataCore.__init__(self, cfile, + self.__usage__) def __call__(self, args): Bcfg2.Server.Admin.MetadataCore.__call__(self, args) @@ -63,7 +78,8 @@ class Viz(Bcfg2.Server.Admin.MetadataCore): print "write to dot process failed. Is graphviz installed?" raise SystemExit(1) dotpipe.tochild.write('\trankdir="LR";\n') - dotpipe.tochild.write(self.metadata.viz(hosts, bundles, key, self.colors)) + dotpipe.tochild.write(self.metadata.viz(hosts, bundles, + key, self.colors)) if key: dotpipe.tochild.write("\tsubgraph cluster_key {\n") dotpipe.tochild.write('''\tstyle="filled";\n''') diff --git a/src/lib/Server/Admin/__init__.py b/src/lib/Server/Admin/__init__.py index cd99cb801..ee06a33d0 100644 --- a/src/lib/Server/Admin/__init__.py +++ b/src/lib/Server/Admin/__init__.py @@ -40,7 +40,8 @@ class Mode(object): return self.cfp.get('server', 'repository') def load_stats(self, client): - stats = lxml.etree.parse("%s/etc/statistics.xml" % (self.get_repo_path())) + stats = lxml.etree.parse("%s/etc/statistics.xml" % + (self.get_repo_path())) hostent = stats.xpath('//Node[@name="%s"]' % client) if not hostent: self.errExit("Could not find stats for client %s" % (client)) @@ -49,12 +50,13 @@ class Mode(object): class MetadataCore(Mode): allowed = ['Metadata', 'BB'] '''Base class for admin-modes that handle metadata''' - def __init__(self, configfile): + def __init__(self, configfile, usage): Mode.__init__(self, configfile) options = {'plugins': Bcfg2.Options.SERVER_PLUGINS, 'structures': Bcfg2.Options.SERVER_STRUCTURES, 'generators': Bcfg2.Options.SERVER_GENERATORS} setup = Bcfg2.Options.OptionParser(options) + setup.hm = usage setup.parse(sys.argv[1:]) plugins = [plugin for plugin in setup['plugins'] if plugin in self.allowed] @@ -64,7 +66,8 @@ class MetadataCore(Mode): if generator in self.allowed] try: self.bcore = Bcfg2.Server.Core.Core(self.get_repo_path(), plugins, - structures, generators, 'foo', False, 'UTF-8') + structures, generators, + 'foo', False, 'UTF-8') except Bcfg2.Server.Core.CoreInitError, msg: self.errExit("Core load failed because %s" % msg) [self.bcore.fam.Service() for _ in range(5)] diff --git a/src/sbin/bcfg2-admin b/src/sbin/bcfg2-admin index 2a1fc233d..bf7296517 100755 --- a/src/sbin/bcfg2-admin +++ b/src/sbin/bcfg2-admin @@ -26,23 +26,23 @@ if __name__ == '__main__': raise SystemExit(1) - do_help = False # First get the options... for opt, arg in opts: - if opt in ("-h", "--help"): - do_help = True if opt in ("-C", "--configfile"): configfile = arg modes = [x.lower() for x in Bcfg2.Server.Admin.__all__] modes.remove('mode') - if do_help or len(args) < 1 or args[0] == 'help': + if len(args) < 1 or args[0] == 'help': + sys.stdout.write("Usage: bcfg2-admin MODE [ARGS]\n\n" + "Available modes are:") if len(args) > 1: args = [args[1], args[0]] else: - for mod in [mode_import(mode) for mode in modes]: - print mod.__shorthelp__ + for mode in modes: + sys.stdout.write("\n %-12s %s" % + (mode, mode_import(mode).__shorthelp__)) raise SystemExit(0) if args[0] in modes: modname = args[0].capitalize() |