#!/usr/bin/env python """This tool examines your Bcfg2 specifications for errors.""" 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') 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): arg = setup for key, val in config.items(plugin_name): arg[key] = val args.append(arg) 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'], filemonitor=setup['filemonitor'], setup=setup) core.fam.handle_events_in_interval(4) return core if __name__ == '__main__': optinto = dict(config=Bcfg2.Options.LINT_CONFIG, showerrors=Bcfg2.Options.LINT_SHOW_ERRORS, stdin=Bcfg2.Options.LINT_FILES_ON_STDIN, schema=Bcfg2.Options.SCHEMA_PATH) optinfo.update(CLI_COMMON_OPTIONS) optinfo.update(SERVER_COMMON_OPTIONS) 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 = ConfigParser.SafeConfigParser() config.read(setup['configfile']) config.read(setup['config']) # 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: try: allplugins = config.get('lint', 'plugins').split(',') except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): allplugins = Bcfg2.Server.Lint.__all__ 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) if setup['showerrors']: for plugin in serverplugins.values() + serverlessplugins.values(): errorhandler.RegisterErrors(getattr(plugin, 'Errors')()) print("%-35s %-35s" % ("Error name", "Handler")) for err, handler in errorhandler._handlers.items(): print("%-35s %-35s" % (err, handler.__name__)) raise SystemExit(0) run_serverless_plugins(serverlessplugins, errorhandler=errorhandler, config=config, setup=setup) if serverplugins: if errorhandler.errors: # it would be swell if we could try to start the server # even if there were errors with the serverless plugins, # but since XML parsing errors occur in the FAM thread # (not in the core server thread), there's no way we can # start the server and try to catch exceptions -- # bcfg2-lint isn't in the same stack as the exceptions. # so we're forced to assume that a serverless plugin error # will prevent the server from starting print("Serverless plugins encountered errors, skipping server " "plugins") else: 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)