From 2454dddb3a5a0afdcfc2f875edfdcc7b5a85d4ba Mon Sep 17 00:00:00 2001 From: John Morris Date: Sun, 20 Apr 2014 17:06:54 -0500 Subject: Enable bcfg2-yum-helper to depsolve for arches incompatible with server By default, the yum dependency resolver uses the host's architecture to filter compatible packages. This prevents dependency resolution when the bcfg2 client's architecture is incompatible with the server's. This workaround checks the element for each of the client's yum sources, and if they are all identical, passes that architecture to bcfg2-yum-helper to override the default. The rpmUtils.arch module may only be configured for a single architecture. If multiple architectures are configured in yum sources, we don't know which one to pick, so use the default behavior instead. --- src/lib/Bcfg2/Server/Plugins/Packages/Yum.py | 29 ++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py index 67ff05ca1..6139a28b5 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py @@ -429,6 +429,25 @@ class YumCollection(Collection): yumconf.write(open(self.cfgfile, 'w')) + def get_arch(self): + """ If 'arch' for each source is the same, return that arch, otherwise + None. + + This helps bcfg2-yum-helper when the client arch is + incompatible with the bcfg2 server's arch. + + In case multiple arches are found, punt back to the default behavior. + """ + arches = set() + for source in self: + for url_map in source.url_map: + if url_map['arch'] in self.metadata.groups: + arches.add(url_map['arch']) + if len(arches) == 1: + return arches.pop() + else: + return None + def get_config(self, raw=False): # pylint: disable=W0221 """ Get the yum configuration for this collection. @@ -886,10 +905,12 @@ class YumCollection(Collection): if packagelist: try: - result = self.call_helper( - "complete", - dict(packages=list(packagelist), - groups=list(self.get_relevant_groups()))) + helper_dict = dict(packages=list(packagelist), + groups=list(self.get_relevant_groups())) + arch = self.get_arch() + if arch is not None: + helper_dict['arch'] = arch + result = self.call_helper("complete", helper_dict) except ValueError: # error reported by call_helper() return set(), packagelist -- cgit v1.2.3-1-g7c22 From 5888be3f06738f6a93cd6afab930369bdd2eb023 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Fri, 25 Apr 2014 07:52:35 -0400 Subject: reduce logging from failed decryption with decrypt=lax --- .../Server/Plugins/Cfg/CfgEncryptedGenerator.py | 21 +++++++++++---------- .../Server/Plugins/Cfg/CfgPrivateKeyCreator.py | 14 ++++++-------- src/lib/Bcfg2/Server/Plugins/Properties.py | 20 ++++++++------------ 3 files changed, 25 insertions(+), 30 deletions(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenerator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenerator.py index cf7eae75b..0a30a070a 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenerator.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenerator.py @@ -1,12 +1,11 @@ """ CfgEncryptedGenerator lets you encrypt your plaintext :ref:`server-plugins-generators-cfg` files on the server. """ -import Bcfg2.Server.Plugins.Cfg from Bcfg2.Server.Plugin import PluginExecutionError -from Bcfg2.Server.Plugins.Cfg import CfgGenerator +from Bcfg2.Server.Plugins.Cfg import CfgGenerator, SETUP try: from Bcfg2.Encryption import bruteforce_decrypt, EVPError, \ - get_algorithm + get_algorithm, CFG_SECTION HAS_CRYPTO = True except ImportError: HAS_CRYPTO = False @@ -27,7 +26,6 @@ class CfgEncryptedGenerator(CfgGenerator): CfgGenerator.__init__(self, fname, spec, encoding) if not HAS_CRYPTO: raise PluginExecutionError("M2Crypto is not available") - __init__.__doc__ = CfgGenerator.__init__.__doc__ def handle_event(self, event): CfgGenerator.handle_event(self, event) @@ -36,15 +34,18 @@ class CfgEncryptedGenerator(CfgGenerator): # todo: let the user specify a passphrase by name try: self.data = bruteforce_decrypt( - self.data, - setup=Bcfg2.Server.Plugins.Cfg.SETUP, - algorithm=get_algorithm(Bcfg2.Server.Plugins.Cfg.SETUP)) + self.data, setup=SETUP, + algorithm=get_algorithm(SETUP)) except EVPError: - raise PluginExecutionError("Failed to decrypt %s" % self.name) - handle_event.__doc__ = CfgGenerator.handle_event.__doc__ + strict = SETUP.cfp.get(CFG_SECTION, "decrypt", + default="strict") + msg = "Cfg: Failed to decrypt %s" % self.name + if strict: + raise PluginExecutionError(msg) + else: + self.logger.debug(msg) def get_data(self, entry, metadata): if self.data is None: raise PluginExecutionError("Failed to decrypt %s" % self.name) return CfgGenerator.get_data(self, entry, metadata) - get_data.__doc__ = CfgGenerator.get_data.__doc__ diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgPrivateKeyCreator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgPrivateKeyCreator.py index e890fdecb..ac031461a 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgPrivateKeyCreator.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgPrivateKeyCreator.py @@ -31,7 +31,6 @@ class CfgPrivateKeyCreator(CfgCreator, StructFile): pubkey_path = os.path.dirname(self.name) + ".pub" pubkey_name = os.path.join(pubkey_path, os.path.basename(pubkey_path)) self.pubkey_creator = CfgPublicKeyCreator(pubkey_name) - __init__.__doc__ = CfgCreator.__init__.__doc__ @property def category(self): @@ -55,7 +54,6 @@ class CfgPrivateKeyCreator(CfgCreator, StructFile): def handle_event(self, event): CfgCreator.handle_event(self, event) StructFile.HandleEvent(self, event) - handle_event.__doc__ = CfgCreator.handle_event.__doc__ def _gen_keypair(self, metadata, spec=None): """ Generate a keypair according to the given client medata @@ -201,10 +199,6 @@ class CfgPrivateKeyCreator(CfgCreator, StructFile): def Index(self): StructFile.Index(self) if HAS_CRYPTO: - strict = self.xdata.get( - "decrypt", - SETUP.cfp.get(Bcfg2.Encryption.CFG_SECTION, "decrypt", - default="strict")) == "strict" for el in self.xdata.xpath("//*[@encrypted]"): try: el.text = self._decrypt(el).encode('ascii', @@ -213,13 +207,17 @@ class CfgPrivateKeyCreator(CfgCreator, StructFile): self.logger.info("Cfg: Decrypted %s to gibberish, skipping" % el.tag) except Bcfg2.Encryption.EVPError: + default_strict = SETUP.cfp.get( + Bcfg2.Encryption.CFG_SECTION, "decrypt", + default="strict") + strict = self.xdata.get("decrypt", + default_strict) == "strict" msg = "Cfg: Failed to decrypt %s element in %s" % \ (el.tag, self.name) if strict: raise PluginExecutionError(msg) else: - self.logger.info(msg) - Index.__doc__ = StructFile.Index.__doc__ + self.logger.debug(msg) def _decrypt(self, element): """ Decrypt a single encrypted element """ diff --git a/src/lib/Bcfg2/Server/Plugins/Properties.py b/src/lib/Bcfg2/Server/Plugins/Properties.py index 8c6cf799a..ac0cc884a 100644 --- a/src/lib/Bcfg2/Server/Plugins/Properties.py +++ b/src/lib/Bcfg2/Server/Plugins/Properties.py @@ -172,7 +172,6 @@ class XMLPropertyFile(Bcfg2.Server.Plugin.StructFile, PropertyFile): Bcfg2.Server.Plugin.StructFile.__init__(self, name, fam=fam, should_monitor=should_monitor) PropertyFile.__init__(self, name) - __init__.__doc__ = Bcfg2.Server.Plugin.StructFile.__init__.__doc__ def _write(self): open(self.name, "wb").write( @@ -180,7 +179,6 @@ class XMLPropertyFile(Bcfg2.Server.Plugin.StructFile, PropertyFile): xml_declaration=False, pretty_print=True).decode('UTF-8')) return True - _write.__doc__ = PropertyFile._write.__doc__ def validate_data(self): """ ensure that the data in this object validates against the @@ -203,30 +201,28 @@ class XMLPropertyFile(Bcfg2.Server.Plugin.StructFile, PropertyFile): self.name) else: return True - validate_data.__doc__ = PropertyFile.validate_data.__doc__ def Index(self): Bcfg2.Server.Plugin.StructFile.Index(self) if HAS_CRYPTO: - strict = self.xdata.get( - "decrypt", - SETUP.cfp.get(Bcfg2.Encryption.CFG_SECTION, "decrypt", - default="strict")) == "strict" for el in self.xdata.xpath("//*[@encrypted]"): try: el.text = self._decrypt(el).encode('ascii', 'xmlcharrefreplace') except UnicodeDecodeError: - LOGGER.info("Properties: Decrypted %s to gibberish, " - "skipping" % el.tag) + self.logger.info("Properties: Decrypted %s to gibberish, " + "skipping" % el.tag) except Bcfg2.Encryption.EVPError: + strict = self.xdata.get( + "decrypt", + SETUP.cfp.get(Bcfg2.Encryption.CFG_SECTION, "decrypt", + default="strict")) == "strict" msg = "Properties: Failed to decrypt %s element in %s" % \ - (el.tag, self.name) + (el.tag, self.name) if strict: raise PluginExecutionError(msg) else: - LOGGER.info(msg) - Index.__doc__ = Bcfg2.Server.Plugin.StructFile.Index.__doc__ + self.logger.debug(msg) def _decrypt(self, element): """ Decrypt a single encrypted properties file element """ -- cgit v1.2.3-1-g7c22 From a88ce57202d778d0a4d95ef45d3d9361471c4525 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Fri, 25 Apr 2014 07:53:36 -0400 Subject: do not bruteforce Properties decrypts with unknown passphrase this greatly decreases startup time with lots of data encrypted with missing passphrases --- src/lib/Bcfg2/Server/Plugins/Properties.py | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Plugins/Properties.py b/src/lib/Bcfg2/Server/Plugins/Properties.py index ac0cc884a..6f054fd33 100644 --- a/src/lib/Bcfg2/Server/Plugins/Properties.py +++ b/src/lib/Bcfg2/Server/Plugins/Properties.py @@ -231,19 +231,12 @@ class XMLPropertyFile(Bcfg2.Server.Plugin.StructFile, PropertyFile): passes = Bcfg2.Encryption.get_passphrases(SETUP) try: passphrase = passes[element.get("encrypted")] - try: - return Bcfg2.Encryption.ssl_decrypt( - element.text, passphrase, - algorithm=Bcfg2.Encryption.get_algorithm(SETUP)) - except Bcfg2.Encryption.EVPError: - # error is raised below - pass - except KeyError: - # bruteforce_decrypt raises an EVPError with a sensible - # error message, so we just let it propagate up the stack - return Bcfg2.Encryption.bruteforce_decrypt( - element.text, passphrases=passes.values(), + return Bcfg2.Encryption.ssl_decrypt( + element.text, passphrase, algorithm=Bcfg2.Encryption.get_algorithm(SETUP)) + except KeyError: + raise Bcfg2.Encryption.EVPError("No passphrase named '%s'" % + element.get("encrypted")) raise Bcfg2.Encryption.EVPError("Failed to decrypt") def get_additional_data(self, metadata): -- cgit v1.2.3-1-g7c22 From 148239de876a0c8d2fb53fd644ffaabc70540370 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Fri, 25 Apr 2014 08:46:59 -0400 Subject: fixed pylint/pep-8 tests --- src/lib/Bcfg2/Server/Admin/Minestruct.py | 4 ++-- src/lib/Bcfg2/Server/Admin/Pull.py | 8 ++++---- src/lib/Bcfg2/Server/Admin/Viz.py | 20 ++++++++++---------- src/lib/Bcfg2/Server/Core.py | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Admin/Minestruct.py b/src/lib/Bcfg2/Server/Admin/Minestruct.py index 37ca74894..65f99a213 100644 --- a/src/lib/Bcfg2/Server/Admin/Minestruct.py +++ b/src/lib/Bcfg2/Server/Admin/Minestruct.py @@ -11,8 +11,8 @@ class Minestruct(Bcfg2.Server.Admin.StructureMode): __usage__ = ("[options] \n\n" " %-25s%s\n" " %-25s%s\n" % - ("-f ", "build a particular file", - "-g ", "only build config for groups")) + ("-f ", "build a particular file", + "-g ", "only build config for groups")) def __call__(self, args): if len(args) == 0: diff --git a/src/lib/Bcfg2/Server/Admin/Pull.py b/src/lib/Bcfg2/Server/Admin/Pull.py index 459fcec65..fccdb2d94 100644 --- a/src/lib/Bcfg2/Server/Admin/Pull.py +++ b/src/lib/Bcfg2/Server/Admin/Pull.py @@ -18,10 +18,10 @@ class Pull(Bcfg2.Server.Admin.MetadataCore): " %-25s%s\n" " %-25s%s\n" " %-25s%s\n" % - ("-v", "be verbose", - "-f", "force", - "-I", "interactive", - "-s", "stdin")) + ("-v", "be verbose", + "-f", "force", + "-I", "interactive", + "-s", "stdin")) def __init__(self, setup): Bcfg2.Server.Admin.MetadataCore.__init__(self, setup) diff --git a/src/lib/Bcfg2/Server/Admin/Viz.py b/src/lib/Bcfg2/Server/Admin/Viz.py index 2cbd7eaf6..cb2470e17 100644 --- a/src/lib/Bcfg2/Server/Admin/Viz.py +++ b/src/lib/Bcfg2/Server/Admin/Viz.py @@ -14,16 +14,16 @@ class Viz(Bcfg2.Server.Admin.MetadataCore): " %-32s%s\n" " %-32s%s\n" " %-32s%s\n" % - ("-H, --includehosts", - "include hosts in the viz output", - "-b, --includebundles", - "include bundles in the viz output", - "-k, --includekey", - "show a key for different digraph shapes", - "-c, --only-client ", - "show only the groups, bundles for the named client", - "-o, --outfile ", - "write viz output to an output file")) + ("-H, --includehosts", + "include hosts in the viz output", + "-b, --includebundles", + "include bundles in the viz output", + "-k, --includekey", + "show a key for different digraph shapes", + "-c, --only-client ", + "show only the groups, bundles for the named client", + "-o, --outfile ", + "write viz output to an output file")) colors = ['steelblue1', 'chartreuse', 'gold', 'magenta', 'indianred1', 'limegreen', 'orange1', 'lightblue2', diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index 4375512e9..44ba0fee8 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -387,7 +387,7 @@ class BaseCore(object): self.setup['plugins'].remove('') for plugin in self.setup['plugins']: - if not plugin in self.plugins: + if plugin not in self.plugins: self.init_plugin(plugin) # Remove blacklisted plugins -- cgit v1.2.3-1-g7c22