diff options
author | Chris St. Pierre <chris.a.st.pierre@gmail.com> | 2014-04-25 10:55:41 -0400 |
---|---|---|
committer | Chris St. Pierre <chris.a.st.pierre@gmail.com> | 2014-04-25 10:55:41 -0400 |
commit | cc27d0525f40ae5a7896992f4e42b8b9037d5b22 (patch) | |
tree | a8ca451a6fb356b305e56eefd193f2d6b3023898 | |
parent | 1ed010e2af5df7544dc316984736159de0c8a8ec (diff) | |
parent | c3edef5bd2b55266fee96327f17a093a0fb9cce4 (diff) | |
download | bcfg2-cc27d0525f40ae5a7896992f4e42b8b9037d5b22.tar.gz bcfg2-cc27d0525f40ae5a7896992f4e42b8b9037d5b22.tar.bz2 bcfg2-cc27d0525f40ae5a7896992f4e42b8b9037d5b22.zip |
Merge branch 'maint'
Conflicts:
misc/bcfg2.spec
src/lib/Bcfg2/Client/Client.py
src/lib/Bcfg2/Client/Tools/APK.py
src/lib/Bcfg2/Client/Tools/MacPorts.py
src/lib/Bcfg2/Client/Tools/Pacman.py
src/lib/Bcfg2/Client/Tools/YUM.py
src/lib/Bcfg2/Server/Admin/Minestruct.py
src/lib/Bcfg2/Server/Admin/Pull.py
src/lib/Bcfg2/Server/Admin/Viz.py
src/lib/Bcfg2/Server/Core.py
src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenerator.py
src/lib/Bcfg2/Server/Plugins/Cfg/CfgPrivateKeyCreator.py
src/lib/Bcfg2/Server/Plugins/Properties.py
src/lib/Bcfg2/settings.py
src/sbin/bcfg2-crypt
src/sbin/bcfg2-info
src/sbin/bcfg2-lint
src/sbin/bcfg2-yum-helper
testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgEncryptedGenerator.py
testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestProperties.py
27 files changed, 298 insertions, 321 deletions
diff --git a/misc/bcfg2.spec b/misc/bcfg2.spec index ab1394110..3539b0dec 100644 --- a/misc/bcfg2.spec +++ b/misc/bcfg2.spec @@ -561,11 +561,7 @@ sed "s@http://www.w3.org/2001/xml.xsd@file://$(pwd)/schemas/xml.xsd@" \ %if 0%{?suse_version} %fillup_and_insserv -f bcfg2 %else - %if 0%{?fedora} >= 16 - /bin/systemctl daemon-reload >/dev/null 2>&1 || : - %else - /sbin/chkconfig --add bcfg2 - %endif + /sbin/chkconfig --add bcfg2 %endif fi %endif @@ -579,11 +575,7 @@ sed "s@http://www.w3.org/2001/xml.xsd@file://$(pwd)/schemas/xml.xsd@" \ %if 0%{?suse_version} %fillup_and_insserv -f bcfg2-server %else - %if 0%{?fedora} >= 16 - /bin/systemctl daemon-reload >/dev/null 2>&1 || : - %else - /sbin/chkconfig --add bcfg2-server - %endif + /sbin/chkconfig --add bcfg2-server %endif fi %endif @@ -597,13 +589,8 @@ sed "s@http://www.w3.org/2001/xml.xsd@file://$(pwd)/schemas/xml.xsd@" \ %if 0%{?suse_version} %stop_on_removal bcfg2 %else - %if 0%{?fedora} >= 16 - /bin/systemctl --no-reload disable bcfg2.service > /dev/null 2>&1 || : - /bin/systemctl stop bcfg2.service > /dev/null 2>&1 || : - %else /sbin/service bcfg2 stop &>/dev/null || : /sbin/chkconfig --del bcfg2 - %endif %endif fi %endif @@ -618,13 +605,8 @@ sed "s@http://www.w3.org/2001/xml.xsd@file://$(pwd)/schemas/xml.xsd@" \ %stop_on_removal bcfg2-server %stop_on_removal bcfg2-report-collector %else - %if 0%{?fedora} >= 16 - /bin/systemctl --no-reload disable bcfg2-server.service > /dev/null 2>&1 || : - /bin/systemctl stop bcfg2-server.service > /dev/null 2>&1 || : - %else /sbin/service bcfg2-server stop &>/dev/null || : /sbin/chkconfig --del bcfg2-server - %endif %endif fi %endif @@ -641,11 +623,7 @@ sed "s@http://www.w3.org/2001/xml.xsd@file://$(pwd)/schemas/xml.xsd@" \ %if 0%{?suse_version} %insserv_cleanup %else - %if 0%{?fedora} >= 16 - /bin/systemctl try-restart bcfg2.service >/dev/null 2>&1 || : - %else /sbin/service bcfg2 condrestart &>/dev/null || : - %endif %endif fi %endif @@ -654,16 +632,9 @@ sed "s@http://www.w3.org/2001/xml.xsd@file://$(pwd)/schemas/xml.xsd@" \ %if 0%{?fedora} >= 18 %systemd_postun bcfg2-server.service %else - %if 0%{?fedora} >= 16 - /bin/systemctl daemon-reload >/dev/null 2>&1 || : - %endif if [ $1 -ge 1 ] ; then # Package upgrade, not uninstall - %if 0%{?fedora} >= 16 - /bin/systemctl try-restart bcfg2-server.service >/dev/null 2>&1 || : - %else /sbin/service bcfg2-server condrestart &>/dev/null || : - %endif fi %if 0%{?suse_version} if [ $1 -eq 0 ]; then @@ -793,6 +764,9 @@ sed "s@http://www.w3.org/2001/xml.xsd@file://$(pwd)/schemas/xml.xsd@" \ %changelog +* Wed Apr 23 2014 Jonathan S. Billings <jsbillin@umich.edu> - 1.3.4-2 +- Fixed RPM scriptlet logic for el6 vs. Fedora init commands + * Sun Apr 6 2014 John Morris <john@zultron.com> - 1.3.4-1 - New upstream release diff --git a/src/lib/Bcfg2/Client/Tools/APK.py b/src/lib/Bcfg2/Client/Tools/APK.py index 457197c28..7313f6fcc 100644 --- a/src/lib/Bcfg2/Client/Tools/APK.py +++ b/src/lib/Bcfg2/Client/Tools/APK.py @@ -25,7 +25,7 @@ class APK(Bcfg2.Client.Tools.PkgTool): def VerifyPackage(self, entry, _): """Verify Package status for entry.""" - if not 'version' in entry.attrib: + if 'version' not in entry.attrib: self.logger.info("Cannot verify unversioned package %s" % entry.attrib['name']) return False @@ -33,7 +33,7 @@ class APK(Bcfg2.Client.Tools.PkgTool): if entry.attrib['name'] in self.installed: if entry.attrib['version'] in \ ['auto', self.installed[entry.attrib['name']]]: - #FIXME: Does APK have any sort of verification mechanism? + # FIXME: Does APK have any sort of verification mechanism? return True else: self.logger.info(" pkg %s at version %s, not %s" % diff --git a/src/lib/Bcfg2/Client/Tools/FreeBSDPackage.py b/src/lib/Bcfg2/Client/Tools/FreeBSDPackage.py index 31925fa3c..22cf802cf 100644 --- a/src/lib/Bcfg2/Client/Tools/FreeBSDPackage.py +++ b/src/lib/Bcfg2/Client/Tools/FreeBSDPackage.py @@ -29,7 +29,7 @@ class FreeBSDPackage(Bcfg2.Client.Tools.PkgTool): self.installed[name] = version def VerifyPackage(self, entry, _): - if not 'version' in entry.attrib: + if 'version' not in entry.attrib: self.logger.info("Cannot verify unversioned package %s" % entry.attrib['name']) return False diff --git a/src/lib/Bcfg2/Client/Tools/IPS.py b/src/lib/Bcfg2/Client/Tools/IPS.py index c998ff083..0f82b1bc1 100644 --- a/src/lib/Bcfg2/Client/Tools/IPS.py +++ b/src/lib/Bcfg2/Client/Tools/IPS.py @@ -37,7 +37,7 @@ class IPS(Bcfg2.Client.Tools.PkgTool): def VerifyPackage(self, entry, _): """Verify package for entry.""" pname = entry.get('name') - if not 'version' in entry.attrib: + if 'version' not in entry.attrib: self.logger.info("Cannot verify unversioned package %s" % (pname)) return False if pname not in self.installed: diff --git a/src/lib/Bcfg2/Client/Tools/MacPorts.py b/src/lib/Bcfg2/Client/Tools/MacPorts.py index 265171a5a..1e9847c42 100644 --- a/src/lib/Bcfg2/Client/Tools/MacPorts.py +++ b/src/lib/Bcfg2/Client/Tools/MacPorts.py @@ -31,16 +31,16 @@ class MacPorts(Bcfg2.Client.Tools.PkgTool): def VerifyPackage(self, entry, _): """Verify Package status for entry.""" - if not 'version' in entry.attrib: + if 'version' not in entry.attrib: self.logger.info("Cannot verify unversioned package %s" % entry.attrib['name']) return False if entry.attrib['name'] in self.installed: if (self.installed[entry.attrib['name']] == entry.attrib['version'] - or entry.attrib['version'] == 'any'): - #FIXME: We should be able to check this once - # http://trac.macports.org/ticket/15709 is implemented + or entry.attrib['version'] == 'any'): + # FIXME: We should be able to check this once + # http://trac.macports.org/ticket/15709 is implemented return True else: self.logger.info(" %s: Wrong version installed. " diff --git a/src/lib/Bcfg2/Client/Tools/POSIX/Augeas.py b/src/lib/Bcfg2/Client/Tools/POSIX/Augeas.py index dc5fc6755..fc4e16904 100644 --- a/src/lib/Bcfg2/Client/Tools/POSIX/Augeas.py +++ b/src/lib/Bcfg2/Client/Tools/POSIX/Augeas.py @@ -195,7 +195,7 @@ class POSIXAugeas(POSIXTool): self._augeas = dict() # file tool for setting initial values of files that don't # exist - self.filetool = POSIXFile(logger, setup, config) + self.filetool = POSIXFile(config) def get_augeas(self, entry): """ Get an augeas object for the given entry. """ diff --git a/src/lib/Bcfg2/Client/Tools/POSIXUsers.py b/src/lib/Bcfg2/Client/Tools/POSIXUsers.py index 1a3b22506..a7fcb6709 100644 --- a/src/lib/Bcfg2/Client/Tools/POSIXUsers.py +++ b/src/lib/Bcfg2/Client/Tools/POSIXUsers.py @@ -79,7 +79,7 @@ class POSIXUsers(Bcfg2.Client.Tools.Tool): defined, and the uid/gid is in that whitelist; or b) no whitelist is defined, and the uid/gid is not in the blacklist. """ - if self._whitelist[tag] is None: + if not self._whitelist[tag]: return eid not in self._blacklist[tag] else: return eid in self._whitelist[tag] diff --git a/src/lib/Bcfg2/Client/Tools/Pacman.py b/src/lib/Bcfg2/Client/Tools/Pacman.py index 2ab9b7403..b82b905e7 100644 --- a/src/lib/Bcfg2/Client/Tools/Pacman.py +++ b/src/lib/Bcfg2/Client/Tools/Pacman.py @@ -19,7 +19,6 @@ class Pacman(Bcfg2.Client.Tools.PkgTool): for pkg in self.cmd.run("/usr/bin/pacman -Q").stdout.splitlines(): pkgname = pkg.split(' ')[0].strip() version = pkg.split(' ')[1].strip() - #self.logger.info(" pkgname: %s, version: %s" % (pkgname, version)) self.installed[pkgname] = version def VerifyPackage(self, entry, _): @@ -28,7 +27,7 @@ class Pacman(Bcfg2.Client.Tools.PkgTool): self.logger.info("VerifyPackage: %s : %s" % (entry.get('name'), entry.get('version'))) - if not 'version' in entry.attrib: + if 'version' not in entry.attrib: self.logger.info("Cannot verify unversioned package %s" % entry.attrib['name']) return False @@ -38,8 +37,8 @@ class Pacman(Bcfg2.Client.Tools.PkgTool): return True elif self.installed[entry.attrib['name']] == \ entry.attrib['version']: - #FIXME: need to figure out if pacman - # allows you to verify packages + # FIXME: need to figure out if pacman + # allows you to verify packages return True else: entry.set('current_version', self.installed[entry.get('name')]) diff --git a/src/lib/Bcfg2/Client/Tools/Portage.py b/src/lib/Bcfg2/Client/Tools/Portage.py index a61ede820..5c092f46b 100644 --- a/src/lib/Bcfg2/Client/Tools/Portage.py +++ b/src/lib/Bcfg2/Client/Tools/Portage.py @@ -50,7 +50,7 @@ class Portage(Bcfg2.Client.Tools.PkgTool): def VerifyPackage(self, entry, modlist): """Verify package for entry.""" - if not 'version' in entry.attrib: + if 'version' not in entry.attrib: self.logger.info("Cannot verify unversioned package %s" % (entry.get('name'))) return False @@ -68,11 +68,11 @@ class Portage(Bcfg2.Client.Tools.PkgTool): if ('verify' not in entry.attrib or entry.get('verify').lower() == 'true'): - # Check the package if: - # - Not running in quick mode - # - No verify option is specified in the literal configuration - # OR - # - Verify option is specified and is true + # Check the package if: + # - Not running in quick mode + # - No verify option is specified in the literal configuration + # OR + # - Verify option is specified and is true self.logger.debug('Running equery check on %s' % entry.get('name')) diff --git a/src/lib/Bcfg2/Client/Tools/SMF.py b/src/lib/Bcfg2/Client/Tools/SMF.py index 8b23a4a37..1a580d8a5 100644 --- a/src/lib/Bcfg2/Client/Tools/SMF.py +++ b/src/lib/Bcfg2/Client/Tools/SMF.py @@ -25,7 +25,7 @@ class SMF(Bcfg2.Client.Tools.SvcTool): def GetFMRI(self, entry): """Perform FMRI resolution for service.""" - if not 'FMRI' in entry.attrib: + if 'FMRI' not in entry.attrib: rv = self.cmd.run(["/usr/bin/svcs", "-H", "-o", "FMRI", entry.get('name')]) if rv.success: diff --git a/src/lib/Bcfg2/Client/Tools/YUM.py b/src/lib/Bcfg2/Client/Tools/YUM.py index 7782581c1..ee1cd6fad 100644 --- a/src/lib/Bcfg2/Client/Tools/YUM.py +++ b/src/lib/Bcfg2/Client/Tools/YUM.py @@ -894,7 +894,7 @@ class YUM(Bcfg2.Client.Tools.PkgTool): cleanup() - def Install(self, packages): # pylint: disable=R0912,R0914 + def Install(self, packages): # pylint: disable=R0912,R0914,R0915 """ Try and fix everything that Yum.VerifyPackages() found wrong for each Package Entry. This can result in individual RPMs being installed (for the first time), deleted, downgraded @@ -956,14 +956,16 @@ class YUM(Bcfg2.Client.Tools.PkgTool): continue status = self.instance_status[inst] if (not status.get('installed', False) and - Bcfg2.Options.setup.yum_install_missing): + Bcfg2.Options.setup.yum_install_missing): queue_pkg(pkg, inst, install_pkgs) - elif status.get('version_fail', False) and self.do_upgrade: + elif (status.get('version_fail', False) and + Bcfg2.Options.setup.yum_fix_version): if pkg.get("package_fail_action") == "downgrade": queue_pkg(pkg, inst, downgrade_pkgs) else: queue_pkg(pkg, inst, upgrade_pkgs) - elif status.get('verify_fail', False) and self.do_reinst: + elif (status.get('verify_fail', False) and + Bcfg2.Options.setup.yum_reinstall_broken): queue_pkg(pkg, inst, reinstall_pkgs) else: # Either there was no Install/Version/Verify diff --git a/src/lib/Bcfg2/DBSettings.py b/src/lib/Bcfg2/DBSettings.py index 3b2edd849..c5b78ed0b 100644 --- a/src/lib/Bcfg2/DBSettings.py +++ b/src/lib/Bcfg2/DBSettings.py @@ -169,10 +169,10 @@ class PerApplicationRouter(object): """ Django database router for redirecting different applications to their own database """ - def _db_per_app(self, model, **hints): + def _db_per_app(self, model, **_): """ If a database with the same name as the application exists, use it. Otherwise use the default """ - return get_db_label(model._meta.app_label) + return get_db_label(model._meta.app_label) # pylint: disable=W0212 def db_for_read(self, model, **hints): """ Called when Django wants to find out what database to read from """ @@ -182,12 +182,14 @@ class PerApplicationRouter(object): """ Called when Django wants to find out what database to write to """ return self._db_per_app(model, **hints) - def allow_relation(self, obj1, obj2, **hints): + def allow_relation(self, obj1, obj2, **_): """ Called when Django wants to determine what relations to allow. Only allow relations within an app """ + # pylint: disable=W0212 return obj1._meta.app_label == obj2._meta.app_label + # pylint: enable=W0212 - def allow_syncdb(self, db, model): + def allow_syncdb(self, *_): """ Called when Django wants to determine which models to sync to a given database. Take the cowards way out and sync all models to all databases to allow for easy migrations. """ diff --git a/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py b/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py index b2d26d190..687b4b571 100644 --- a/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py +++ b/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py @@ -371,8 +371,8 @@ class DjangoORM(StorageBase): self.logger.error("Failed to import interaction: %s" % traceback.format_exc().splitlines()[-1]) finally: - self.logger.info("%s: Closing database connection" % - self.__class__.__name__) + self.logger.debug("%s: Closing database connection" % + self.__class__.__name__) db.close_connection() diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index 9c22d17ac..544f417b4 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -26,7 +26,6 @@ from Bcfg2.Server.Plugin import track_statistics try: from django.core.exceptions import ImproperlyConfigured - from django.core import management import django.conf HAS_DJANGO = True except ImportError: @@ -146,6 +145,10 @@ class Core(object): default='off', choices=['off', 'on', 'initial', 'cautious', 'aggressive'])] + #: The name of this server core. This can be overridden by core + #: implementations to provide a more specific name. + name = "Core" + def __init__(self): # pylint: disable=R0912,R0915 """ .. automethod:: _run @@ -356,7 +359,7 @@ class Core(object): This does not start plugin threads; that is done later, in :func:`Bcfg2.Server.Core.BaseCore.run` """ for plugin in Bcfg2.Options.setup.plugins: - if not plugin in self.plugins: + if plugin not in self.plugins: self.init_plugin(plugin) # Remove blacklisted plugins diff --git a/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py b/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py index 22c97a0fe..ebf4c4954 100644 --- a/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py +++ b/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py @@ -212,7 +212,7 @@ class RequiredAttrs(Bcfg2.Server.Lint.ServerPlugin): "attribute: \n%s" % self.RenderXML(path)) # ensure that abstract Package tags have either name # or group specified - for package in xdata.xpath("//Package"): + for package in bundle.xdata.xpath("//Package"): if ('name' not in package.attrib and 'group' not in package.attrib): self.LintError( diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index 407e9df46..b5ab1c18b 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -757,9 +757,6 @@ class StructFile(XMLFileBacked): err)) if HAS_CRYPTO and self.encryption: - lax_decrypt = self.xdata.get( - "lax_decryption", - str(Bcfg2.Options.setup.lax_decryption)).lower() == "true" for el in self.xdata.xpath("//*[@encrypted]"): try: el.text = self._decrypt(el).encode('ascii', @@ -768,10 +765,14 @@ class StructFile(XMLFileBacked): self.logger.info("%s: Decrypted %s to gibberish, skipping" % (self.name, el.tag)) except Bcfg2.Server.Encryption.EVPError: + lax_decrypt = self.xdata.get( + "lax_decryption", + str(Bcfg2.Options.setup.lax_decryption)).lower() == \ + "true" msg = "Failed to decrypt %s element in %s" % (el.tag, self.name) if lax_decrypt: - self.logger.warning(msg) + self.logger.debug(msg) else: raise PluginExecutionError(msg) Index.__doc__ = XMLFileBacked.Index.__doc__ @@ -783,16 +784,11 @@ class StructFile(XMLFileBacked): passes = Bcfg2.Options.setup.passphrases try: passphrase = passes[element.get("encrypted")] - try: - return Bcfg2.Server.Encryption.ssl_decrypt(element.text, - passphrase) - except Bcfg2.Server.Encryption.EVPError: - # error is raised below - pass + return Bcfg2.Server.Encryption.ssl_decrypt(element.text, + passphrase) except KeyError: - # bruteforce_decrypt raises an EVPError with a sensible - # error message, so we just let it propagate up the stack - return Bcfg2.Server.Encryption.bruteforce_decrypt(element.text) + raise Bcfg2.Server.Encryption.EVPError("No passphrase named '%s'" % + element.get("encrypted")) raise Bcfg2.Server.Encryption.EVPError("Failed to decrypt") def _include_element(self, item, metadata, *args): diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenerator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenerator.py index e2a2f696a..ae93fae4a 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenerator.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenerator.py @@ -1,6 +1,7 @@ """ CfgEncryptedGenerator lets you encrypt your plaintext :ref:`server-plugins-generators-cfg` files on the server. """ +import Bcfg2.Options from Bcfg2.Server.Plugin import PluginExecutionError from Bcfg2.Server.Plugins.Cfg import CfgGenerator try: @@ -25,7 +26,6 @@ class CfgEncryptedGenerator(CfgGenerator): CfgGenerator.__init__(self, fname, spec) 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) @@ -35,11 +35,14 @@ class CfgEncryptedGenerator(CfgGenerator): try: self.data = bruteforce_decrypt(self.data) except EVPError: - raise PluginExecutionError("Failed to decrypt %s" % self.name) - handle_event.__doc__ = CfgGenerator.handle_event.__doc__ + msg = "Cfg: Failed to decrypt %s" % self.name + print "lax decrypt: %s" % Bcfg2.Options.setup.lax_decryption + if Bcfg2.Options.setup.lax_decryption: + self.logger.debug(msg) + else: + raise PluginExecutionError(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 e9698f526..8cc3f7b21 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgPrivateKeyCreator.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgPrivateKeyCreator.py @@ -34,7 +34,6 @@ class CfgPrivateKeyCreator(XMLCfgCreator): pubkey_name = os.path.join(pubkey_path, os.path.basename(pubkey_path)) self.pubkey_creator = CfgPublicKeyCreator(pubkey_name) self.cmd = Executor() - __init__.__doc__ = XMLCfgCreator.__init__.__doc__ def _gen_keypair(self, metadata, spec=None): """ Generate a keypair according to the given client medata diff --git a/src/lib/Bcfg2/Server/Plugins/Metadata.py b/src/lib/Bcfg2/Server/Plugins/Metadata.py index bf51ff678..4c1c31307 100644 --- a/src/lib/Bcfg2/Server/Plugins/Metadata.py +++ b/src/lib/Bcfg2/Server/Plugins/Metadata.py @@ -1477,7 +1477,7 @@ class Metadata(Bcfg2.Server.Plugin.Metadata, # want detailed numbers of added/removed clients for # logging for client in added.union(removed): - self.expire_cache(client) + self.cache.expire(client) def start_client_run(self, metadata): """ Hook to reread client list if the database is in use """ diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py index 3cfda9e9c..2dc44d0c4 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py @@ -63,7 +63,7 @@ import Bcfg2.Server.Plugin import Bcfg2.Server.FileMonitor from lockfile import FileLock from Bcfg2.Utils import Executor -from distutils.spawn import find_executable +from distutils.spawn import find_executable # pylint: disable=E0611 # pylint: disable=W0622 from Bcfg2.Compat import StringIO, cPickle, HTTPError, URLError, \ ConfigParser, any @@ -347,8 +347,8 @@ class YumCollection(Collection): config file to see if it has been explicitly specified; next we see if it's in $PATH; finally we default to /usr/sbin, the default location. """ + # pylint: disable=W0212 if not self._helper: - # pylint: disable=W0212 self.__class__._helper = Bcfg2.Options.setup.yum_helper if not self.__class__._helper: # first see if bcfg2-yum-helper is in PATH @@ -416,6 +416,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. @@ -871,10 +890,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 diff --git a/src/lib/Bcfg2/Server/Plugins/Properties.py b/src/lib/Bcfg2/Server/Plugins/Properties.py index 04314218c..28400f6d2 100644 --- a/src/lib/Bcfg2/Server/Plugins/Properties.py +++ b/src/lib/Bcfg2/Server/Plugins/Properties.py @@ -163,7 +163,6 @@ class XMLPropertyFile(Bcfg2.Server.Plugin.StructFile, PropertyFile): Bcfg2.Server.Plugin.StructFile.__init__(self, name, should_monitor=should_monitor) PropertyFile.__init__(self, name) - __init__.__doc__ = Bcfg2.Server.Plugin.StructFile.__init__.__doc__ def _write(self): open(self.name, "wb").write( @@ -171,7 +170,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 @@ -194,7 +192,6 @@ class XMLPropertyFile(Bcfg2.Server.Plugin.StructFile, PropertyFile): self.name) else: return True - validate_data.__doc__ = PropertyFile.validate_data.__doc__ def get_additional_data(self, metadata): if Bcfg2.Options.setup.automatch: diff --git a/src/lib/Bcfg2/Server/Plugins/Svn.py b/src/lib/Bcfg2/Server/Plugins/Svn.py index b2a16e52e..b752650f0 100644 --- a/src/lib/Bcfg2/Server/Plugins/Svn.py +++ b/src/lib/Bcfg2/Server/Plugins/Svn.py @@ -20,8 +20,8 @@ class Svn(Bcfg2.Server.Plugin.Version): Bcfg2.Options.Option( cf=("svn", "conflict_resolution"), dest="svn_conflict_resolution", type=lambda v: v.replace("-", "_"), - choices=dir(pysvn.wc_conflict_choice), - default=pysvn.wc_conflict_choice.postpone, + choices=dir(pysvn.wc_conflict_choice), # pylint: disable=E1101 + default=pysvn.wc_conflict_choice.postpone, # pylint: disable=E1101 help="SVN conflict resolution method"), Bcfg2.Options.Option( cf=("svn", "user"), dest="svn_user", help="SVN username"), diff --git a/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIX/TestAugeas.py b/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIX/TestAugeas.py index b8534f5a8..500016c9d 100644 --- a/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIX/TestAugeas.py +++ b/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIX/TestAugeas.py @@ -48,200 +48,200 @@ test_data = """<Test> test_xdata = lxml.etree.XML(test_data) -if can_skip or HAS_AUGEAS: - class TestPOSIXAugeas(TestPOSIXTool): - test_obj = POSIXAugeas - - applied_commands = dict( - insert=lxml.etree.Element( - "Insert", label="Thing", - path='Test/Children[#attribute/identical = "true"]/Thing'), - set=lxml.etree.Element("Set", path="Test/Text/#text", - value="content with spaces"), - move=lxml.etree.Element( - "Move", source="Test/Foo", - destination='Test/Children[#attribute/identical = "false"]/Foo'), - remove=lxml.etree.Element("Remove", path="Test/Bar"), - clear=lxml.etree.Element("Clear", path="Test/Empty/#text"), - setm=lxml.etree.Element( - "SetMulti", sub="#text", value="same", - base='Test/Children[#attribute/multi = "true"]/Thing')) - - @skipUnless(HAS_AUGEAS, "Python Augeas libraries not found") - def setUp(self): - fd, self.tmpfile = tempfile.mkstemp() - os.fdopen(fd, 'w').write(test_data) - - def tearDown(self): - tmpfile = getattr(self, "tmpfile", None) - if tmpfile and os.path.exists(tmpfile): - os.unlink(tmpfile) - - def test_fully_specified(self): - ptool = self.get_obj() - - entry = lxml.etree.Element("Path", name="/test", type="augeas") - self.assertFalse(ptool.fully_specified(entry)) - - lxml.etree.SubElement(entry, "Set", path="/test", value="test") - self.assertTrue(ptool.fully_specified(entry)) - - def test_install(self): - # this is tested adequately by the other tests - pass - - def test_verify(self): - # this is tested adequately by the other tests - pass - - @patch("Bcfg2.Client.Tools.POSIX.Augeas.POSIXTool.verify") - def _verify(self, commands, mock_verify): - ptool = self.get_obj() - mock_verify.return_value = True - - entry = lxml.etree.Element("Path", name=self.tmpfile, - type="augeas", lens="Xml") - entry.extend(commands) - - modlist = [] - self.assertTrue(ptool.verify(entry, modlist)) - mock_verify.assert_called_with(ptool, entry, modlist) - self.assertXMLEqual(lxml.etree.parse(self.tmpfile).getroot(), - test_xdata) - - def test_verify_insert(self): - """ Test successfully verifying an Insert command """ - self._verify([self.applied_commands['insert']]) - - def test_verify_set(self): - """ Test successfully verifying a Set command """ - self._verify([self.applied_commands['set']]) - - def test_verify_move(self): - """ Test successfully verifying a Move command """ - self._verify([self.applied_commands['move']]) - - def test_verify_remove(self): - """ Test successfully verifying a Remove command """ - self._verify([self.applied_commands['remove']]) - - def test_verify_clear(self): - """ Test successfully verifying a Clear command """ - self._verify([self.applied_commands['clear']]) - - def test_verify_set_multi(self): - """ Test successfully verifying a SetMulti command """ - self._verify([self.applied_commands['setm']]) - - def test_verify_all(self): - """ Test successfully verifying multiple commands """ - self._verify(self.applied_commands.values()) - - @patch("Bcfg2.Client.Tools.POSIX.Augeas.POSIXTool.install") - def _install(self, commands, expected, mock_install, **attrs): - ptool = self.get_obj() - mock_install.return_value = True - - entry = lxml.etree.Element("Path", name=self.tmpfile, - type="augeas", lens="Xml") - for key, val in attrs.items(): - entry.set(key, val) - entry.extend(commands) - - self.assertTrue(ptool.install(entry)) - mock_install.assert_called_with(ptool, entry) - self.assertXMLEqual(lxml.etree.parse(self.tmpfile).getroot(), - expected) - - def test_install_set_existing(self): - """ Test setting the value of an existing node """ - expected = copy.deepcopy(test_xdata) - expected.find("Text").text = "Changed content" - self._install([lxml.etree.Element("Set", path="Test/Text/#text", - value="Changed content")], - expected) - - def test_install_set_new(self): - """ Test setting the value of an new node """ - expected = copy.deepcopy(test_xdata) - newtext = lxml.etree.SubElement(expected, "NewText") - newtext.text = "new content" - self._install([lxml.etree.Element("Set", path="Test/NewText/#text", - value="new content")], - expected) - - def test_install_remove(self): - """ Test removing a node """ - expected = copy.deepcopy(test_xdata) - expected.remove(expected.find("Attrs")) - self._install( - [lxml.etree.Element("Remove", - path='Test/*[#attribute/foo = "foo"]')], - expected) - - def test_install_move(self): - """ Test moving a node """ - expected = copy.deepcopy(test_xdata) - foo = expected.xpath("//Foo")[0] - expected.append(foo) - self._install( - [lxml.etree.Element("Move", source='Test/Children/Foo', - destination='Test/Foo')], - expected) - - def test_install_clear(self): - """ Test clearing a node """ - # TODO: clearing a node doesn't seem to work with the XML lens - # - # % augtool -b - # augtool> set /augeas/load/Xml/incl[3] "/tmp/test.xml" - # augtool> load - # augtool> clear '/files/tmp/test.xml/Test/Text/#text' - # augtool> save - # error: Failed to execute command - # saving failed (run 'print /augeas//error' for details) - # augtool> print /augeas//error - # - # The error isn't useful. - pass - - def test_install_set_multi(self): - """ Test setting multiple nodes at once """ - expected = copy.deepcopy(test_xdata) - for thing in expected.xpath("Children[@identical='true']/Thing"): - thing.text = "same" - self._install( - [lxml.etree.Element( - "SetMulti", value="same", - base='Test/Children[#attribute/identical = "true"]', - sub="Thing/#text")], - expected) - - def test_install_insert(self): - """ Test inserting a node """ - expected = copy.deepcopy(test_xdata) - children = expected.xpath("Children[@identical='true']")[0] - thing = lxml.etree.Element("Thing") - thing.text = "three" - children.append(thing) - self._install( - [lxml.etree.Element( - "Insert", - path='Test/Children[#attribute/identical = "true"]/Thing[2]', - label="Thing", where="after"), - lxml.etree.Element( - "Set", - path='Test/Children[#attribute/identical = "true"]/Thing[3]/#text', - value="three")], - expected) - - def test_install_initial(self): - """ Test creating initial content and then modifying it """ - os.unlink(self.tmpfile) - expected = copy.deepcopy(test_xdata) - expected.find("Text").text = "Changed content" - initial = lxml.etree.Element("Initial") - initial.text = test_data - modify = lxml.etree.Element("Set", path="Test/Text/#text", - value="Changed content") - self._install([initial, modify], expected, current_exists="false") +class TestPOSIXAugeas(TestPOSIXTool): + test_obj = POSIXAugeas + + applied_commands = dict( + insert=lxml.etree.Element( + "Insert", label="Thing", + path='Test/Children[#attribute/identical = "true"]/Thing'), + set=lxml.etree.Element("Set", path="Test/Text/#text", + value="content with spaces"), + move=lxml.etree.Element( + "Move", source="Test/Foo", + destination='Test/Children[#attribute/identical = "false"]/Foo'), + remove=lxml.etree.Element("Remove", path="Test/Bar"), + clear=lxml.etree.Element("Clear", path="Test/Empty/#text"), + setm=lxml.etree.Element( + "SetMulti", sub="#text", value="same", + base='Test/Children[#attribute/multi = "true"]/Thing')) + + @skipUnless(HAS_AUGEAS, "Python Augeas libraries not found") + def setUp(self): + TestPOSIXTool.setUp(self) + fd, self.tmpfile = tempfile.mkstemp() + os.fdopen(fd, 'w').write(test_data) + + def tearDown(self): + tmpfile = getattr(self, "tmpfile", None) + if tmpfile and os.path.exists(tmpfile): + os.unlink(tmpfile) + + def test_fully_specified(self): + ptool = self.get_obj() + + entry = lxml.etree.Element("Path", name="/test", type="augeas") + self.assertFalse(ptool.fully_specified(entry)) + + lxml.etree.SubElement(entry, "Set", path="/test", value="test") + self.assertTrue(ptool.fully_specified(entry)) + + def test_install(self): + # this is tested adequately by the other tests + pass + + def test_verify(self): + # this is tested adequately by the other tests + pass + + @patch("Bcfg2.Client.Tools.POSIX.Augeas.POSIXTool.verify") + def _verify(self, commands, mock_verify): + ptool = self.get_obj() + mock_verify.return_value = True + + entry = lxml.etree.Element("Path", name=self.tmpfile, + type="augeas", lens="Xml") + entry.extend(commands) + + modlist = [] + self.assertTrue(ptool.verify(entry, modlist)) + mock_verify.assert_called_with(ptool, entry, modlist) + self.assertXMLEqual(lxml.etree.parse(self.tmpfile).getroot(), + test_xdata) + + def test_verify_insert(self): + """ Test successfully verifying an Insert command """ + self._verify([self.applied_commands['insert']]) + + def test_verify_set(self): + """ Test successfully verifying a Set command """ + self._verify([self.applied_commands['set']]) + + def test_verify_move(self): + """ Test successfully verifying a Move command """ + self._verify([self.applied_commands['move']]) + + def test_verify_remove(self): + """ Test successfully verifying a Remove command """ + self._verify([self.applied_commands['remove']]) + + def test_verify_clear(self): + """ Test successfully verifying a Clear command """ + self._verify([self.applied_commands['clear']]) + + def test_verify_set_multi(self): + """ Test successfully verifying a SetMulti command """ + self._verify([self.applied_commands['setm']]) + + def test_verify_all(self): + """ Test successfully verifying multiple commands """ + self._verify(self.applied_commands.values()) + + @patch("Bcfg2.Client.Tools.POSIX.Augeas.POSIXTool.install") + def _install(self, commands, expected, mock_install, **attrs): + ptool = self.get_obj() + mock_install.return_value = True + + entry = lxml.etree.Element("Path", name=self.tmpfile, + type="augeas", lens="Xml") + for key, val in attrs.items(): + entry.set(key, val) + entry.extend(commands) + + self.assertTrue(ptool.install(entry)) + mock_install.assert_called_with(ptool, entry) + self.assertXMLEqual(lxml.etree.parse(self.tmpfile).getroot(), + expected) + + def test_install_set_existing(self): + """ Test setting the value of an existing node """ + expected = copy.deepcopy(test_xdata) + expected.find("Text").text = "Changed content" + self._install([lxml.etree.Element("Set", path="Test/Text/#text", + value="Changed content")], + expected) + + def test_install_set_new(self): + """ Test setting the value of an new node """ + expected = copy.deepcopy(test_xdata) + newtext = lxml.etree.SubElement(expected, "NewText") + newtext.text = "new content" + self._install([lxml.etree.Element("Set", path="Test/NewText/#text", + value="new content")], + expected) + + def test_install_remove(self): + """ Test removing a node """ + expected = copy.deepcopy(test_xdata) + expected.remove(expected.find("Attrs")) + self._install( + [lxml.etree.Element("Remove", + path='Test/*[#attribute/foo = "foo"]')], + expected) + + def test_install_move(self): + """ Test moving a node """ + expected = copy.deepcopy(test_xdata) + foo = expected.xpath("//Foo")[0] + expected.append(foo) + self._install( + [lxml.etree.Element("Move", source='Test/Children/Foo', + destination='Test/Foo')], + expected) + + def test_install_clear(self): + """ Test clearing a node """ + # TODO: clearing a node doesn't seem to work with the XML lens + # + # % augtool -b + # augtool> set /augeas/load/Xml/incl[3] "/tmp/test.xml" + # augtool> load + # augtool> clear '/files/tmp/test.xml/Test/Text/#text' + # augtool> save + # error: Failed to execute command + # saving failed (run 'print /augeas//error' for details) + # augtool> print /augeas//error + # + # The error isn't useful. + pass + + def test_install_set_multi(self): + """ Test setting multiple nodes at once """ + expected = copy.deepcopy(test_xdata) + for thing in expected.xpath("Children[@identical='true']/Thing"): + thing.text = "same" + self._install( + [lxml.etree.Element( + "SetMulti", value="same", + base='Test/Children[#attribute/identical = "true"]', + sub="Thing/#text")], + expected) + + def test_install_insert(self): + """ Test inserting a node """ + expected = copy.deepcopy(test_xdata) + children = expected.xpath("Children[@identical='true']")[0] + thing = lxml.etree.Element("Thing") + thing.text = "three" + children.append(thing) + self._install( + [lxml.etree.Element( + "Insert", + path='Test/Children[#attribute/identical = "true"]/Thing[2]', + label="Thing", where="after"), + lxml.etree.Element( + "Set", + path='Test/Children[#attribute/identical = "true"]/Thing[3]/#text', + value="three")], + expected) + + def test_install_initial(self): + """ Test creating initial content and then modifying it """ + os.unlink(self.tmpfile) + expected = copy.deepcopy(test_xdata) + expected.find("Text").text = "Changed content" + initial = lxml.etree.Element("Initial") + initial.text = test_data + modify = lxml.etree.Element("Set", path="Test/Text/#text", + value="Changed content") + self._install([initial, modify], expected, current_exists="false") diff --git a/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIXUsers.py b/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIXUsers.py index 9647413b6..cc1ea6fd7 100644 --- a/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIXUsers.py +++ b/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIXUsers.py @@ -26,10 +26,10 @@ class TestPOSIXUsers(TestTool): def setUp(self): TestTool.setUp(self) - set_setup_default('uid_whitelist') - set_setup_default('uid_blacklist') - set_setup_default('gid_whitelist') - set_setup_default('gid_blacklist') + set_setup_default('uid_whitelist', []) + set_setup_default('uid_blacklist', []) + set_setup_default('gid_whitelist', []) + set_setup_default('gid_blacklist', []) set_setup_default('encoding', 'UTF-8') def get_obj(self, config=None): diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py index 75bd4ec95..1f8449bb6 100644 --- a/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py +++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py @@ -773,19 +773,15 @@ class TestStructFile(TestXMLFileBacked): @skipUnless(HAS_CRYPTO, "No crypto libraries found, skipping") @patchIf(HAS_CRYPTO, "Bcfg2.Server.Encryption.ssl_decrypt") - @patchIf(HAS_CRYPTO, "Bcfg2.Server.Encryption.bruteforce_decrypt") - def test_decrypt(self, mock_bruteforce, mock_ssl): + def test_decrypt(self, mock_ssl): sf = self.get_obj() def reset(): - mock_bruteforce.reset_mock() mock_ssl.reset_mock() - # test element without text contents Bcfg2.Options.setup.passphrases = dict() self.assertIsNone(sf._decrypt(lxml.etree.Element("Test"))) - self.assertFalse(mock_bruteforce.called) self.assertFalse(mock_ssl.called) # test element with a passphrase in the config file @@ -796,29 +792,17 @@ class TestStructFile(TestXMLFileBacked): mock_ssl.return_value = "decrypted with ssl" self.assertEqual(sf._decrypt(el), mock_ssl.return_value) mock_ssl.assert_called_with(el.text, "foopass") - self.assertFalse(mock_bruteforce.called) - - # test failure to decrypt element with a passphrase in the config - reset() - mock_ssl.side_effect = EVPError - self.assertRaises(EVPError, sf._decrypt, el) - mock_ssl.assert_called_with(el.text, "foopass") - self.assertFalse(mock_bruteforce.called) # test element without valid passphrase reset() el.set("encrypted", "true") - mock_bruteforce.return_value = "decrypted with bruteforce" - self.assertEqual(sf._decrypt(el), mock_bruteforce.return_value) - mock_bruteforce.assert_called_with(el.text) + self.assertRaises(EVPError, sf._decrypt, el) self.assertFalse(mock_ssl.called) - # test failure to decrypt element without valid passphrase + # test failure to decrypt element with a passphrase in the config reset() - mock_bruteforce.side_effect = EVPError + mock_ssl.side_effect = EVPError self.assertRaises(EVPError, sf._decrypt, el) - mock_bruteforce.assert_called_with(el.text) - self.assertFalse(mock_ssl.called) def test_include_element(self): sf = self.get_obj() diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgEncryptedGenerator.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgEncryptedGenerator.py index 03b9fb0f4..7989bf514 100644 --- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgEncryptedGenerator.py +++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgEncryptedGenerator.py @@ -22,14 +22,11 @@ from TestServer.TestPlugins.TestCfg.Test_init import TestCfgGenerator class TestCfgEncryptedGenerator(TestCfgGenerator): test_obj = CfgEncryptedGenerator - @skipUnless(HAS_CRYPTO, "Encryption libraries not found, skipping") - def setUp(self): - TestCfgGenerator.setUp(self) - @patchIf(HAS_CRYPTO, "Bcfg2.Server.Plugins.Cfg.CfgEncryptedGenerator.bruteforce_decrypt") def test_handle_event(self, mock_decrypt): @patch("Bcfg2.Server.Plugins.Cfg.CfgGenerator.handle_event") + @patch("Bcfg2.Options.setup.lax_decryption", False) def inner(mock_handle_event): def reset(): mock_decrypt.reset_mock() diff --git a/testsuite/Testsrc/test_code_checks.py b/testsuite/Testsrc/test_code_checks.py index 17fac4fe4..2b8b05926 100644 --- a/testsuite/Testsrc/test_code_checks.py +++ b/testsuite/Testsrc/test_code_checks.py @@ -327,7 +327,7 @@ class TestPylint(CodeTestCase): class TestPEP8(CodeTestCase): __test__ = True - command = ["pep8", "--ignore=E125,E501"] + command = ["pep8", "--ignore=E125,E129,E501"] def _test_errors(self, files, extra_args=None): pass |