From 4b0e3c79152f53656f5ea2b7a00d921a0e7e6596 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Fri, 22 Feb 2013 04:10:44 +0100 Subject: Server/Plugins/TemplateHelper: backported TemplateHelper from 1.3 --- debian/changelog | 6 ++ src/lib/Server/Plugins/TemplateHelper.py | 154 +++++++++++++++++++++++++++++++ src/lib/Server/Plugins/__init__.py | 1 + 3 files changed, 161 insertions(+) create mode 100644 src/lib/Server/Plugins/TemplateHelper.py diff --git a/debian/changelog b/debian/changelog index d06347378..1d0ca0f58 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +bcfg2 (1.2.3-5) unstable; urgency=low + + * Server/Plugins/TemplateHelper: backported TemplateHelper from 1.3 + + -- Alexander Sulfrian Fri, 22 Feb 2013 04:07:35 +0100 + bcfg2 (1.2.3-4) unstable; urgency=low * Client: always actions do not modify hosts diff --git a/src/lib/Server/Plugins/TemplateHelper.py b/src/lib/Server/Plugins/TemplateHelper.py new file mode 100644 index 000000000..3cdedb0ea --- /dev/null +++ b/src/lib/Server/Plugins/TemplateHelper.py @@ -0,0 +1,154 @@ +""" A plugin to provide helper classes and functions to templates """ + +import re +import imp +import sys +import logging +import Bcfg2.Server.Lint +import Bcfg2.Server.Plugin + +LOGGER = logging.getLogger(__name__) + +MODULE_RE = re.compile(r'(?P(?P[^\/]+)\.py)$') + + +def safe_module_name(module): + """ Munge the name of a TemplateHelper module to avoid collisions + with other Python modules. E.g., if someone has a helper named + 'ldap.py', it should not be added to ``sys.modules`` as ``ldap``, + but rather as something more obscure. """ + return '__TemplateHelper_%s' % module + + +class HelperModule(object): + """ Representation of a TemplateHelper module """ + + def __init__(self, name, fam=None): + 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. + self._module_name = MODULE_RE.search(self.name).group('module') + + #: The attributes exported by this module + self._attrs = [] + + def HandleEvent(self, event=None): + """ HandleEvent is called whenever the FAM registers an event. + + :param event: The event object + :type event: Bcfg2.Server.FileMonitor.Event + :returns: None + """ + if event and event.code2str() not in ['exists', 'changed', 'created']: + return + + try: + module = imp.load_source(safe_module_name(self._module_name), + self.name) + except: # pylint: disable=W0702 + err = sys.exc_info()[1] + 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) + return + + newattrs = [] + for sym in module.__export__: + if sym not in self._attrs and hasattr(self, sym): + 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)) + # remove old exports + for sym in set(self._attrs) - set(newattrs): + delattr(self, sym) + + self._attrs = newattrs + + +class TemplateHelper(Bcfg2.Server.Plugin.Plugin, + Bcfg2.Server.Plugin.Connector, + Bcfg2.Server.Plugin.DirectoryBacked): + """ A plugin to provide helper classes and functions to templates """ + name = 'TemplateHelper' + __author__ = 'chris.a.st.pierre@gmail.com' + ignore = re.compile("^(\.#.*|.*~|\\..*\\.(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 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): + """ find duplicate Pkgmgr entries with the same priority """ + 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): + self.check_helper(helper.name) + + def check_helper(self, helper): + """ check a helper module for export errors """ + 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"} diff --git a/src/lib/Server/Plugins/__init__.py b/src/lib/Server/Plugins/__init__.py index c69c37452..b39793290 100644 --- a/src/lib/Server/Plugins/__init__.py +++ b/src/lib/Server/Plugins/__init__.py @@ -29,6 +29,7 @@ __all__ = [ 'Svcmgr', 'Svn', 'TCheetah', + 'TemplateHelper', 'Trigger', 'SGenshi', 'TGenshi', -- cgit v1.2.3-1-g7c22