diff options
Diffstat (limited to 'src/lib/Bcfg2/Server/Plugins/TemplateHelper.py')
-rw-r--r-- | src/lib/Bcfg2/Server/Plugins/TemplateHelper.py | 153 |
1 files changed, 58 insertions, 95 deletions
diff --git a/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py b/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py index db7370f01..047fc062e 100644 --- a/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py +++ b/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py @@ -3,11 +3,10 @@ import re import imp import sys -import logging -import Bcfg2.Server.Lint -import Bcfg2.Server.Plugin - -LOGGER = logging.getLogger(__name__) +import lxml.etree +from Bcfg2.Server.Plugin import Plugin, Connector, DirectoryBacked, \ + TemplateDataProvider, DefaultTemplateDataProvider +from Bcfg2.Logger import Debuggable MODULE_RE = re.compile(r'(?P<filename>(?P<module>[^\/]+)\.py)$') @@ -20,12 +19,12 @@ def safe_module_name(module): return '__TemplateHelper_%s' % module -class HelperModule(object): +class HelperModule(Debuggable): """ Representation of a TemplateHelper module """ - def __init__(self, name, fam=None): + def __init__(self, name): + Debuggable.__init__(self) self.name = name - self.fam = fam #: The name of the module as used by get_additional_data(). #: the name of the file with .py stripped off. @@ -34,6 +33,14 @@ class HelperModule(object): #: The attributes exported by this module self._attrs = [] + #: The attributes added to the template namespace by this module + self.defaults = [] + + default_prov = DefaultTemplateDataProvider() + self.reserved_defaults = default_prov.get_template_data( + lxml.etree.Element("Path", name="/dummy"), + None, None).keys() + ["path"] + def HandleEvent(self, event=None): """ HandleEvent is called whenever the FAM registers an event. @@ -49,120 +56,76 @@ class HelperModule(object): self.name) except: # pylint: disable=W0702 err = sys.exc_info()[1] - LOGGER.error("TemplateHelper: Failed to import %s: %s" % - (self.name, err)) + self.logger.error("TemplateHelper: Failed to import %s: %s" % + (self.name, err)) return if not hasattr(module, "__export__"): - LOGGER.error("TemplateHelper: %s has no __export__ list" % - self.name) + self.logger.error("TemplateHelper: %s has no __export__ list" % + self.name) return newattrs = [] - for sym in module.__export__: + for sym in module.__export__ + getattr(module, "__default__", []): + if sym in newattrs: + # already added to attribute list + continue if sym not in self._attrs and hasattr(self, sym): - LOGGER.warning("TemplateHelper: %s: %s is a reserved keyword, " - "skipping export" % (self.name, sym)) + self.logger.warning( + "TemplateHelper: %s: %s is a reserved keyword, " + "skipping export" % (self.name, sym)) continue try: setattr(self, sym, getattr(module, sym)) newattrs.append(sym) except AttributeError: - LOGGER.warning("TemplateHelper: %s exports %s, but has no " - "such attribute" % (self.name, sym)) + self.logger.warning( + "TemplateHelper: %s exports %s, but has no such attribute" + % (self.name, sym)) + # remove old exports for sym in set(self._attrs) - set(newattrs): delattr(self, sym) self._attrs = newattrs + self.defaults = [] + for sym in getattr(module, "__default__", []): + if sym in self.reserved_defaults: + self.logger.warning( + "TemplateHelper: %s: %s is a reserved keyword, not adding " + "as default" % (self.name, sym)) + self.defaults.append(sym) + -class TemplateHelper(Bcfg2.Server.Plugin.Plugin, - Bcfg2.Server.Plugin.Connector, - Bcfg2.Server.Plugin.DirectoryBacked): +class TemplateHelper(Plugin, Connector, DirectoryBacked, TemplateDataProvider): """ A plugin to provide helper classes and functions to templates """ __author__ = 'chris.a.st.pierre@gmail.com' ignore = re.compile(r'^(\.#.*|.*~|\..*\.(sw[px])|.*\.py[co])$') patterns = MODULE_RE __child__ = HelperModule - def __init__(self, core, datastore): - Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore) - Bcfg2.Server.Plugin.Connector.__init__(self) - Bcfg2.Server.Plugin.DirectoryBacked.__init__(self, self.data, core.fam) + def __init__(self, core): + Plugin.__init__(self, core) + Connector.__init__(self) + DirectoryBacked.__init__(self, self.data) + TemplateDataProvider.__init__(self) def get_additional_data(self, _): return dict([(h._module_name, h) # pylint: disable=W0212 for h in self.entries.values()]) - -class TemplateHelperLint(Bcfg2.Server.Lint.ServerPlugin): - """ ``bcfg2-lint`` plugin to ensure that all :ref:`TemplateHelper - <server-plugins-connectors-templatehelper>` modules are valid. - This can check for: - - * A TemplateHelper module that cannot be imported due to syntax or - other compile-time errors; - * A TemplateHelper module that does not have an ``__export__`` - attribute, or whose ``__export__`` is not a list; - * Bogus symbols listed in ``__export__``, including symbols that - don't exist, that are reserved, or that start with underscores. - """ - - def __init__(self, *args, **kwargs): - Bcfg2.Server.Lint.ServerPlugin.__init__(self, *args, **kwargs) - self.reserved_keywords = dir(HelperModule("foo.py")) - - def Run(self): - for helper in self.core.plugins['TemplateHelper'].entries.values(): - if self.HandlesFile(helper.name): - self.check_helper(helper.name) - - def check_helper(self, helper): - """ Check a single helper module. - - :param helper: The filename of the helper module - :type helper: string - """ - module_name = MODULE_RE.search(helper).group(1) - - try: - module = imp.load_source(safe_module_name(module_name), helper) - except: # pylint: disable=W0702 - err = sys.exc_info()[1] - self.LintError("templatehelper-import-error", - "Failed to import %s: %s" % - (helper, err)) - return - - if not hasattr(module, "__export__"): - self.LintError("templatehelper-no-export", - "%s has no __export__ list" % helper) - return - elif not isinstance(module.__export__, list): - self.LintError("templatehelper-nonlist-export", - "__export__ is not a list in %s" % helper) - return - - for sym in module.__export__: - if not hasattr(module, sym): - self.LintError("templatehelper-nonexistent-export", - "%s: exported symbol %s does not exist" % - (helper, sym)) - elif sym in self.reserved_keywords: - self.LintError("templatehelper-reserved-export", - "%s: exported symbol %s is reserved" % - (helper, sym)) - elif sym.startswith("_"): - self.LintError("templatehelper-underscore-export", - "%s: exported symbol %s starts with underscore" - % (helper, sym)) - - @classmethod - def Errors(cls): - return {"templatehelper-import-error": "error", - "templatehelper-no-export": "error", - "templatehelper-nonlist-export": "error", - "templatehelper-nonexistent-export": "error", - "templatehelper-reserved-export": "error", - "templatehelper-underscore-export": "warning"} + def get_template_data(self, *_): + rv = dict() + source = dict() + for helper in self.entries.values(): + for key in helper.defaults: + if key not in rv: + rv[key] = getattr(helper, key) + source[key] = helper + else: + self.logger.warning( + "TemplateHelper: Duplicate default variable %s " + "provided by both %s and %s" % + (key, helper.name, source[key].name)) + return rv |