diff options
Diffstat (limited to 'src/lib/Bcfg2/Server')
-rw-r--r-- | src/lib/Bcfg2/Server/Core.py | 40 | ||||
-rwxr-xr-x | src/lib/Bcfg2/Server/Encryption.py | 6 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Lint/Comments.py | 2 | ||||
-rwxr-xr-x | src/lib/Bcfg2/Server/Lint/Genshi.py | 48 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Plugins/Cfg/CfgExternalCommandVerifier.py | 9 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py | 1 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py | 9 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Plugins/Defaults.py | 29 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Plugins/Git.py | 48 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Plugins/Metadata.py | 2 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Plugins/Packages/Collection.py | 2 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Plugins/Packages/Yum.py | 93 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Plugins/SSLCA.py | 5 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Plugins/TemplateHelper.py | 18 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Reports/updatefix.py | 5 |
15 files changed, 189 insertions, 128 deletions
diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index f93ca0a7b..1b0ecadf5 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -332,9 +332,23 @@ class BaseCore(object): self.fam.handle_event_set(self.lock) except: continue - # VCS plugin periodic updates - for plugin in self.plugins_by_type(Bcfg2.Server.Plugin.Version): - self.revision = plugin.get_revision() + self._update_vcs_revision() + + @track_statistics() + def _update_vcs_revision(self): + """ Update the revision of the current configuration on-disk + from the VCS plugin """ + for plugin in self.plugins_by_type(Bcfg2.Server.Plugin.Version): + try: + newrev = plugin.get_revision() + if newrev != self.revision: + self.logger.debug("Updated to revision %s" % newrev) + self.revision = newrev + break + except: + self.logger.warning("Error getting revision from %s: %s" % + (plugin.name, sys.exc_info()[1])) + self.revision = '-1' def init_plugin(self, plugin): """ Import and instantiate a single plugin. The plugin is @@ -360,8 +374,8 @@ class BaseCore(object): try: plug = getattr(mod, plugin.split('.')[-1]) except AttributeError: - self.logger.error("Failed to load plugin %s (AttributeError)" % - plugin) + self.logger.error("Failed to load plugin %s: %s" % + (plugin, sys.exc_info()[1])) return # Blacklist conflicting plugins cplugs = [conflict for conflict in plug.conflicts @@ -536,18 +550,16 @@ class BaseCore(object): continue try: self.Bind(entry, metadata) - except PluginExecutionError: - exc = sys.exc_info()[1] - if 'failure' not in entry.attrib: - entry.set('failure', 'bind error: %s' % exc) - self.logger.error("Failed to bind entry %s:%s: %s" % - (entry.tag, entry.get('name'), exc)) - except Exception: + except: exc = sys.exc_info()[1] if 'failure' not in entry.attrib: entry.set('failure', 'bind error: %s' % exc) - self.logger.error("Unexpected failure in BindStructure: %s %s" - % (entry.tag, entry.get('name')), exc_info=1) + if isinstance(exc, PluginExecutionError): + msg = "Failed to bind entry" + else: + msg = "Unexpected failure binding entry" + self.logger.error("%s %s:%s: %s" % + (msg, entry.tag, entry.get('name'), exc)) def Bind(self, entry, metadata): """ Bind a single entry using the appropriate generator. diff --git a/src/lib/Bcfg2/Server/Encryption.py b/src/lib/Bcfg2/Server/Encryption.py index c931ed2a7..b46337eb0 100755 --- a/src/lib/Bcfg2/Server/Encryption.py +++ b/src/lib/Bcfg2/Server/Encryption.py @@ -30,6 +30,9 @@ CFG_SECTION = "encryption" #: The config option used to store the algorithm CFG_ALGORITHM = "algorithm" +#: The config option used to store the decryption strictness +CFG_DECRYPT = "decrypt" + #: Default cipher algorithm. To get a full list of valid algorithms, #: you can run:: #: @@ -40,6 +43,7 @@ ALGORITHM = Bcfg2.Options.get_option_parser().cfp.get( # pylint: disable=E1103 CFG_ALGORITHM, default="aes_256_cbc").lower().replace("-", "_") + Rand.rand_seed(os.urandom(1024)) @@ -165,7 +169,7 @@ def get_passphrases(): if setup.cfp.has_section(CFG_SECTION): return dict([(o, setup.cfp.get(CFG_SECTION, o)) for o in setup.cfp.options(CFG_SECTION) - if o != CFG_ALGORITHM]) + if o not in [CFG_ALGORITHM, CFG_DECRYPT]]) else: return dict() diff --git a/src/lib/Bcfg2/Server/Lint/Comments.py b/src/lib/Bcfg2/Server/Lint/Comments.py index ecea1ad1b..8bfb76461 100644 --- a/src/lib/Bcfg2/Server/Lint/Comments.py +++ b/src/lib/Bcfg2/Server/Lint/Comments.py @@ -130,7 +130,7 @@ class Comments(Bcfg2.Server.Lint.ServerPlugin): rtype) def check_plaintext(self, filename, data, rtype): - """ check generic plaintex files for required headers """ + """ check generic plaintext files for required headers """ self.check_lines(filename, data.splitlines(), rtype) def check_lines(self, filename, lines, rtype): diff --git a/src/lib/Bcfg2/Server/Lint/Genshi.py b/src/lib/Bcfg2/Server/Lint/Genshi.py index 437e69d82..ed0d9930f 100755 --- a/src/lib/Bcfg2/Server/Lint/Genshi.py +++ b/src/lib/Bcfg2/Server/Lint/Genshi.py @@ -1,8 +1,11 @@ """ Check Genshi templates for syntax errors """ import sys -import genshi.template import Bcfg2.Server.Lint +from genshi.template import TemplateLoader, NewTextTemplate, MarkupTemplate, \ + TemplateSyntaxError +from Bcfg2.Server.Plugins.Bundler import BundleTemplateFile +from Bcfg2.Server.Plugins.Cfg.CfgGenshiGenerator import CfgGenshiGenerator class Genshi(Bcfg2.Server.Lint.ServerPlugin): @@ -10,29 +13,40 @@ class Genshi(Bcfg2.Server.Lint.ServerPlugin): def Run(self): """ run plugin """ - loader = genshi.template.TemplateLoader() if 'Cfg' in self.core.plugins: - self.check_files(self.core.plugins['Cfg'].entries, - loader=loader) + self.check_cfg() + if 'Bundler' in self.core.plugins: + self.check_bundler() @classmethod def Errors(cls): return {"genshi-syntax-error": "error"} - def check_files(self, entries, loader=None): - """ Check genshi templates in a list of entries for syntax - errors """ - if loader is None: - loader = genshi.template.TemplateLoader() - - for eset in entries.values(): - for fname, sdata in list(eset.entries.items()): - if (self.HandlesFile(fname) and - (fname.endswith(".genshi") or fname.endswith(".newtxt"))): + def check_cfg(self): + """ Check genshi templates in Cfg for syntax errors """ + for entryset in self.core.plugins['Cfg'].entries.values(): + for entry in entryset.entries.values(): + if (self.HandlesFile(entry.name) and + isinstance(entry, CfgGenshiGenerator) and + not entry.template): try: - loader.load(sdata.name, - cls=genshi.template.NewTextTemplate) - except genshi.template.TemplateSyntaxError: + entry.loader.load(entry.name, + cls=NewTextTemplate) + except TemplateSyntaxError: err = sys.exc_info()[1] self.LintError("genshi-syntax-error", "Genshi syntax error: %s" % err) + + def check_bundler(self): + """ Check templates in Bundler for syntax errors """ + loader = TemplateLoader() + + for entry in self.core.plugins['Bundler'].entries.values(): + if (self.HandlesFile(entry.name) and + isinstance(entry, BundleTemplateFile)): + try: + loader.load(entry.name, cls=MarkupTemplate) + except TemplateSyntaxError: + err = sys.exc_info()[1] + self.LintError("genshi-syntax-error", + "Genshi syntax error: %s" % err) diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgExternalCommandVerifier.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgExternalCommandVerifier.py index b702ac899..313e53ee9 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgExternalCommandVerifier.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgExternalCommandVerifier.py @@ -23,10 +23,15 @@ class CfgExternalCommandVerifier(CfgVerifier): def verify_entry(self, entry, metadata, data): try: proc = Popen(self.cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE) - err = proc.communicate(input=data)[1] + out, err = proc.communicate(input=data) rv = proc.wait() if rv != 0: - raise CfgVerificationError(err) + # pylint: disable=E1103 + raise CfgVerificationError(err.strip() or out.strip() or + "Non-zero return value %s" % rv) + # pylint: enable=E1103 + except CfgVerificationError: + raise except: err = sys.exc_info()[1] raise CfgVerificationError("Error running external command " diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py index c11939bd5..5f10879be 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py @@ -166,6 +166,7 @@ class CfgGenshiGenerator(CfgGenerator): raise def handle_event(self, event): + CfgGenerator.handle_event(self, event) try: self.template = self.loader.load(self.name, cls=NewTextTemplate, encoding=self.encoding) diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py b/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py index 81adea42f..2301de725 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py @@ -553,11 +553,10 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet, try: self._validate_data(entry, metadata, data) except CfgVerificationError: - msg = "Data for %s for %s failed to verify: %s" % \ - (entry.get('name'), metadata.hostname, - sys.exc_info()[1]) - self.logger.error(msg) - raise PluginExecutionError(msg) + raise PluginExecutionError("Failed to verify %s for %s: %s" % + (entry.get('name'), + metadata.hostname, + sys.exc_info()[1])) if entry.get('encoding') == 'base64': data = b64encode(data) diff --git a/src/lib/Bcfg2/Server/Plugins/Defaults.py b/src/lib/Bcfg2/Server/Plugins/Defaults.py index f4d86a64f..04c14aa96 100644 --- a/src/lib/Bcfg2/Server/Plugins/Defaults.py +++ b/src/lib/Bcfg2/Server/Plugins/Defaults.py @@ -5,7 +5,7 @@ import Bcfg2.Server.Plugins.Rules class Defaults(Bcfg2.Server.Plugins.Rules.Rules, - Bcfg2.Server.Plugin.StructureValidator): + Bcfg2.Server.Plugin.GoalValidator): """Set default attributes on bound entries""" __author__ = 'bcfg-dev@mcs.anl.gov' @@ -22,27 +22,18 @@ class Defaults(Bcfg2.Server.Plugins.Rules.Rules, def HandleEvent(self, event): Bcfg2.Server.Plugin.XMLDirectoryBacked.HandleEvent(self, event) - def validate_structures(self, metadata, structures): + def validate_goals(self, metadata, config): """ Apply defaults """ - for struct in structures: + for struct in config.getchildren(): for entry in struct.getchildren(): - if entry.tag.startswith("Bound"): - is_bound = True - entry.tag = entry.tag[5:] - else: - is_bound = False try: - try: - self.BindEntry(entry, metadata) - except Bcfg2.Server.Plugin.PluginExecutionError: - # either no matching defaults (which is okay), - # or multiple matching defaults (which is not - # okay, but is logged). either way, we don't - # care about the error. - pass - finally: - if is_bound: - entry.tag = "Bound" + entry.tag + self.BindEntry(entry, metadata) + except Bcfg2.Server.Plugin.PluginExecutionError: + # either no matching defaults (which is okay), + # or multiple matching defaults (which is not + # okay, but is logged). either way, we don't + # care about the error. + pass @property def _regex_enabled(self): diff --git a/src/lib/Bcfg2/Server/Plugins/Git.py b/src/lib/Bcfg2/Server/Plugins/Git.py index 8cc63a46f..c8362db41 100644 --- a/src/lib/Bcfg2/Server/Plugins/Git.py +++ b/src/lib/Bcfg2/Server/Plugins/Git.py @@ -2,7 +2,7 @@ git. """ import sys -import Bcfg2.Server.Plugin +from Bcfg2.Server.Plugin import Version, PluginExecutionError from subprocess import Popen, PIPE try: @@ -12,16 +12,16 @@ except ImportError: HAS_GITPYTHON = False -class Git(Bcfg2.Server.Plugin.Version): +class Git(Version): """ The Git plugin provides a revision interface for Bcfg2 repos using git. """ __author__ = 'bcfg-dev@mcs.anl.gov' __vcs_metadata_path__ = ".git" if HAS_GITPYTHON: - __rmi__ = Bcfg2.Server.Plugin.Version.__rmi__ + ['Update'] + __rmi__ = Version.__rmi__ + ['Update'] def __init__(self, core, datastore): - Bcfg2.Server.Plugin.Version.__init__(self, core, datastore) + Version.__init__(self, core, datastore) if HAS_GITPYTHON: self.repo = git.Repo(self.vcs_root) else: @@ -31,6 +31,11 @@ class Git(Bcfg2.Server.Plugin.Version): self.logger.debug("Initialized git plugin with git directory %s" % self.vcs_path) + def _log_git_cmd(self, output): + """ Send output from a GitPython command to the debug log """ + for line in output.strip().splitlines(): + self.debug_log("Git: %s" % line) + def get_revision(self): """Read git revision information for the Bcfg2 repository.""" try: @@ -46,11 +51,9 @@ class Git(Bcfg2.Server.Plugin.Version): raise Exception(err) return rv except: - err = sys.exc_info()[1] - msg = "Git: Error getting revision from %s: %s" % (self.vcs_root, - err) - self.logger.error(msg) - raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + raise PluginExecutionError("Git: Error getting revision from %s: " + "%s" % (self.vcs_root, + sys.exc_info()[1])) def Update(self, ref=None): """ Git.Update() => True|False @@ -60,20 +63,25 @@ class Git(Bcfg2.Server.Plugin.Version): self.debug_log("Git: Performing garbage collection on repo at %s" % self.vcs_root) try: - self.repo.git.gc('--auto') + self._log_git_cmd(self.repo.git.gc('--auto')) except git.GitCommandError: self.logger.warning("Git: Failed to perform garbage collection: %s" % sys.exc_info()[1]) + self.debug_log("Git: Fetching all refs for repo at %s" % self.vcs_root) + try: + self._log_git_cmd(self.repo.git.fetch('--all')) + except git.GitCommandError: + self.logger.warning("Git: Failed to fetch refs: %s" % + sys.exc_info()[1]) + if ref: self.debug_log("Git: Checking out %s" % ref) try: - self.repo.git.checkout('-f', ref) + self._log_git_cmd(self.repo.git.checkout('-f', ref)) except git.GitCommandError: - err = sys.exc_info()[1] - msg = "Git: Failed to checkout %s: %s" % (ref, err) - self.logger.error(msg) - raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + raise PluginExecutionError("Git: Failed to checkout %s: %s" % + (ref, sys.exc_info()[1])) # determine if we should try to pull to get the latest commit # on this head @@ -87,12 +95,10 @@ class Git(Bcfg2.Server.Plugin.Version): self.debug_log("Git: %s is a tracking branch, pulling from %s" % (self.repo.head.ref.name, tracking)) try: - self.repo.git.pull("--rebase") - except: # pylint: disable=W0702 - err = sys.exc_info()[1] - msg = "Git: Failed to pull from upstream: %s" % err - self.logger.error(msg) - raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + self._log_git_cmd(self.repo.git.pull("--rebase")) + except git.GitCommandError: + raise PluginExecutionError("Git: Failed to pull from " + "upstream: %s" % sys.exc_info()[1]) self.logger.info("Git: Repo at %s updated to %s" % (self.vcs_root, self.get_revision())) diff --git a/src/lib/Bcfg2/Server/Plugins/Metadata.py b/src/lib/Bcfg2/Server/Plugins/Metadata.py index e568c5c65..b053e65d3 100644 --- a/src/lib/Bcfg2/Server/Plugins/Metadata.py +++ b/src/lib/Bcfg2/Server/Plugins/Metadata.py @@ -1452,7 +1452,7 @@ class MetadataLint(Bcfg2.Server.Lint.ServerPlugin): defaults = [] for grp in self.metadata.groups_xml.xdata.xpath("//Groups/Group") + \ self.metadata.groups_xml.xdata.xpath("//Groups/Group//Group"): - if grp.get("default"): + if grp.get("default", "false").lower() == "true": defaults.append(self.RenderXML(grp)) if len(defaults) > 1: self.LintError("multiple-default-groups", diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Collection.py b/src/lib/Bcfg2/Server/Plugins/Packages/Collection.py index 3ad64b242..59eefe143 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Collection.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Collection.py @@ -533,7 +533,7 @@ class Collection(list, Bcfg2.Server.Plugin.Debuggable): # should be resolved current = pkgs.pop() self.debug_log("Packages: handling package requirement %s" % - current) + (current,)) packages.add(current) deps = self.get_deps(current) newdeps = set(deps).difference(examined) diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py index 4057ed230..775caaa08 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py @@ -684,6 +684,21 @@ class YumCollection(Collection): return self.call_helper("get_groups", inputdata=gdicts) + def _element_to_pkg(self, el, name): + """ Convert a Package or Instance element to a package tuple """ + rv = (name, el.get("arch"), el.get("epoch"), + el.get("version"), el.get("release")) + if rv[3] in ['any', 'auto']: + rv = (rv[0], rv[1], rv[2], None, None) + # if a package requires no specific version, we just use + # the name, not the tuple. this limits the amount of JSON + # encoding/decoding that has to be done to pass the + # package list to bcfg2-yum-helper. + if rv[1:] == (None, None, None, None): + return name + else: + return rv + def packages_from_entry(self, entry): """ When using the Python yum libraries, convert a Package entry to a list of package tuples. See :ref:`yum-pkg-objects` @@ -693,32 +708,42 @@ class YumCollection(Collection): :type entry: lxml.etree._Element :returns: list of tuples """ + if not self.use_yum: + return Collection.packages_from_entry(self, entry) + rv = set() name = entry.get("name") - def _tag_to_pkg(tag): - """ Convert a Package or Instance tag to a package tuple """ - rv = (name, tag.get("arch"), tag.get("epoch"), - tag.get("version"), tag.get("release")) - if rv[3] in ['any', 'auto']: - rv = (rv[0], rv[1], rv[2], None, None) - # if a package requires no specific version, we just use - # the name, not the tuple. this limits the amount of JSON - # encoding/decoding that has to be done to pass the - # package list to bcfg2-yum-helper. - if rv[1:] == (None, None, None, None): - return name - else: - return rv - for inst in entry.getchildren(): if inst.tag != "Instance": continue - rv.add(_tag_to_pkg(inst)) + rv.add(self._element_to_pkg(inst, name)) if not rv: - rv.add(_tag_to_pkg(entry)) + rv.add(self._element_to_pkg(entry, name)) return list(rv) + def _get_entry_attrs(self, pkgtup): + """ Given a package tuple, return a dict of attributes + suitable for applying to either a Package or an Instance + tag """ + attrs = dict(version=self.setup.cfp.get("packages", "version", + default="auto")) + if attrs['version'] == 'any' or not isinstance(pkgtup, tuple): + return attrs + + try: + if pkgtup[1]: + attrs['arch'] = pkgtup[1] + if pkgtup[2]: + attrs['epoch'] = pkgtup[2] + if pkgtup[3]: + attrs['version'] = pkgtup[3] + if pkgtup[4]: + attrs['release'] = pkgtup[4] + except IndexError: + self.logger.warning("Malformed package tuple: %s" % pkgtup) + return attrs + def packages_to_entry(self, pkglist, entry): """ When using the Python yum libraries, convert a list of package tuples to a Package entry. See :ref:`yum-pkg-objects` @@ -738,28 +763,8 @@ class YumCollection(Collection): :type entry: lxml.etree._Element :returns: None """ - def _get_entry_attrs(pkgtup): - """ Given a package tuple, return a dict of attributes - suitable for applying to either a Package or an Instance - tag """ - attrs = dict(version=self.setup.cfp.get("packages", - "version", - default="auto")) - if attrs['version'] == 'any' or not isinstance(pkgtup, tuple): - return attrs - - try: - if pkgtup[1]: - attrs['arch'] = pkgtup[1] - if pkgtup[2]: - attrs['epoch'] = pkgtup[2] - if pkgtup[3]: - attrs['version'] = pkgtup[3] - if pkgtup[4]: - attrs['release'] = pkgtup[4] - except IndexError: - self.logger.warning("Malformed package tuple: %s" % pkgtup) - return attrs + if not self.use_yum: + return Collection.packages_to_entry(self, pkglist, entry) packages = dict() for pkg in pkglist: @@ -776,9 +781,9 @@ class YumCollection(Collection): **pkgattrs) for inst in instances: lxml.etree.SubElement(pkg_el, "Instance", - _get_entry_attrs(inst)) + self._get_entry_attrs(inst)) else: - attrs = _get_entry_attrs(instances[0]) + attrs = self._get_entry_attrs(instances[0]) attrs.update(pkgattrs) lxml.etree.SubElement(entry, 'BoundPackage', **attrs) @@ -803,7 +808,11 @@ class YumCollection(Collection): initial_names.append(pkg) new = [] for pkg in complete: - if pkg[0] not in initial_names: + if isinstance(pkg, tuple): + name = pkg[0] + else: + name = pkg + if name not in initial_names: new.append(pkg) return new diff --git a/src/lib/Bcfg2/Server/Plugins/SSLCA.py b/src/lib/Bcfg2/Server/Plugins/SSLCA.py index cc1a2ceac..ab2f80552 100644 --- a/src/lib/Bcfg2/Server/Plugins/SSLCA.py +++ b/src/lib/Bcfg2/Server/Plugins/SSLCA.py @@ -180,7 +180,7 @@ class SSLCAEntrySet(Bcfg2.Server.Plugin.EntrySet): self.logger.error("SSLCA: Failed to unlink temporary files: %s" % sys.exc_info()[1]) if cert_spec['append_chain'] and 'chaincert' in ca: - cert += open(self.parent.get_ca(ca)['chaincert']).read() + cert += open(ca['chaincert']).read() open(os.path.join(self.path, filename), 'w').write(cert) return cert @@ -363,7 +363,8 @@ class SSLCA(Bcfg2.Server.Plugin.GroupSpool): """ The SSLCA generator handles the creation and management of ssl certificates and their keys. """ __author__ = 'g.hagger@gmail.com' - es_cls = lambda self, *args: SSLCAEntrySet(*args, parent=self) + # python 2.5 doesn't support mixing *magic and keyword arguments + es_cls = lambda self, *args: SSLCAEntrySet(*args, **dict(parent=self)) es_child_cls = SSLCADataFile def get_ca(self, name): diff --git a/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py b/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py index e3f8ed749..ad3eb65bc 100644 --- a/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py +++ b/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py @@ -12,12 +12,25 @@ LOGGER = logging.getLogger(__name__) MODULE_RE = re.compile(r'(?P<filename>(?P<module>[^\/]+)\.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): self.name = name + + #: 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): @@ -31,7 +44,8 @@ class HelperModule(object): return try: - module = imp.load_source(self._module_name, self.name) + 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" % @@ -97,7 +111,7 @@ class TemplateHelperLint(Bcfg2.Server.Lint.ServerPlugin): module_name = MODULE_RE.search(helper).group(1) try: - module = imp.load_source(module_name, helper) + module = imp.load_source(safe_module_name(module_name), helper) except: # pylint: disable=W0702 err = sys.exc_info()[1] self.LintError("templatehelper-import-error", diff --git a/src/lib/Bcfg2/Server/Reports/updatefix.py b/src/lib/Bcfg2/Server/Reports/updatefix.py index b377806ab..cb131c29d 100644 --- a/src/lib/Bcfg2/Server/Reports/updatefix.py +++ b/src/lib/Bcfg2/Server/Reports/updatefix.py @@ -80,6 +80,9 @@ def _populate_interaction_entry_counts(): cursor.close() +def update_noop(): + return True + # be sure to test your upgrade query before reflecting the change in the models # the list of function and sql command to do should go here _fixes = [_merge_database_table_entries, @@ -103,6 +106,8 @@ _fixes = [_merge_database_table_entries, _interactions_constraint_or_idx, 'alter table reports_reason add is_binary bool NOT NULL default False;', 'alter table reports_reason add is_sensitive bool NOT NULL default False;', + update_noop, #_remove_table_column('reports_interaction', 'client_version'), + "alter table reports_reason add unpruned varchar(1280) not null default 'N/A';", ] # this will calculate the last possible version of the database |