summaryrefslogtreecommitdiffstats
path: root/src/sbin/bcfg2-lint
diff options
context:
space:
mode:
Diffstat (limited to 'src/sbin/bcfg2-lint')
-rwxr-xr-xsrc/sbin/bcfg2-lint194
1 files changed, 194 insertions, 0 deletions
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)