diff options
Diffstat (limited to 'src/sbin')
-rwxr-xr-x | src/sbin/bcfg2 | 29 | ||||
-rwxr-xr-x | src/sbin/bcfg2-admin | 10 | ||||
-rwxr-xr-x | src/sbin/bcfg2-build-reports | 62 | ||||
-rwxr-xr-x | src/sbin/bcfg2-info | 108 | ||||
-rwxr-xr-x | src/sbin/bcfg2-lint | 194 | ||||
-rwxr-xr-x | src/sbin/bcfg2-ping-sweep | 23 | ||||
l---------[-rwxr-xr-x] | src/sbin/bcfg2-repo-validate | 228 | ||||
-rwxr-xr-x | src/sbin/bcfg2-reports | 24 | ||||
-rwxr-xr-x | src/sbin/bcfg2-server | 3 |
9 files changed, 339 insertions, 342 deletions
diff --git a/src/sbin/bcfg2 b/src/sbin/bcfg2 index 9bc50fe65..7f7d8f5c6 100755 --- a/src/sbin/bcfg2 +++ b/src/sbin/bcfg2 @@ -3,18 +3,20 @@ """Bcfg2 Client""" __revision__ = '$Revision$' +import fcntl import logging import os import signal +import stat import sys import tempfile import time -import xmlrpclib -import fcntl import Bcfg2.Options import Bcfg2.Client.XML import Bcfg2.Client.Frame import Bcfg2.Client.Tools +# Compatibility imports +from Bcfg2.Bcfg2Py3k import xmlrpclib import Bcfg2.Proxy import Bcfg2.Logger @@ -106,7 +108,12 @@ class Client: raise SystemExit(0) if self.setup['remove'] and 'services' in self.setup['remove']: self.logger.error("Service removal is nonsensical, disable services to get former behavior") - if self.setup['remove'] not in [False, 'all', 'services', 'packages']: + if self.setup['remove'] not in [False, + 'all', + 'Services', + 'Packages', + 'services', + 'packages']: self.logger.error("Got unknown argument %s for -r" % (self.setup['remove'])) if (self.setup["file"] != False) and (self.setup["cache"] != False): print("cannot use -f and -c together") @@ -130,7 +137,9 @@ class Client: script.write(probe.text) script.close() os.close(scripthandle) - os.chmod(script.name, 0755) + os.chmod(script.name, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | + stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH | + stat.S_IWUSR) # 0755 ret.text = os.popen(script.name).read().strip() self.logger.info("Probe %s has result:\n%s" % (name, ret.text)) finally: @@ -183,7 +192,8 @@ class Client: try: probe_data = proxy.GetProbes() - except xmlrpclib.Fault, flt: + except xmlrpclib.Fault: + flt = sys.exc_info()[1] self.logger.error("Failed to download probes from bcfg2") self.logger.error(flt.faultString) raise SystemExit(1) @@ -192,7 +202,8 @@ class Client: try: probes = Bcfg2.Client.XML.XML(probe_data) - except Bcfg2.Client.XML.ParseError, syntax_error: + except Bcfg2.Client.XML.ParseError: + syntax_error = sys.exc_info()[1] self.fatal_error( "Server returned invalid probe requests: %s" % (syntax_error)) @@ -223,7 +234,8 @@ class Client: self.setup['decision']) self.logger.info("Got decision list from server:") self.logger.info(self.setup['decision_list']) - except xmlrpclib.Fault, f: + except xmlrpclib.Fault: + f = sys.exc_info()[1] if f.faultCode == 1: print("GetDecisionList method not supported by server") else: @@ -249,7 +261,8 @@ class Client: try: self.config = Bcfg2.Client.XML.XML(rawconfig) - except Bcfg2.Client.XML.ParseError, syntax_error: + except Bcfg2.Client.XML.ParseError: + syntax_error = sys.exc_info()[1] self.fatal_error("The configuration could not be parsed: %s" % (syntax_error)) return(1) diff --git a/src/sbin/bcfg2-admin b/src/sbin/bcfg2-admin index 2c9a43859..36be6ab14 100755 --- a/src/sbin/bcfg2-admin +++ b/src/sbin/bcfg2-admin @@ -2,11 +2,12 @@ """bcfg2-admin is a script that helps to administrate a Bcfg2 deployment.""" from optparse import OptionParser -from StringIO import StringIO import logging import Bcfg2.Server.Core import Bcfg2.Logger import Bcfg2.Options +# Compatibility import +from Bcfg2.Bcfg2Py3k import StringIO log = logging.getLogger('bcfg2-admin') @@ -56,14 +57,15 @@ def main(): else: # Print short help for all modes parser.print_help() - print create_description() + print(create_description()) raise SystemExit(0) if args[0] in get_modes(): modname = args[0].capitalize() try: mode_cls = mode_import(modname) - except ImportError, e: + except ImportError: + e = sys.exc_info()[1] log.error("Failed to load admin mode %s: %s" % (modname, e)) raise SystemExit(1) mode = mode_cls(options.configfile) @@ -73,7 +75,7 @@ def main(): else: log.error("Unknown mode %s" % args[0]) parser.print_help() - print create_description() + print(create_description()) raise SystemExit(1) if __name__ == '__main__': diff --git a/src/sbin/bcfg2-build-reports b/src/sbin/bcfg2-build-reports index 231f52105..7122fb300 100755 --- a/src/sbin/bcfg2-build-reports +++ b/src/sbin/bcfg2-build-reports @@ -13,8 +13,9 @@ import os import socket import sys from time import asctime, strptime -from ConfigParser import ConfigParser, NoSectionError, NoOptionError from lxml.etree import XML, XSLT, parse, Element, ElementTree, SubElement, tostring, XMLSyntaxError +# Compatibility imports +from Bcfg2.Bcfg2Py3k import ConfigParser def generatereport(rspec, nrpt): """ @@ -42,9 +43,9 @@ def generatereport(rspec, nrpt): # This line actually sorts from most recent to oldest. statisticslist.sort(lambda y, x: cmp(strptime(x.get("time")), strptime(y.get("time")))) stats = statisticslist[0] - + [node.remove(item) for item in node.findall('Statistics')] - + # Add a good tag if node is good and we wnat to report such. if reportgood == 'Y' and stats.get('state') == 'clean': SubElement(stats,"Good") @@ -52,7 +53,7 @@ def generatereport(rspec, nrpt): [stats.remove(item) for item in stats.findall("Bad") + stats.findall("Modified") if \ item.getchildren() == []] [stats.remove(item) for item in stats.findall("Modified") if reportmodified == 'N'] - + # Test for staleness -if stale add Stale tag. if stats.get("time").find(current_date) == -1: SubElement(stats,"Stale") @@ -64,7 +65,7 @@ def mail(mailbody, confi): try: mailer = confi.get('statistics', 'sendmailpath') - except (NoSectionError, NoOptionError): + except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): mailer = "/usr/sbin/sendmail" # Open a pipe to the mail program and # write the data to the pipe. @@ -72,7 +73,7 @@ def mail(mailbody, confi): pipe.write(mailbody) exitcode = pipe.close() if exitcode: - print "Exit code: %s" % exitcode + print("Exit code: %s" % exitcode) def rss(reportxml, delivery, report): """rss appends a new report to the specified rss file @@ -98,7 +99,7 @@ def rss(reportxml, delivery, report): chantitle = SubElement(channel, "title") chantitle.text = report.attrib['name'] chanlink = SubElement(channel, "link") - + # This can later link to WWW report if one gets published # simultaneously? chanlink.text = "http://www.mcs.anl.gov/cobalt/bcfg2" @@ -119,7 +120,7 @@ def www(reportxml, delivery): """www outputs report to.""" # This can later link to WWW report if one gets published - # simultaneously? + # simultaneously? for destination in delivery.findall('Destination'): fil = open(destination.attrib['address'], 'w') @@ -138,15 +139,15 @@ def pretty_print(element, level=0): """Produce a pretty-printed text representation of element.""" if element.text: fmt = "%s<%%s %%s>%%s</%%s>" % (level*" ") - data = (element.tag, (" ".join(["%s='%s'" % keyval for keyval in element.attrib.iteritems()])), + data = (element.tag, (" ".join(["%s='%s'" % keyval for keyval in list(element.attrib.items())])), element.text, element.tag) if element._children: fmt = "%s<%%s %%s>\n" % (level*" ",) + (len(element._children) * "%s") + "%s</%%s>\n" % (level*" ") - data = (element.tag, ) + (" ".join(["%s='%s'" % keyval for keyval in element.attrib.iteritems()]),) + data = (element.tag, ) + (" ".join(["%s='%s'" % keyval for keyval in list(element.attrib.items())]),) data += tuple([pretty_print(entry, level+2) for entry in element._children]) + (element.tag, ) else: fmt = "%s<%%s %%s/>\n" % (level * " ") - data = (element.tag, " ".join(["%s='%s'" % keyval for keyval in element.attrib.iteritems()])) + data = (element.tag, " ".join(["%s='%s'" % keyval for keyval in list(element.attrib.items())])) return fmt % data @@ -157,14 +158,14 @@ if __name__ == '__main__': cfpath = sys.argv[sys.argv.index('-C') + 1] else: cfpath = '/etc/bcfg2.conf' - c = ConfigParser() + c = ConfigParser.ConfigParser() c.read([cfpath]) configpath = "%s/etc/report-configuration.xml" % c.get('server', 'repository') statpath = "%s/etc/statistics.xml" % c.get('server', 'repository') clientsdatapath = "%s/Metadata/clients.xml" % c.get('server', 'repository') try: prefix = c.get('server', 'prefix') - except (NoSectionError, NoOptionError): + except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): prefix = '/usr' transformpath = "/%s/share/bcfg2/xsl-transforms/" % (prefix) @@ -172,13 +173,14 @@ if __name__ == '__main__': try: opts, args = getopt.getopt(sys.argv[1:], "C:hAc:Ns:", ["help", "all", "config=","no-ping", "stats="]) - except getopt.GetoptError, mesg: + except getopt.GetoptError: + mesg = sys.exc_info()[1] # Print help information and exit: - print "%s\nUsage:\nbcfg2-build-reports [-h][-A (include ALL clients)] [-c <configuration-file>] [-s <statistics-file>][-N (do not ping clients)]" % (mesg) - raise SystemExit, 2 + print("%s\nUsage:\nbcfg2-build-reports [-h][-A (include ALL clients)] [-c <configuration-file>] [-s <statistics-file>][-N (do not ping clients)]" % (mesg)) + raise SystemExit(2) for o, a in opts: if o in ("-h", "--help"): - print "Usage:\nbcfg2-build-reports [-h] [-c <configuration-file>] [-s <statistics-file>]" + print("Usage:\nbcfg2-build-reports [-h] [-c <configuration-file>] [-s <statistics-file>]") raise SystemExit if o in ("-A", "--all"): all=True @@ -205,17 +207,17 @@ if __name__ == '__main__': statsdata = XML(open(statpath).read()) except (IOError, XMLSyntaxError): print("bcfg2-build-reports: Failed to parse %s"%(statpath)) - raise SystemExit, 1 + raise SystemExit(1) try: configdata = XML(open(configpath).read()) except (IOError, XMLSyntaxError): print("bcfg2-build-reports: Failed to parse %s"%(configpath)) - raise SystemExit, 1 + raise SystemExit(1) try: clientsdata = XML(open(clientsdatapath).read()) except (IOError, XMLSyntaxError): print("bcfg2-build-reports: Failed to parse %s"%(clientsdatapath)) - raise SystemExit, 1 + raise SystemExit(1) # Merge data from three sources. nodereport = Element("Report", attrib={"time" : asctime()}) @@ -229,7 +231,7 @@ if __name__ == '__main__': for statel in nod.findall("Statistics"): nodel.append(statel) nodereport.append(nodel) - + if all: for nod in statsdata.findall("Node"): for client in clientsdata.findall("Client"): @@ -242,8 +244,8 @@ if __name__ == '__main__': for statel in nod.findall("Statistics"): nodel.append(statel) nodereport.append(nodel) - - + + for reprt in configdata.findall('Report'): nodereport.set("name", reprt.get("name", default="BCFG Report")) @@ -254,7 +256,7 @@ if __name__ == '__main__': for deliv in reprt.findall('Delivery'): # Is a deepcopy of procnodereport necessary? - + delivtype = deliv.get('type', default='nodes-digest') deliverymechanism = deliv.get('mechanism', default='www') @@ -269,14 +271,14 @@ if __name__ == '__main__': except: print("bcfg2-build-reports: Invalid report type or delivery mechanism.\n Can't find: "\ + transformpath + transform) - raise SystemExit, 1 + raise SystemExit(1) try: # Try to parse stylesheet. stylesheet = XSLT(parse(transformpath + transform)) except: print("bcfg2-build-reports: invalid XSLT transform file.") - raise SystemExit, 1 - + raise SystemExit(1) + if deliverymechanism == 'mail': if delivtype == 'nodes-individual': reportdata = copy.deepcopy(procnodereport) @@ -285,7 +287,7 @@ if __name__ == '__main__': reportdata.append(noden) result = stylesheet.apply(ElementTree(reportdata)) outputstring = stylesheet.tostring(result) - + if not outputstring == None: toastring = '' for desti in deliv.findall("Destination"): @@ -295,13 +297,13 @@ if __name__ == '__main__': outputstring = "To: %s\nFrom: root@%s\n%s"% \ (toastring, socket.getfqdn(), outputstring) mail(outputstring, c) #call function to send - + else: reportdata = copy.deepcopy(procnodereport) result = stylesheet.apply(ElementTree(reportdata)) outputstring = stylesheet.tostring(result) - + if not outputstring == None: toastring = '' for desti in deliv.findall("Destination"): diff --git a/src/sbin/bcfg2-info b/src/sbin/bcfg2-info index a6d236bc8..161fee441 100755 --- a/src/sbin/bcfg2-info +++ b/src/sbin/bcfg2-info @@ -27,6 +27,40 @@ import Bcfg2.Server.Plugins.Metadata import Bcfg2.Server.Plugin logger = logging.getLogger('bcfg2-info') +USAGE = """Commands: +build <hostname> <filename> - Build config for hostname, writing to filename +builddir <hostname> <dirname> - Build config for hostname, writing separate files to dirname +buildall <directory> - Build configs for all clients in directory +buildfile <filename> <hostname> - Build config file for hostname (not written to disk) +bundles - Print out group/bundle information +clients - Print out client/profile information +config - Print out the configuration of the Bcfg2 server +debug - Shell out to native python interpreter +event_debug - Display filesystem events as they are processed +generators - List current versions of generators +groups - List groups +help - Print this list of available commands +mappings <type*> <name*> - Print generator mappings for optional type and name +profile <command> <args> - Profile a single bcfg2-info command +quit - Exit the bcfg2-info command line +showentries <hostname> <type> - Show abstract configuration entries for a given host +showclient <client1> <client2> - Show metadata for given hosts +update - Process pending file events +version - Print version of this tool""" + +BUILDDIR_USAGE = """Usage: builddir [-f] <hostname> <output dir> + +Generates a config for client <hostname> and writes the +individual configuration files out separately in a tree +under <output dir>. The <output dir> directory must be +rooted under /tmp unless the -f argument is provided, in +which case it can be located anywhere. + +NOTE: Currently only handles file entries and writes +all content with the default owner and permissions. These +could be much more permissive than would be created by the +Bcfg2 client itself.""" + class mockLog(object): def error(self, *args, **kwargs): @@ -75,7 +109,8 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): encoding) if event_debug: self.fam.debug = True - except Bcfg2.Server.Core.CoreInitError, msg: + except Bcfg2.Server.Core.CoreInitError: + msg = sys.exc_info()[1] print("Core load failed because %s" % msg) raise SystemExit(1) self.prompt = '> ' @@ -89,7 +124,7 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): try: self.cmdloop('Welcome to bcfg2-info\n' 'Type "help" for more information') - except SystemExit, val: + except SystemExit: raise except Bcfg2.Server.Plugin.PluginExecutionError: continue @@ -106,7 +141,7 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): try: opts, _ = getopt.getopt(args.split(), 'nf:') except: - print "Usage: debug [-n] [-f <command list>]" + print("Usage: debug [-n] [-f <command list>]") return self.cont = False scriptmode = False @@ -136,7 +171,7 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): Exit program. Usage: [quit|exit] """ - for plugin in self.plugins.values(): + for plugin in list(self.plugins.values()): plugin.shutdown() os._exit(0) @@ -145,27 +180,7 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): def do_help(self, _): """Print out usage info.""" - print 'Commands:' - print 'build <hostname> <filename> - Build config for hostname, writing to filename' - print 'builddir <hostname> <dirname> - Build config for hostname, writing separate files to dirname' - print 'buildall <directory> - Build configs for all clients in directory' - print 'buildfile <filename> <hostname> - Build config file for hostname (not written to disk)' - print 'bundles - Print out group/bundle information' - print 'clients - Print out client/profile information' - print 'config - Print out the configuration of the Bcfg2 server' - print 'debug - Shell out to native python interpreter' - print 'event_debug - Display filesystem events as they are processed' - print 'generators - List current versions of generators' - print 'groups - List groups' - print 'help - Print this list of available commands' - print 'mappings <type*> <name*> - Print generator mappings for optional type and name' - print 'profile <command> <args> - Profile a single bcfg2-info command' - print 'quit - Exit the bcfg2-info command line' - print 'showentries <hostname> <type> - Show abstract configuration entries for a given host' - print 'showclient <client1> <client2> - Show metadata for given hosts' - print 'update - Process pending file events' - print 'version - Print version of this tool' - + print(USAGE) def do_update(self, _): """Process pending filesystem events.""" @@ -198,18 +213,7 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): def help_builddir(self): """Display help for builddir command.""" - print('Usage: builddir [-f] <hostname> <output dir>') - print('') - print('Generates a config for client <hostname> and writes the') - print('individual configuration files out separately in a tree') - print('under <output dir>. The <output dir> directory must be') - print('rooted under /tmp unless the -f argument is provided, in') - print('which case it can be located anywhere.') - print('') - print('NOTE: Currently only handles file entries and writes') - print('all content with the default owner and permissions. These') - print('could be much more permissive than would be created by the') - print('Bcfg2 client itself.') + print(BUILDDIR_USAGE) def do_builddir(self, args): """Build client configuration as separate files within a dir.""" @@ -238,7 +242,7 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): p = Bcfg2.Client.Tools.POSIX.POSIX(log, setup, client_config) states = dict() p.Inventory(states) - p.Install(states.keys(), states) + p.Install(list(states.keys()), states) else: print('Error: Incorrect number of parameters.') self.help_builddir() @@ -262,7 +266,7 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): try: metadata = self.build_metadata(client) self.Bind(entry, metadata) - print(lxml.etree.tostring(entry, encoding="UTF-8", + print(lxml.etree.tostring(entry, encoding="UTF-8", xml_declaration=True)) except: print("Failed to build entry %s for host %s" % (fname, client)) @@ -371,22 +375,22 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): except: print("Client %s not defined" % client) continue - print "Hostname:\t", client_meta.hostname - print "Profile:\t", client_meta.profile - print "Groups:\t\t", list(client_meta.groups)[0] + print("Hostname:\t", client_meta.hostname) + print("Profile:\t", client_meta.profile) + print("Groups:\t\t", list(client_meta.groups)[0]) for grp in list(client_meta.groups)[1:]: - print '\t\t%s' % grp + print('\t\t%s' % grp) if client_meta.bundles: - print "Bundles:\t", list(client_meta.bundles)[0] + print("Bundles:\t", list(client_meta.bundles)[0]) for bnd in list(client_meta.bundles)[1:]: - print '\t\t%s' % bnd + print('\t\t%s' % bnd) if client_meta.connectors: - print "Connector data" - print "=" * 80 + print("Connector data") + print("=" * 80) for conn in client_meta.connectors: if getattr(client_meta, conn): - print "%s:\t" % (conn), getattr(client_meta, conn) - print "=" * 80 + print("%s:\t" % (conn), getattr(client_meta, conn)) + print("=" * 80) def do_mappings(self, args): """Print out mapping info.""" @@ -402,11 +406,11 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): interested = [(etype, [args.split()[1]]) for etype in etypes] else: - interested = [(etype, generator.Entries[etype]) - for etype in etypes + interested = [(etype, generator.Entries[etype]) + for etype in etypes if etype in generator.Entries] for etype, names in interested: - for name in [name for name in names if name in + for name in [name for name in names if name in generator.Entries.get(etype, {})]: data.append((generator.name, etype, name)) printTabular(data) diff --git a/src/sbin/bcfg2-lint b/src/sbin/bcfg2-lint new file mode 100755 index 000000000..6bc34433e --- /dev/null +++ b/src/sbin/bcfg2-lint @@ -0,0 +1,194 @@ +#!/usr/bin/env python + +"""This tool examines your Bcfg2 specifications for errors.""" +__revision__ = '$Revision$' + +import sys +import inspect +import logging +import Bcfg2.Logger +import Bcfg2.Options +import Bcfg2.Server.Core +import Bcfg2.Server.Lint +# Compatibility imports +from Bcfg2.Bcfg2Py3k import ConfigParser + +logger = logging.getLogger('bcfg2-lint') + +class Parser(ConfigParser.ConfigParser): + def get(self, section, option, default): + """ Override ConfigParser.get: If the request option is not in + the config file then return the value of default rather than + raise an exception. We still raise exceptions on missing + sections. + """ + try: + return ConfigParser.ConfigParser.get(self, section, option) + except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): + return default + +def run_serverless_plugins(plugins, config=None, setup=None, errorhandler=None): + logger.debug("Running serverless plugins") + for plugin_name, plugin in list(plugins.items()): + run_plugin(plugin, plugin_name, errorhandler=errorhandler, + setup=setup, config=config, files=files) + +def run_server_plugins(plugins, config=None, setup=None, errorhandler=None): + core = load_server(setup) + logger.debug("Running server plugins") + for plugin_name, plugin in list(plugins.items()): + run_plugin(plugin, plugin_name, args=[core], errorhandler=errorhandler, + setup=setup, config=config, files=files) + +def run_plugin(plugin, plugin_name, setup=None, errorhandler=None, + args=None, config=None, files=None): + logger.debug(" Running %s" % plugin_name) + if args is None: + args = [] + + if errorhandler is None: + errorhandler = get_errorhandler(config) + + if config is not None and config.has_section(plugin_name): + args.append(dict(config.items(plugin_name), **setup)) + else: + args.append(setup) + + # older versions of python do not support mixing *-magic and + # non-*-magic (e.g., "plugin(*args, files=files)", so we do this + # all with *-magic + kwargs = dict(files=files, errorhandler=errorhandler) + + return plugin(*args, **kwargs).Run() + +def get_errorhandler(config): + """ get a Bcfg2.Server.Lint.ErrorHandler object """ + if config.has_section("errors"): + conf = dict(config.items("errors")) + else: + conf = None + return Bcfg2.Server.Lint.ErrorHandler(config=conf) + +def load_server(setup): + """ load server """ + core = Bcfg2.Server.Core.Core(setup['repo'], setup['plugins'], + setup['password'], setup['encoding']) + if setup['event debug']: + core.fam.debug = True + core.fam.handle_events_in_interval(4) + return core + +if __name__ == '__main__': + optinfo = { + 'configfile': Bcfg2.Options.CFILE, + 'help': Bcfg2.Options.HELP, + 'verbose': Bcfg2.Options.VERBOSE, + } + optinfo.update({ + 'event debug': Bcfg2.Options.DEBUG, + 'encoding': Bcfg2.Options.ENCODING, + # Server options + 'repo': Bcfg2.Options.SERVER_REPOSITORY, + 'plugins': Bcfg2.Options.SERVER_PLUGINS, + 'mconnect': Bcfg2.Options.SERVER_MCONNECT, + 'filemonitor': Bcfg2.Options.SERVER_FILEMONITOR, + 'location': Bcfg2.Options.SERVER_LOCATION, + 'static': Bcfg2.Options.SERVER_STATIC, + 'key': Bcfg2.Options.SERVER_KEY, + 'cert': Bcfg2.Options.SERVER_CERT, + 'ca': Bcfg2.Options.SERVER_CA, + 'password': Bcfg2.Options.SERVER_PASSWORD, + 'protocol': Bcfg2.Options.SERVER_PROTOCOL, + # More options + 'logging': Bcfg2.Options.LOGGING_FILE_PATH, + 'stdin': Bcfg2.Options.FILES_ON_STDIN, + 'schema': Bcfg2.Options.SCHEMA_PATH, + 'config': Bcfg2.Options.Option('Specify bcfg2-lint configuration file', + '/etc/bcfg2-lint.conf', + cmd='--lint-config', + odesc='<conffile>', + long_arg=True), + 'showerrors': Bcfg2.Options.Option('Show error handling', False, + cmd='--list-errors', + long_arg=True), + }) + setup = Bcfg2.Options.OptionParser(optinfo) + setup.parse(sys.argv[1:]) + + log_args = dict(to_syslog=False, to_console=logging.WARNING) + if setup['verbose']: + log_args['to_console'] = logging.DEBUG + Bcfg2.Logger.setup_logging('bcfg2-info', **log_args) + + config = Parser() + config.read(setup['config']) + + if setup['showerrors']: + if config.has_section("errors"): + econf = dict(config.items("errors")) + else: + econf = dict() + + print("%-35s %-35s" % ("Error name", "Handler (Default)")) + for err, default in Bcfg2.Server.Lint.ErrorHandler._errors.items(): + if err in econf and econf[err] != default: + handler = "%s (%s)" % (econf[err], default) + else: + handler = default + print("%-35s %-35s" % (err, handler)) + raise SystemExit(0) + + # get list of plugins to run + if setup['args']: + allplugins = setup['args'] + elif "bcfg2-repo-validate" in sys.argv[0]: + allplugins = 'Duplicates,RequiredAttrs,Validate'.split(',') + else: + allplugins = config.get('lint', 'plugins', + ",".join(Bcfg2.Server.Lint.__all__)).split(',') + + if setup['stdin']: + files = [s.strip() for s in sys.stdin.readlines()] + else: + files = None + + # load plugins + serverplugins = {} + serverlessplugins = {} + for plugin_name in allplugins: + try: + mod = getattr(__import__("Bcfg2.Server.Lint.%s" % + (plugin_name)).Server.Lint, plugin_name) + except ImportError: + try: + mod = __import__(plugin_name) + except Exception: + err = sys.exc_info()[1] + logger.error("Failed to load plugin %s: %s" % (plugin_name, + err)) + raise SystemExit(1) + plugin = getattr(mod, plugin_name) + if [c for c in inspect.getmro(plugin) + if c == Bcfg2.Server.Lint.ServerPlugin]: + serverplugins[plugin_name] = plugin + else: + serverlessplugins[plugin_name] = plugin + + errorhandler = get_errorhandler(config) + + run_serverless_plugins(serverlessplugins, + errorhandler=errorhandler, + config=config, setup=setup) + + if serverplugins: + run_server_plugins(serverplugins, errorhandler=errorhandler, + config=config, setup=setup) + + if errorhandler.errors or errorhandler.warnings or setup['verbose']: + print("%d errors" % errorhandler.errors) + print("%d warnings" % errorhandler.warnings) + + if errorhandler.errors: + raise SystemExit(2) + elif errorhandler.warnings: + raise SystemExit(3) diff --git a/src/sbin/bcfg2-ping-sweep b/src/sbin/bcfg2-ping-sweep index 4082cad8b..70f718690 100755 --- a/src/sbin/bcfg2-ping-sweep +++ b/src/sbin/bcfg2-ping-sweep @@ -8,7 +8,7 @@ __revision__ = '$Revision$' from os import dup2, execl, fork, uname, wait import sys import time -import lxml.etree +import lxml.etree import Bcfg2.Options @@ -20,9 +20,10 @@ if __name__ == '__main__': cfpath = setup['configfile'] clientdatapath = "%s/Metadata/clients.xml" % setup['repo'] - + clientElement = lxml.etree.parse(clientdatapath) - hostlist = [client.get('name') for client in clientElement.findall("Client")] + hostlist = [client.get('name') + for client in clientElement.findall("Client")] pids = {} null = open('/dev/null', 'w+') @@ -31,9 +32,8 @@ if __name__ == '__main__': #/bin/ping on linux /sbin/ping on os x osname = uname()[0] - while hostlist or pids: - if hostlist and len(pids.keys()) < 15: + if hostlist and len(list(pids.keys())) < 15: host = hostlist.pop() pid = fork() if pid == 0: @@ -47,7 +47,7 @@ if __name__ == '__main__': execl('/sbin/ping', 'ping', '-t', '5', '-c', '1', host) elif osname == 'SunOS': execl('/usr/sbin/ping', 'ping', host, '56', '1') - else: #default + else: # default execl('/bin/ping', 'ping', '-w', '5', '-c', '1', host) else: pids[pid] = host @@ -58,14 +58,15 @@ if __name__ == '__main__': continue chost = pids[cpid] del pids[cpid] - elm = clientElement.xpath("//Client[@name='%s']"%chost)[0] + elm = clientElement.xpath("//Client[@name='%s']" % chost)[0] if status == 0: - elm.set("pingable",'Y') + elm.set("pingable", 'Y') elm.set("pingtime", str(time.time())) else: - elm.set("pingable",'N') + elm.set("pingable", 'N') fout = open(clientdatapath, 'w') - fout.write(lxml.etree.tostring(clientElement.getroot(), encoding='UTF-8', xml_declaration=True)) + fout.write(lxml.etree.tostring(clientElement.getroot(), + encoding='UTF-8', + xml_declaration=True)) fout.close() - diff --git a/src/sbin/bcfg2-repo-validate b/src/sbin/bcfg2-repo-validate index 554e4f72b..cea09cda3 100755..120000 --- a/src/sbin/bcfg2-repo-validate +++ b/src/sbin/bcfg2-repo-validate @@ -1,227 +1 @@ -#!/usr/bin/env python - -""" -bcfg2-repo-validate checks all xml files in Bcfg2 -repos against their respective XML schemas. -""" -__revision__ = '$Revision$' - -import glob -import lxml.etree -import os -import sys -import Bcfg2.Options - -if __name__ == '__main__': - opts = {'repo': Bcfg2.Options.SERVER_REPOSITORY, - 'prefix': Bcfg2.Options.INSTALL_PREFIX, - 'verbose': Bcfg2.Options.VERBOSE, - 'configfile': Bcfg2.Options.CFILE} - setup = Bcfg2.Options.OptionParser(opts) - setup.parse(sys.argv[1:]) - verbose = setup['verbose'] - cpath = setup['configfile'] - prefix = setup['prefix'] - schemadir = "%s/share/bcfg2/schemas" % (prefix) - os.chdir(schemadir) - repo = setup['repo'] - - # Get a list of all info.xml files in the bcfg2 repository - info_list = [] - for infodir in ['Cfg', 'TGenshi', 'TCheetah']: - for root, dirs, files in os.walk('%s/%s' % (repo, infodir)): - for filename in files: - if filename == 'info.xml': - info_list.append(os.path.join(root, filename)) - - # get metadata list (with all included files) - metadata_list = glob.glob("%s/Metadata/groups.xml" % repo) - ref_bundles = set() - xdata = lxml.etree.parse("%s/Metadata/groups.xml" % repo) - included = set([ent.get('href') for ent in \ - xdata.findall('./{http://www.w3.org/2001/XInclude}include')]) - while included: - try: - filename = included.pop() - except KeyError: - continue - metadata_list.append("%s/Metadata/%s" % (repo, filename)) - groupdata = lxml.etree.parse("%s/Metadata/%s" % (repo, filename)) - group_ents = [ent.get('href') for ent in \ - groupdata. - findall('./{http://www.w3.org/2001/XInclude}include')] - for ent in group_ents: - included.add(ent) - included.discard(filename) - - # check for multiple default group definitions - default_groups = [] - for grp in lxml.etree.parse("%s/Metadata/groups.xml" \ - % repo).findall('.//Group'): - if grp.get('default') == 'true': - default_groups.append(grp) - if len(default_groups) > 1: - print("*** Warning: Multiple default groups defined") - for grp in default_groups: - print(" %s" % grp.get('name')) - - # get all XIncluded bundles - xdata.xinclude() - for bundle in xdata.findall("//Bundle"): - ref_bundles.add("%s/Bundler/%s" % (repo, bundle.get('name'))) - - # get lists of all other xml files to validate - clients_list = glob.glob("%s/Metadata/clients.xml" % repo) - bundle_list = glob.glob("%s/Bundler/*.xml" % repo) - genshibundle_list = glob.glob("%s/Bundler/*.genshi" % repo) - pkg_list = glob.glob("%s/Pkgmgr/*.xml" % repo) - base_list = glob.glob("%s/Base/*.xml" % repo) - rules_list = glob.glob("%s/Rules/*.xml" % repo) - imageinfo_list = glob.glob("%s/etc/report-configuration.xml" % repo) - services_list = glob.glob("%s/Svcmgr/*.xml" % repo) - deps_list = glob.glob("%s/Deps/*.xml" % repo) - dec_list = glob.glob("%s/Decisions/*" % repo) - pkgcfg_list = glob.glob("%s/Packages/config.xml" % repo) - gp_list = glob.glob('%s/GroupPatterns/config.xml' % repo) - - # verify attributes for configuration entries - # (as defined in doc/server/configurationentries) - # TODO: See if it is possible to do this in the schema instead - required_configuration_attrs = { - 'device': ['name', 'owner', 'group', 'dev_type'], - 'directory': ['name', 'owner', 'group', 'perms'], - 'file': ['name', 'owner', 'group', 'perms'], - 'hardlink': ['name', 'to'], - 'symlink': ['name', 'to'], - 'ignore': ['name'], - 'nonexistent': ['name'], - 'permissions': ['name', 'owner', 'group', 'perms']} - for rfile in rules_list: - try: - xdata = lxml.etree.parse(rfile) - except lxml.etree.XMLSyntaxError, e: - print("Failed to parse %s: %s" % (rfile, e)) - for posixpath in xdata.findall("//Path"): - pathname = posixpath.get('name') - pathtype = posixpath.get('type') - pathset = set(posixpath.attrib.keys()) - try: - required_attrs = set(required_configuration_attrs[pathtype] \ - + ['type']) - except KeyError: - continue - if 'dev_type' in required_attrs: - dev_type = posixpath.get('dev_type') - if dev_type in ['block', 'char']: - # check if major/minor are specified - required_attrs |= set(['major', 'minor']) - if pathset.issuperset(required_attrs): - continue - else: - print("The following required attributes are missing for" - " Path %s in %s: %s" % (pathname, rfile, - [attr for attr in required_attrs.difference(pathset)])) - - # warn on duplicate Pkgmgr entries with the same priority - pset = set() - for plist in pkg_list: - try: - xdata = lxml.etree.parse(plist) - except lxml.etree.XMLSyntaxError, e: - print("Failed to parse %s: %s" % (plist, e)) - # get priority, type, group - priority = xdata.getroot().get('priority') - ptype = xdata.getroot().get('type') - for pkg in xdata.findall("//Package"): - if pkg.getparent().tag == 'Group': - grp = pkg.getparent().get('name') - if type(grp) is not str and grp.getparent().tag == 'Group': - pgrp = grp.getparent().get('name') - else: - pgrp = 'none' - else: - grp = 'none' - pgrp = 'none' - ptuple = (pkg.get('name'), priority, ptype, grp, pgrp) - # check if package is already listed with same priority, - # type, grp - if ptuple in pset: - print("Duplicate Package %s, priority:%s, type:%s"\ - % (pkg.get('name'), priority, ptype)) - else: - pset.add(ptuple) - - filesets = {'metadata': (metadata_list, "%s/metadata.xsd"), - 'clients': (clients_list, "%s/clients.xsd"), - 'info': (info_list, "%s/info.xsd"), - 'bundle': (bundle_list, "%s/bundle.xsd"), - 'pkglist': (pkg_list, "%s/pkglist.xsd"), - 'base': (base_list, "%s/base.xsd"), - 'rules': (rules_list, "%s/rules.xsd"), - 'imageinfo': (imageinfo_list, "%s/report-configuration.xsd"), - 'services': (services_list, "%s/services.xsd"), - 'deps': (deps_list, "%s/deps.xsd"), - 'decisions': (dec_list, "%s/decisions.xsd"), - 'packages': (pkgcfg_list, "%s/packages.xsd"), - 'grouppatterns': (gp_list, "%s/grouppatterns.xsd"), - } - - failures = 0 - for k, (filelist, schemaname) in list(filesets.items()): - try: - schema = lxml.etree.XMLSchema(lxml.etree.parse(open(schemaname%(schemadir)))) - except: - print("Failed to process schema %s" % (schemaname%(schemadir))) - failures = 1 - continue - for filename in filelist: - try: - datafile = lxml.etree.parse(open(filename)) - except SyntaxError: - print("%s ***FAILS*** to parse \t\t<----" % (filename)) - os.system("xmllint %s" % filename) - failures = 1 - continue - except IOError: - print("Failed to open file %s \t\t<---" % (filename)) - failures = 1 - continue - if schema.validate(datafile): - if verbose: - print("%s checks out" % (filename)) - else: - rc = os.system("xmllint --noout --xinclude --schema \ - %s %s > /dev/null 2>/dev/null" % \ - (schemaname % schemadir, filename)) - if rc: - failures = 1 - print("%s ***FAILS*** to verify \t\t<----" % (filename)) - os.system("xmllint --noout --xinclude --schema %s %s" % \ - (schemaname % schemadir, filename)) - elif verbose: - print("%s checks out" % (filename)) - - # print out missing bundle information - if verbose: - print("") - for bundle in ref_bundles: - # check for both regular and genshi bundles - xmlbundle = "%s.xml" % bundle - genshibundle = "%s.genshi" % bundle - allbundles = bundle_list + genshibundle_list - if xmlbundle not in allbundles and \ - genshibundle not in allbundles: - print("*** Warning: Bundle %s referenced, but does not " - "exist." % bundle) - # verify bundle name attribute matches filename - for bundle in (bundle_list + genshibundle_list): - fname = bundle.split('Bundler/')[1].split('.')[0] - xdata = lxml.etree.parse(bundle) - bname = xdata.getroot().get('name') - if fname != bname: - print("The following names are inconsistent:") - print(" Filename is %s" % fname) - print(" Bundle name found in %s is %s" % (fname, bname)) - - - raise SystemExit, failures +bcfg2-lint
\ No newline at end of file diff --git a/src/sbin/bcfg2-reports b/src/sbin/bcfg2-reports index d83e45e7c..20288fc5e 100755 --- a/src/sbin/bcfg2-reports +++ b/src/sbin/bcfg2-reports @@ -5,7 +5,13 @@ __revision__ = '$Revision$' import os import sys -import Bcfg2.Server.Reports.settings +try: + import Bcfg2.Server.Reports.settings +except ConfigParser.NoSectionError: + print("Your bcfg2.conf is currently missing the statistics section which " + "is necessary for the reporting interface. Please see bcfg2.conf(5) " + "for more details.") + sys.exit(1) project_directory = os.path.dirname(Bcfg2.Server.Reports.settings.__file__) project_name = os.path.basename(project_directory) @@ -87,13 +93,13 @@ def print_fields(fields, cli, max_name, entrydict): if len(entrydict) > 0: display += " " display += str(entrydict[cli]) - print display + print(display) def print_entry(item, max_name): fmt = ("%%-%ds " % (max_name)) fdata = item.entry.kind + ":" + item.entry.name display = fmt % (fdata) - print display + print(display) fields = "" sort = "" @@ -131,14 +137,14 @@ if expire != "": if expire == c_inst.name: if c_inst.expiration == None: c_inst.expiration = datetime.datetime.now() - print "Host expired." + print("Host expired.") else: c_inst.expiration = None - print "Host un-expired." + print("Host un-expired.") c_inst.save() elif '-h' in args: - print """Usage: bcfg2-reports [option] ... + print("""Usage: bcfg2-reports [option] ... Options and arguments (and corresponding environment variables): -a : shows all hosts, including expired hosts @@ -164,13 +170,13 @@ Options and arguments (and corresponding environment variables): (name,time,state) --sort=ARG1,ARG2,... : sorts output on ARG1,ARG2,... (name,time,state) --stale : shows hosts which haven't run in the last 24 hours -""" +""") elif singlehost != "": for c_inst in c_list: if singlehost == c_inst.name: baditems = c_inst.current_interaction.bad() if len(baditems) > 0 and ('-b' in args or '-s' in args): - print "Bad Entries:" + print("Bad Entries:") max_name = -1 for item in baditems: if len(item.entry.name) > max_name: @@ -179,7 +185,7 @@ elif singlehost != "": print_entry(item, max_name) extraitems = c_inst.current_interaction.extra() if len(extraitems) > 0 and ('-e' in args or '-s' in args): - print "Extra Entries:" + print("Extra Entries:") max_name = -1 for item in extraitems: if len(item.entry.name) > max_name: diff --git a/src/sbin/bcfg2-server b/src/sbin/bcfg2-server index cf44f1699..f4bd5e5b7 100755 --- a/src/sbin/bcfg2-server +++ b/src/sbin/bcfg2-server @@ -69,7 +69,8 @@ if __name__ == '__main__': certfile=setup['cert'], ca=setup['ca'], ) - except CoreInitError, msg: + except CoreInitError: + msg = sys.exc_info()[1] logger.error(msg) logger.error("exiting") sys.exit(1) |