From 1f6cb52d0c43f842766f3ecd6c8286f0f4eed5c2 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Mon, 4 Feb 2013 16:20:46 -0500 Subject: Bundler: various changes * Deprecated use of an explicit name attribute * Deprecated .genshi bundles * Minor restructuring for better performance * bcfg2-lint updates --- src/lib/Bcfg2/Server/Plugin/helpers.py | 20 ++++--- src/lib/Bcfg2/Server/Plugins/Bundler.py | 101 ++++++++++++++++++++------------ 2 files changed, 73 insertions(+), 48 deletions(-) (limited to 'src/lib') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index 9d76337e0..871b5eb4e 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -570,7 +570,7 @@ class XMLFileBacked(FileBacked): return "%s at %s" % (self.__class__.__name__, self.name) -class StructFile(XMLFileBacked): +class StructFile(XMLFileBacked, Debuggable): """ StructFiles are XML files that contain a set of structure file formatting logic for handling ```` and ```` tags. @@ -589,6 +589,7 @@ class StructFile(XMLFileBacked): def __init__(self, filename, should_monitor=False): XMLFileBacked.__init__(self, filename, should_monitor=should_monitor) + Debuggable.__init__(self) self.setup = Bcfg2.Options.get_option_parser() self.encoding = self.setup['encoding'] self.template = None @@ -605,15 +606,16 @@ class StructFile(XMLFileBacked): encoding=self.encoding) except LookupError: err = sys.exc_info()[1] - LOGGER.error('Genshi lookup error in %s: %s' % (self.name, - err)) + self.logger.error('Genshi lookup error in %s: %s' % (self.name, + err)) except genshi.template.TemplateError: err = sys.exc_info()[1] - LOGGER.error('Genshi template error in %s: %s' % (self.name, - err)) + self.logger.error('Genshi template error in %s: %s' % + (self.name, err)) except genshi.input.ParseError: err = sys.exc_info()[1] - LOGGER.error('Genshi parse error in %s: %s' % (self.name, err)) + self.logger.error('Genshi parse error in %s: %s' % (self.name, + err)) if self.encryption and HAS_CRYPTO: strict = self.xdata.get( @@ -625,15 +627,15 @@ class StructFile(XMLFileBacked): el.text = self._decrypt(el).encode('ascii', 'xmlcharrefreplace') except UnicodeDecodeError: - LOGGER.info("%s: Decrypted %s to gibberish, skipping" % - (self.name, el.tag)) + self.logger.info("%s: Decrypted %s to gibberish, skipping" + % (self.name, el.tag)) except Bcfg2.Encryption.EVPError: msg = "Failed to decrypt %s element in %s" % (el.tag, self.name) if strict: raise PluginExecutionError(msg) else: - LOGGER.warning(msg) + self.logger.warning(msg) Index.__doc__ = XMLFileBacked.Index.__doc__ def _decrypt(self, element): diff --git a/src/lib/Bcfg2/Server/Plugins/Bundler.py b/src/lib/Bcfg2/Server/Plugins/Bundler.py index 051443e22..5eeb542ee 100644 --- a/src/lib/Bcfg2/Server/Plugins/Bundler.py +++ b/src/lib/Bcfg2/Server/Plugins/Bundler.py @@ -3,8 +3,6 @@ import os import re import sys -import copy -import lxml.etree import Bcfg2.Server import Bcfg2.Server.Plugin import Bcfg2.Server.Lint @@ -13,12 +11,29 @@ from genshi.template import TemplateError class BundleFile(Bcfg2.Server.Plugin.StructFile): """ Representation of a bundle XML file """ - def get_xml_value(self, metadata): - """ get the XML data that applies to the given client """ - bundle = lxml.etree.Element('Bundle', name=self.xdata.get("name")) - for item in self.Match(metadata): - bundle.append(copy.copy(item)) - return bundle + bundle_name_re = re.compile('^(?P.*)\.(xml|genshi)$') + + def __init__(self, filename, should_monitor=False): + Bcfg2.Server.Plugin.StructFile.__init__(self, filename, + should_monitor=should_monitor) + if self.name.endswith(".genshi"): + self.logger.warning("Bundler: Bundle filenames ending with " + ".genshi are deprecated; add the Genshi XML " + "namespace to a .xml bundle instead") + __init__.__doc__ = Bcfg2.Server.Plugin.StructFile.__init__.__doc__ + + def Index(self): + Bcfg2.Server.Plugin.StructFile.Index(self) + if self.xdata.get("name"): + self.logger.warning("Bundler: Explicitly specifying bundle names " + "is deprecated") + Index.__doc__ = Bcfg2.Server.Plugin.StructFile.Index.__doc__ + + @property + def bundle_name(self): + """ The name of the bundle, as determined from the filename """ + return self.bundle_name_re.match( + os.path.basename(self.name)).group("name") class Bundler(Bcfg2.Server.Plugin.Plugin, @@ -28,38 +43,35 @@ class Bundler(Bcfg2.Server.Plugin.Plugin, bundle/translation scheme from Bcfg1. """ __author__ = 'bcfg-dev@mcs.anl.gov' __child__ = BundleFile - patterns = re.compile('^(?P.*)\.(xml|genshi)$') def __init__(self, core, datastore): Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore) Bcfg2.Server.Plugin.Structure.__init__(self) - try: - Bcfg2.Server.Plugin.XMLDirectoryBacked.__init__(self, self.data) - except OSError: - err = sys.exc_info()[1] - msg = "Failed to load Bundle repository %s: %s" % (self.data, err) - self.logger.error(msg) - raise Bcfg2.Server.Plugin.PluginInitError(msg) + Bcfg2.Server.Plugin.XMLDirectoryBacked.__init__(self, self.data) + #: Bundles by bundle name, rather than filename + self.bundles = dict() + __init__.__doc__ = Bcfg2.Server.Plugin.Plugin.__init__.__doc__ - def BuildStructures(self, metadata): - """Build all structures for client (metadata).""" - bundleset = [] + def HandleEvent(self, event): + Bcfg2.Server.Plugin.XMLDirectoryBacked.HandleEvent(self, event) - bundle_entries = {} - for key, item in self.entries.items(): - bundle_entries.setdefault( - self.patterns.match(os.path.basename(key)).group('name'), - []).append(item) + self.bundles = dict() + for bundle in self.entries.values(): + self.bundles[bundle.bundle_name] = bundle + HandleEvent.__doc__ = \ + Bcfg2.Server.Plugin.XMLDirectoryBacked.HandleEvent.__doc__ + def BuildStructures(self, metadata): + bundleset = [] for bundlename in metadata.bundles: try: - entries = bundle_entries[bundlename] + bundle = self.bundles[bundlename] except KeyError: self.logger.error("Bundler: Bundle %s does not exist" % bundlename) continue try: - bundleset.append(entries[0].get_xml_value(metadata)) + bundleset.append(bundle.XMLMatch(metadata)) except TemplateError: err = sys.exc_info()[1] self.logger.error("Bundler: Failed to render templated bundle " @@ -68,6 +80,8 @@ class Bundler(Bcfg2.Server.Plugin.Plugin, self.logger.error("Bundler: Unexpected bundler error for %s" % bundlename, exc_info=1) return bundleset + BuildStructures.__doc__ = \ + Bcfg2.Server.Plugin.Structure.BuildStructures.__doc__ class BundlerLint(Bcfg2.Server.Lint.ServerPlugin): @@ -83,7 +97,9 @@ class BundlerLint(Bcfg2.Server.Lint.ServerPlugin): @classmethod def Errors(cls): return {"bundle-not-found": "error", - "inconsistent-bundle-name": "warning"} + "unused-bundle": "warning", + "explicit-bundle-name": "error", + "genshi-extension-bundle": "error"} def missing_bundles(self): """ find bundles listed in Metadata but not implemented in Bundler """ @@ -94,21 +110,28 @@ class BundlerLint(Bcfg2.Server.Lint.ServerPlugin): ref_bundles = set([b.get("name") for b in groupdata.findall("//Bundle")]) - allbundles = self.core.plugins['Bundler'].entries.keys() + allbundles = self.core.plugins['Bundler'].bundles.keys() for bundle in ref_bundles: - xmlbundle = "%s.xml" % bundle - genshibundle = "%s.genshi" % bundle - if (xmlbundle not in allbundles and - genshibundle not in allbundles): + if bundle not in allbundles: self.LintError("bundle-not-found", "Bundle %s referenced, but does not exist" % bundle) + for bundle in allbundles: + if bundle not in ref_bundles: + self.LintError("unused-bundle", + "Bundle %s defined, but is not referenced " + "in Metadata" % bundle) + def bundle_names(self, bundle): - """ verify bundle name attribute matches filename """ - fname = os.path.splitext(os.path.basename(bundle.name))[0] - bname = bundle.xdata.get('name') - if fname != bname: - self.LintError("inconsistent-bundle-name", - "Inconsistent bundle name: filename is %s, " - "bundle name is %s" % (fname, bname)) + """ Verify that deprecated bundle .genshi bundles and explicit + bundle names aren't used """ + if bundle.xdata.get('name'): + self.LintError("explicit-bundle-name", + "Deprecated explicit bundle name in %s" % + bundle.name) + + if bundle.name.endswith(".genshi"): + self.LintError("genshi-extension-bundle", + "Bundle %s uses deprecated .genshi extension" % + bundle.name) -- cgit v1.2.3-1-g7c22