From ebe7542db7217c2fac3d7111e80f94caedfb69e2 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Wed, 16 Jan 2013 13:28:06 -0500 Subject: added module-level OptionParser to avoid passing it as an argument or global all over --- src/lib/Bcfg2/Client/Client.py | 4 +- src/lib/Bcfg2/Encryption.py | 53 +++------ src/lib/Bcfg2/Options.py | 68 +++++++++-- src/lib/Bcfg2/Server/Admin/Compare.py | 4 +- src/lib/Bcfg2/Server/Admin/Init.py | 24 ++-- src/lib/Bcfg2/Server/Admin/Perf.py | 22 ++-- src/lib/Bcfg2/Server/Admin/Pull.py | 4 +- src/lib/Bcfg2/Server/Admin/Reports.py | 4 +- src/lib/Bcfg2/Server/Admin/Snapshots.py | 4 +- src/lib/Bcfg2/Server/Admin/Syncdb.py | 10 +- src/lib/Bcfg2/Server/Admin/Xcmd.py | 29 +++-- src/lib/Bcfg2/Server/Admin/__init__.py | 20 ++-- src/lib/Bcfg2/Server/BuiltinCore.py | 4 +- src/lib/Bcfg2/Server/CherryPyCore.py | 4 +- src/lib/Bcfg2/Server/Core.py | 65 +++++------ src/lib/Bcfg2/Server/Plugin/helpers.py | 33 +++--- src/lib/Bcfg2/Server/Plugins/Bundler.py | 19 ++-- .../Plugins/Cfg/CfgAuthorizedKeysGenerator.py | 8 +- .../Server/Plugins/Cfg/CfgCheetahGenerator.py | 4 +- .../Server/Plugins/Cfg/CfgEncryptedGenerator.py | 8 +- .../Plugins/Cfg/CfgEncryptedGenshiGenerator.py | 7 +- .../Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py | 14 +-- .../Server/Plugins/Cfg/CfgPrivateKeyCreator.py | 34 +++--- src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py | 29 ++--- src/lib/Bcfg2/Server/Plugins/Properties.py | 22 ++-- src/lib/Bcfg2/Server/models.py | 13 +-- src/lib/Bcfg2/settings.py | 28 ++--- src/sbin/bcfg2 | 7 +- src/sbin/bcfg2-admin | 4 +- src/sbin/bcfg2-crypt | 34 +++--- src/sbin/bcfg2-info | 10 +- src/sbin/bcfg2-lint | 40 +++---- src/sbin/bcfg2-report-collector | 4 +- src/sbin/bcfg2-server | 6 +- src/sbin/bcfg2-test | 4 +- testsuite/Testsrc/Testlib/TestEncryption.py | 46 ++------ .../Testlib/TestServer/TestPlugin/Testhelpers.py | 12 +- .../TestCfg/TestCfgAuthorizedKeysGenerator.py | 32 +++--- .../TestPlugins/TestCfg/TestCfgCheetahGenerator.py | 7 +- .../TestCfg/TestCfgEncryptedGenerator.py | 9 +- .../TestPlugins/TestCfg/TestCfgGenshiGenerator.py | 14 +-- .../TestCfg/TestCfgPrivateKeyCreator.py | 126 ++++++++------------- .../TestServer/TestPlugins/TestCfg/Test_init.py | 41 ++++--- .../TestServer/TestPlugins/TestProperties.py | 85 ++++++-------- 44 files changed, 472 insertions(+), 547 deletions(-) diff --git a/src/lib/Bcfg2/Client/Client.py b/src/lib/Bcfg2/Client/Client.py index 45e0b64e6..ea898c42b 100644 --- a/src/lib/Bcfg2/Client/Client.py +++ b/src/lib/Bcfg2/Client/Client.py @@ -22,12 +22,12 @@ from subprocess import Popen, PIPE class Client(object): """ The main Bcfg2 client class """ - def __init__(self, setup): + def __init__(self): self.toolset = None self.tools = None self.config = None self._proxy = None - self.setup = setup + self.setup = Bcfg2.Options.get_option_parser() if self.setup['debug']: level = logging.DEBUG diff --git a/src/lib/Bcfg2/Encryption.py b/src/lib/Bcfg2/Encryption.py index 1eb5aaeb2..341956e03 100755 --- a/src/lib/Bcfg2/Encryption.py +++ b/src/lib/Bcfg2/Encryption.py @@ -3,6 +3,7 @@ handling encryption in Bcfg2. See :ref:`server-encryption` for more details. """ import os +import Bcfg2.Options from M2Crypto import Rand from M2Crypto.EVP import Cipher, EVPError from Bcfg2.Compat import StringIO, md5, b64encode, b64decode @@ -17,13 +18,6 @@ ENCRYPT = 1 #: makes our code more readable. DECRYPT = 0 -#: Default cipher algorithm. To get a full list of valid algorithms, -#: you can run:: -#: -#: openssl list-cipher-algorithms | grep -v ' => ' | \ -#: tr 'A-Z-' 'a-z_' | sort -u -ALGORITHM = "aes_256_cbc" - #: Default initialization vector. For best security, you should use a #: unique IV for each message. :func:`ssl_encrypt` does this in an #: automated fashion. @@ -36,6 +30,16 @@ CFG_SECTION = "encryption" #: The config option used to store the algorithm CFG_ALGORITHM = "algorithm" +#: Default cipher algorithm. To get a full list of valid algorithms, +#: you can run:: +#: +#: openssl list-cipher-algorithms | grep -v ' => ' | \ +#: tr 'A-Z-' 'a-z_' | sort -u +ALGORITHM = Bcfg2.Options.get_option_parser().cfp.get( # pylint: disable=E1103 + CFG_SECTION, + CFG_ALGORITHM, + default="aes_256_cbc").lower().replace("-", "_") + Rand.rand_seed(os.urandom(1024)) @@ -152,58 +156,37 @@ def ssl_encrypt(plaintext, passwd, algorithm=ALGORITHM, salt=None): return b64encode("Salted__" + salt + crypted) + "\n" -def get_algorithm(setup): - """ Get the cipher algorithm from the config file. This is used - in case someone uses the OpenSSL algorithm name (e.g., - "AES-256-CBC") instead of the M2Crypto name (e.g., "aes_256_cbc"), - and to handle errors in a sensible way and deduplicate this code. - - :param setup: The Bcfg2 option set to extract passphrases from - :type setup: Bcfg2.Options.OptionParser - :returns: dict - a dict of ````: ```` - """ - return setup.cfp.get(CFG_SECTION, CFG_ALGORITHM, - default=ALGORITHM).lower().replace("-", "_") - - -def get_passphrases(setup): +def get_passphrases(): """ Get all candidate encryption passphrases from the config file. - :param setup: The Bcfg2 option set to extract passphrases from - :type setup: Bcfg2.Options.OptionParser :returns: dict - a dict of ````: ```` """ - section = CFG_SECTION - if setup.cfp.has_section(section): - return dict([(o, setup.cfp.get(section, o)) - for o in setup.cfp.options(section) + setup = Bcfg2.Options.get_option_parser() + 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]) else: return dict() -def bruteforce_decrypt(crypted, passphrases=None, setup=None, - algorithm=ALGORITHM): +def bruteforce_decrypt(crypted, passphrases=None, algorithm=ALGORITHM): """ Convenience method to decrypt the given encrypted string by trying the given passphrases or all passphrases (as returned by :func:`get_passphrases`) sequentially until one is found that works. - Either ``passphrases`` or ``setup`` must be provided. - :param crypted: The data to decrypt :type crypted: string :param passphrases: The passphrases to try. :type passphrases: list - :param setup: A Bcfg2 option set to extract passphrases from - :type setup: Bcfg2.Options.OptionParser :param algorithm: The cipher algorithm to use :type algorithm: string :returns: string - The decrypted data :raises: :class:`M2Crypto.EVP.EVPError`, if the data cannot be decrypted """ if passphrases is None: - passphrases = get_passphrases(setup).values() + passphrases = get_passphrases().values() for passwd in passphrases: try: return ssl_decrypt(crypted, passwd, algorithm=algorithm) diff --git a/src/lib/Bcfg2/Options.py b/src/lib/Bcfg2/Options.py index c0a274e23..780619f3b 100644 --- a/src/lib/Bcfg2/Options.py +++ b/src/lib/Bcfg2/Options.py @@ -1106,6 +1106,14 @@ CRYPT_OPTIONS = dict(encrypt=ENCRYPT, cfg=CRYPT_CFG, remove=CRYPT_REMOVE) +PATH_METADATA_OPTIONS = dict(owner=MDATA_OWNER, + group=MDATA_GROUP, + mode=MDATA_MODE, + secontext=MDATA_SECONTEXT, + important=MDATA_IMPORTANT, + paranoid=MDATA_PARANOID, + sensitive=MDATA_SENSITIVE) + DRIVER_OPTIONS = \ dict(apt_install_path=CLIENT_APT_TOOLS_INSTALL_PATH, apt_var_path=CLIENT_APT_TOOLS_VAR_PATH, @@ -1190,10 +1198,11 @@ REPORTING_COMMON_OPTIONS = dict(reporting_file_limit=REPORTING_FILE_LIMIT, class OptionParser(OptionSet): - """ - OptionParser bootstraps option parsing, - getting the value of the config file - """ + """ OptionParser bootstraps option parsing, getting the value of + the config file. This should only be instantiated by + :func:`get_option_parser`, below, not by individual plugins or + scripts. """ + def __init__(self, args, argv=None, quiet=False): if argv is None: argv = sys.argv[1:] @@ -1208,17 +1217,21 @@ class OptionParser(OptionSet): self.argv = [] self.do_getopt = True - def reparse(self): + def reparse(self, argv=None, do_getopt=None): """ parse the options again, taking any changes (e.g., to the config file) into account """ for key, opt in self.optinfo.items(): self[key] = opt - if "args" not in self.optinfo: + if "args" not in self.optinfo and "args" in self: del self['args'] - self.parse(self.argv, self.do_getopt) + if do_getopt is None: + do_getopt = self.do_getopt + if argv is None: + argv = self.argv + self.parse(argv, do_getopt) - def parse(self, argv, do_getopt=True): - self.argv = argv + def parse(self, argv=None, do_getopt=True): + self.argv = argv or sys.argv[1:] self.do_getopt = do_getopt OptionSet.parse(self, self.argv, do_getopt=self.do_getopt) @@ -1227,6 +1240,43 @@ class OptionParser(OptionSet): self[name] = opt self.optinfo[name] = opt + def add_options(self, options): + """ Add a set of options to the parser """ + self.update(options) + self.optinfo.update(options) + def update(self, optdict): dict.update(self, optdict) self.optinfo.update(optdict) + + +#: A module-level OptionParser object that all plugins, etc., can use. +#: This should not be used directly, but retrieved via +#: :func:`get_option_parser`. +_PARSER = None + + +def get_option_parser(args=None, argv=None, quiet=False): + """ Get an OptionParser object. If :attr:`_PARSER` already + exists, that will be used; if not, a new OptionParser object will + be created. + + If ``args`` or ``argv`` are given, then a new OptionParser object + will be instantiated regardless of whether one already exists. + + :param args: The argument set to parse. This is required on the + first invocation of :func:`get_option_parser`. + :type args: dict of :class:`Bcfg2.Options.Option` objects + :param argv: The command-line argument list. If this is not + provided, :attr:`sys.argv` will be used. + :type argv: list of strings + :param quiet: Be quiet when bootstrapping the argument parser. + :type quiet: bool + :returns: :class:`Bcfg2.Options.OptionParser` + """ + global _PARSER # pylint: disable=W0603 + if _PARSER is None or args is not None or argv is not None: + if args is None: + args = CLI_COMMON_OPTIONS + _PARSER = OptionParser(args, argv=argv, quiet=quiet) + return _PARSER diff --git a/src/lib/Bcfg2/Server/Admin/Compare.py b/src/lib/Bcfg2/Server/Admin/Compare.py index c56dd0a8f..820271a2f 100644 --- a/src/lib/Bcfg2/Server/Admin/Compare.py +++ b/src/lib/Bcfg2/Server/Admin/Compare.py @@ -9,8 +9,8 @@ class Compare(Bcfg2.Server.Admin.Mode): __usage__ = (" \n\n" " -r\trecursive") - def __init__(self, setup): - Bcfg2.Server.Admin.Mode.__init__(self, setup) + def __init__(self): + Bcfg2.Server.Admin.Mode.__init__(self) self.important = {'Path': ['name', 'type', 'owner', 'group', 'mode', 'important', 'paranoid', 'sensitive', 'dev_type', 'major', 'minor', 'prune', diff --git a/src/lib/Bcfg2/Server/Admin/Init.py b/src/lib/Bcfg2/Server/Admin/Init.py index 14065980d..cf4bd4c0c 100644 --- a/src/lib/Bcfg2/Server/Admin/Init.py +++ b/src/lib/Bcfg2/Server/Admin/Init.py @@ -143,14 +143,9 @@ def create_conf(confpath, confdata): class Init(Bcfg2.Server.Admin.Mode): """Interactively initialize a new repository.""" - options = {'configfile': Bcfg2.Options.CFILE, - 'plugins': Bcfg2.Options.SERVER_PLUGINS, - 'proto': Bcfg2.Options.SERVER_PROTOCOL, - 'repo': Bcfg2.Options.SERVER_REPOSITORY, - 'sendmail': Bcfg2.Options.SENDMAIL_PATH} - - def __init__(self, setup): - Bcfg2.Server.Admin.Mode.__init__(self, setup) + + def __init__(self): + Bcfg2.Server.Admin.Mode.__init__(self) self.data = dict() self.plugins = Bcfg2.Options.SERVER_PLUGINS.default @@ -177,9 +172,16 @@ class Init(Bcfg2.Server.Admin.Mode): Bcfg2.Server.Admin.Mode.__call__(self, args) # Parse options - opts = Bcfg2.Options.OptionParser(self.options) - opts.parse(args) - self._set_defaults(opts) + setup = Bcfg2.Options.get_option_parser() + setup.add_options(dict(configfile=Bcfg2.Options.CFILE, + plugins=Bcfg2.Options.SERVER_PLUGINS, + proto=Bcfg2.Options.SERVER_PROTOCOL, + repo=Bcfg2.Options.SERVER_REPOSITORY, + sendmail=Bcfg2.Options.SENDMAIL_PATH)) + opts = sys.argv[1:] + opts.remove(self.__class__.__name__.lower()) + setup.reparse(argv=opts) + self._set_defaults(setup) # Prompt the user for input self._prompt_config() diff --git a/src/lib/Bcfg2/Server/Admin/Perf.py b/src/lib/Bcfg2/Server/Admin/Perf.py index 86eb6810d..7448855ce 100644 --- a/src/lib/Bcfg2/Server/Admin/Perf.py +++ b/src/lib/Bcfg2/Server/Admin/Perf.py @@ -11,17 +11,17 @@ class Perf(Bcfg2.Server.Admin.Mode): def __call__(self, args): output = [('Name', 'Min', 'Max', 'Mean', 'Count')] - optinfo = { - 'ca': Bcfg2.Options.CLIENT_CA, - 'certificate': Bcfg2.Options.CLIENT_CERT, - 'key': Bcfg2.Options.SERVER_KEY, - 'password': Bcfg2.Options.SERVER_PASSWORD, - 'server': Bcfg2.Options.SERVER_LOCATION, - 'user': Bcfg2.Options.CLIENT_USER, - 'timeout': Bcfg2.Options.CLIENT_TIMEOUT, - } - setup = Bcfg2.Options.OptionParser(optinfo) - setup.parse(sys.argv[1:]) + setup = Bcfg2.Options.get_option_parser() + setup.add_options(dict(ca=Bcfg2.Options.CLIENT_CA, + certificate=Bcfg2.Options.CLIENT_CERT, + key=Bcfg2.Options.SERVER_KEY, + password=Bcfg2.Options.SERVER_PASSWORD, + server=Bcfg2.Options.SERVER_LOCATION, + user=Bcfg2.Options.CLIENT_USER, + timeout=Bcfg2.Options.CLIENT_TIMEOUT)) + opts = sys.argv[1:] + opts.remove(self.__class__.__name__.lower()) + setup.reparse(argv=opts) proxy = Bcfg2.Proxy.ComponentProxy(setup['server'], setup['user'], setup['password'], diff --git a/src/lib/Bcfg2/Server/Admin/Pull.py b/src/lib/Bcfg2/Server/Admin/Pull.py index 130e85b67..1905fac3c 100644 --- a/src/lib/Bcfg2/Server/Admin/Pull.py +++ b/src/lib/Bcfg2/Server/Admin/Pull.py @@ -22,8 +22,8 @@ class Pull(Bcfg2.Server.Admin.MetadataCore): "-I", "interactive", "-s", "stdin")) - def __init__(self, setup): - Bcfg2.Server.Admin.MetadataCore.__init__(self, setup) + def __init__(self): + Bcfg2.Server.Admin.MetadataCore.__init__(self) self.log = False self.mode = 'interactive' diff --git a/src/lib/Bcfg2/Server/Admin/Reports.py b/src/lib/Bcfg2/Server/Admin/Reports.py index 6e313e84b..bb5ee352b 100644 --- a/src/lib/Bcfg2/Server/Admin/Reports.py +++ b/src/lib/Bcfg2/Server/Admin/Reports.py @@ -69,8 +69,8 @@ class Reports(Bcfg2.Server.Admin.Mode): " Django commands:\n " \ + "\n ".join(django_commands)) - def __init__(self, setup): - Bcfg2.Server.Admin.Mode.__init__(self, setup) + def __init__(self): + Bcfg2.Server.Admin.Mode.__init__(self) try: import south except ImportError: diff --git a/src/lib/Bcfg2/Server/Admin/Snapshots.py b/src/lib/Bcfg2/Server/Admin/Snapshots.py index c2d279391..bf44d1451 100644 --- a/src/lib/Bcfg2/Server/Admin/Snapshots.py +++ b/src/lib/Bcfg2/Server/Admin/Snapshots.py @@ -21,8 +21,8 @@ class Snapshots(Bcfg2.Server.Admin.Mode): 'package': Package, 'snapshot': Snapshot} - def __init__(self, setup): - Bcfg2.Server.Admin.Mode.__init__(self, setup) + def __init__(self): + Bcfg2.Server.Admin.Mode.__init__(self) self.session = Bcfg2.Server.Snapshots.setup_session(self.configfile) self.cfile = self.configfile diff --git a/src/lib/Bcfg2/Server/Admin/Syncdb.py b/src/lib/Bcfg2/Server/Admin/Syncdb.py index 4ba840b86..84ad93ae0 100644 --- a/src/lib/Bcfg2/Server/Admin/Syncdb.py +++ b/src/lib/Bcfg2/Server/Admin/Syncdb.py @@ -8,15 +8,17 @@ from django.core.management import setup_environ, call_command class Syncdb(Bcfg2.Server.Admin.Mode): """ Sync the Django ORM with the configured database """ - options = {'configfile': Bcfg2.Options.WEB_CFILE} def __call__(self, args): # Parse options - opts = Bcfg2.Options.OptionParser(self.options) - opts.parse(args) + setup = Bcfg2.Options.get_option_parser() + setup.add_option("web_configfile", Bcfg2.Options.WEB_CFILE) + opts = sys.argv[1:] + opts.remove(self.__class__.__name__.lower()) + setup.reparse(argv=opts) setup_environ(Bcfg2.settings) - Bcfg2.Server.models.load_models(cfile=opts['configfile']) + Bcfg2.Server.models.load_models(cfile=setup['web_configfile']) try: call_command("syncdb", interactive=False, verbosity=0) diff --git a/src/lib/Bcfg2/Server/Admin/Xcmd.py b/src/lib/Bcfg2/Server/Admin/Xcmd.py index 79eeebc7c..7f9f32816 100644 --- a/src/lib/Bcfg2/Server/Admin/Xcmd.py +++ b/src/lib/Bcfg2/Server/Admin/Xcmd.py @@ -12,17 +12,17 @@ class Xcmd(Bcfg2.Server.Admin.Mode): __usage__ = "" def __call__(self, args): - optinfo = { - 'server': Bcfg2.Options.SERVER_LOCATION, - 'user': Bcfg2.Options.CLIENT_USER, - 'password': Bcfg2.Options.SERVER_PASSWORD, - 'key': Bcfg2.Options.SERVER_KEY, - 'certificate': Bcfg2.Options.CLIENT_CERT, - 'ca': Bcfg2.Options.CLIENT_CA, - 'timeout': Bcfg2.Options.CLIENT_TIMEOUT, - } - setup = Bcfg2.Options.OptionParser(optinfo) - setup.parse(args) + setup = Bcfg2.Options.get_option_parser() + setup.add_options(dict(ca=Bcfg2.Options.CLIENT_CA, + certificate=Bcfg2.Options.CLIENT_CERT, + key=Bcfg2.Options.SERVER_KEY, + password=Bcfg2.Options.SERVER_PASSWORD, + server=Bcfg2.Options.SERVER_LOCATION, + user=Bcfg2.Options.CLIENT_USER, + timeout=Bcfg2.Options.CLIENT_TIMEOUT)) + opts = sys.argv[1:] + opts.remove(self.__class__.__name__.lower()) + setup.reparse(argv=opts) Bcfg2.Proxy.RetryMethod.max_retries = 1 proxy = Bcfg2.Proxy.ComponentProxy(setup['server'], setup['user'], @@ -34,12 +34,9 @@ class Xcmd(Bcfg2.Server.Admin.Mode): if len(setup['args']) == 0: print("Usage: xcmd ") return - cmd = setup['args'][0] - args = () - if len(setup['args']) > 1: - args = tuple(setup['args'][1:]) + cmd = args[0] try: - data = getattr(proxy, cmd)(*args) + data = getattr(proxy, cmd)(*setup['args']) except xmlrpclib.Fault: flt = sys.exc_info()[1] if flt.faultCode == 7: diff --git a/src/lib/Bcfg2/Server/Admin/__init__.py b/src/lib/Bcfg2/Server/Admin/__init__.py index 19175533f..20577633a 100644 --- a/src/lib/Bcfg2/Server/Admin/__init__.py +++ b/src/lib/Bcfg2/Server/Admin/__init__.py @@ -35,15 +35,15 @@ class Mode(object): __usage__ = None __args__ = [] - def __init__(self, setup): - self.setup = setup - self.configfile = setup['configfile'] + def __init__(self): + self.setup = Bcfg2.Options.get_option_parser() + self.configfile = self.setup['configfile'] self.__cfp = False self.log = logging.getLogger('Bcfg2.Server.Admin.Mode') usage = "bcfg2-admin %s" % self.__class__.__name__.lower() if self.__usage__ is not None: usage += " " + self.__usage__ - setup.hm = usage + self.setup.hm = usage def getCFP(self): """ get a config parser for the Bcfg2 config file """ @@ -129,19 +129,19 @@ class MetadataCore(Mode): __plugin_whitelist__ = None __plugin_blacklist__ = None - def __init__(self, setup): - Mode.__init__(self, setup) + def __init__(self): + Mode.__init__(self) if self.__plugin_whitelist__ is not None: - setup['plugins'] = [p for p in setup['plugins'] + self.setup['plugins'] = [p for p in self.setup['plugins'] if p in self.__plugin_whitelist__] elif self.__plugin_blacklist__ is not None: - setup['plugins'] = [p for p in setup['plugins'] + self.setup['plugins'] = [p for p in self.setup['plugins'] if p not in self.__plugin_blacklist__] # admin modes don't need to watch for changes. one shot is fine here. - setup['filemonitor'] = 'pseudo' + self.setup['filemonitor'] = 'pseudo' try: - self.bcore = Bcfg2.Server.Core.BaseCore(setup) + self.bcore = Bcfg2.Server.Core.BaseCore() except Bcfg2.Server.Core.CoreInitError: msg = sys.exc_info()[1] self.errExit("Core load failed: %s" % msg) diff --git a/src/lib/Bcfg2/Server/BuiltinCore.py b/src/lib/Bcfg2/Server/BuiltinCore.py index 4d7453840..14b64ff40 100644 --- a/src/lib/Bcfg2/Server/BuiltinCore.py +++ b/src/lib/Bcfg2/Server/BuiltinCore.py @@ -22,8 +22,8 @@ class Core(BaseCore): """ The built-in server core """ name = 'bcfg2-server' - def __init__(self, setup): - BaseCore.__init__(self, setup) + def __init__(self): + BaseCore.__init__(self) #: The :class:`Bcfg2.SSLServer.XMLRPCServer` instance powering #: this server core diff --git a/src/lib/Bcfg2/Server/CherryPyCore.py b/src/lib/Bcfg2/Server/CherryPyCore.py index d097fd08f..79768df20 100644 --- a/src/lib/Bcfg2/Server/CherryPyCore.py +++ b/src/lib/Bcfg2/Server/CherryPyCore.py @@ -36,8 +36,8 @@ class Core(BaseCore): _cp_config = {'tools.xmlrpc_error.on': True, 'tools.bcfg2_authn.on': True} - def __init__(self, setup): - BaseCore.__init__(self, setup) + def __init__(self): + BaseCore.__init__(self) cherrypy.tools.bcfg2_authn = cherrypy.Tool('on_start_resource', self.do_authn) diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index 37da4a4b6..0ef20dfac 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -2,21 +2,22 @@ implementations inherit from. """ import os -import atexit -import logging -import select import sys -import threading import time +import select +import atexit +import logging import inspect +import threading import lxml.etree -import Bcfg2.settings import Bcfg2.Server import Bcfg2.Logger -import Bcfg2.Server.FileMonitor -from Bcfg2.Cache import Cache +import Bcfg2.settings import Bcfg2.Statistics +import Bcfg2.Server.FileMonitor from itertools import chain +from Bcfg2.Cache import Cache +from Bcfg2.Options import get_option_parser from Bcfg2.Compat import xmlrpclib # pylint: disable=W0622 from Bcfg2.Server.Plugin import PluginInitError, PluginExecutionError, \ track_statistics @@ -85,23 +86,23 @@ class BaseCore(object): and modules. All core implementations must inherit from ``BaseCore``. """ - def __init__(self, setup): # pylint: disable=R0912,R0915 + def __init__(self): # pylint: disable=R0912,R0915 """ - :param setup: A Bcfg2 options dict - :type setup: Bcfg2.Options.OptionParser - .. automethod:: _daemonize .. automethod:: _run .. automethod:: _block .. ----- .. automethod:: _file_monitor_thread """ + #: The Bcfg2 options dict + self.setup = get_option_parser() + #: The Bcfg2 repository directory - self.datastore = setup['repo'] + self.datastore = self.setup['repo'] - if setup['debug']: + if self.setup['debug']: level = logging.DEBUG - elif setup['verbose']: + elif self.setup['verbose']: level = logging.INFO else: level = logging.WARNING @@ -112,8 +113,8 @@ class BaseCore(object): # setup_logging and the console will get DEBUG output. Bcfg2.Logger.setup_logging('bcfg2-server', to_console=logging.INFO, - to_syslog=setup['syslog'], - to_file=setup['logging'], + to_syslog=self.setup['syslog'], + to_file=self.setup['logging'], level=level) #: A :class:`logging.Logger` object for use by the core @@ -121,16 +122,16 @@ class BaseCore(object): try: filemonitor = \ - Bcfg2.Server.FileMonitor.available[setup['filemonitor']] + Bcfg2.Server.FileMonitor.available[self.setup['filemonitor']] except KeyError: self.logger.error("File monitor driver %s not available; " - "forcing to default" % setup['filemonitor']) + "forcing to default" % self.setup['filemonitor']) filemonitor = Bcfg2.Server.FileMonitor.available['default'] famargs = dict(ignore=[], debug=False) - if 'ignore' in setup: - famargs['ignore'] = setup['ignore'] - if 'debug' in setup: - famargs['debug'] = setup['debug'] + if 'ignore' in self.setup: + famargs['ignore'] = self.setup['ignore'] + if 'debug' in self.setup: + famargs['debug'] = self.setup['debug'] try: #: The :class:`Bcfg2.Server.FileMonitor.FileMonitor` @@ -138,12 +139,13 @@ class BaseCore(object): #: changes. self.fam = filemonitor(**famargs) except IOError: - msg = "Failed to instantiate fam driver %s" % setup['filemonitor'] + msg = "Failed to instantiate fam driver %s" % \ + self.setup['filemonitor'] self.logger.error(msg, exc_info=1) raise CoreInitError(msg) #: Path to bcfg2.conf - self.cfile = setup['configfile'] + self.cfile = self.setup['configfile'] #: Dict of plugins that are enabled. Keys are the plugin #: names (just the plugin name, in the correct case; e.g., @@ -161,9 +163,6 @@ class BaseCore(object): #: :class:`Bcfg2.Server.Plugin.interfaces.Version` plugin. self.revision = '-1' - #: The Bcfg2 options dict - self.setup = setup - atexit.register(self.shutdown) #: Threading event to signal worker threads (e.g., @@ -217,10 +216,10 @@ class BaseCore(object): self.logger.error("Failed to set ownership of database " "at %s: %s" % (db_settings['NAME'], err)) - if '' in setup['plugins']: - setup['plugins'].remove('') + if '' in self.setup['plugins']: + self.setup['plugins'].remove('') - for plugin in setup['plugins']: + for plugin in self.setup['plugins']: if not plugin in self.plugins: self.init_plugin(plugin) # Remove blacklisted plugins @@ -283,12 +282,12 @@ class BaseCore(object): self.connectors = self.plugins_by_type(Bcfg2.Server.Plugin.Connector) #: The CA that signed the server cert - self.ca = setup['ca'] + self.ca = self.setup['ca'] #: The FAM :class:`threading.Thread`, #: :func:`_file_monitor_thread` self.fam_thread = \ - threading.Thread(name="%sFAMThread" % setup['filemonitor'], + threading.Thread(name="%sFAMThread" % self.setup['filemonitor'], target=self._file_monitor_thread) #: A :func:`threading.Lock` for use by @@ -393,8 +392,10 @@ class BaseCore(object): """ Get the client :attr:`metadata_cache` mode. Options are off, initial, cautious, aggressive, on (synonym for cautious). See :ref:`server-caching` for more details. """ + # pylint: disable=E1103 mode = self.setup.cfp.get("caching", "client_metadata", default="off").lower() + # pylint: enable=E1103 if mode == "on": return "cautious" else: diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index acf6af1f8..7b22d52ca 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -23,18 +23,6 @@ try: except ImportError: HAS_DJANGO = False -#: A dict containing default metadata for Path entries from bcfg2.conf -DEFAULT_FILE_METADATA = Bcfg2.Options.OptionParser(dict( - owner=Bcfg2.Options.MDATA_OWNER, - group=Bcfg2.Options.MDATA_GROUP, - mode=Bcfg2.Options.MDATA_MODE, - secontext=Bcfg2.Options.MDATA_SECONTEXT, - important=Bcfg2.Options.MDATA_IMPORTANT, - paranoid=Bcfg2.Options.MDATA_PARANOID, - sensitive=Bcfg2.Options.MDATA_SENSITIVE)) -DEFAULT_FILE_METADATA.parse(sys.argv[1:]) -del DEFAULT_FILE_METADATA['args'] - LOGGER = logging.getLogger(__name__) #: a compiled regular expression for parsing info and :info files @@ -49,7 +37,20 @@ INFO_REGEX = re.compile('owner:(\s)*(?P\S+)|' + 'mtime:(\s)*(?P\w+)|') -def bind_info(entry, metadata, infoxml=None, default=DEFAULT_FILE_METADATA): +def default_path_metadata(): + """ Get the default Path entry metadata from the config. + + :returns: dict of metadata attributes and their default values + """ + attrs = Bcfg2.Options.PATH_METADATA_OPTIONS.keys() + setup = Bcfg2.Options.get_option_parser() + if not set(attrs).issubset(setup.keys()): + setup.add_options(Bcfg2.Options.PATH_METADATA_OPTIONS) + setup.reparse() + return dict([(k, setup[k]) for k in attrs]) + + +def bind_info(entry, metadata, infoxml=None, default=None): """ Bind the file metadata in the given :class:`Bcfg2.Server.Plugin.helpers.InfoXML` object to the given entry. @@ -66,6 +67,8 @@ def bind_info(entry, metadata, infoxml=None, default=DEFAULT_FILE_METADATA): :returns: None :raises: :class:`Bcfg2.Server.Plugin.exceptions.PluginExecutionError` """ + if default is None: + default = default_path_metadata() for attr, val in list(default.items()): entry.set(attr, val) if infoxml: @@ -1154,7 +1157,7 @@ class EntrySet(Debuggable): self.path = path self.entry_type = entry_type self.entries = {} - self.metadata = DEFAULT_FILE_METADATA.copy() + self.metadata = default_path_metadata() self.infoxml = None self.encoding = encoding @@ -1376,7 +1379,7 @@ class EntrySet(Debuggable): if event.filename == 'info.xml': self.infoxml = None elif event.filename in [':info', 'info']: - self.metadata = DEFAULT_FILE_METADATA.copy() + self.metadata = default_path_metadata() def bind_info_to_entry(self, entry, metadata): """ Shortcut to call :func:`bind_info` with the base diff --git a/src/lib/Bcfg2/Server/Plugins/Bundler.py b/src/lib/Bcfg2/Server/Plugins/Bundler.py index b200346bc..6dc3c2b1d 100644 --- a/src/lib/Bcfg2/Server/Plugins/Bundler.py +++ b/src/lib/Bcfg2/Server/Plugins/Bundler.py @@ -1,15 +1,15 @@ """This provides bundle clauses with translation functionality.""" -import copy -import logging -import lxml.etree import os -import os.path import re import sys +import copy +import logging +import lxml.etree import Bcfg2.Server import Bcfg2.Server.Plugin import Bcfg2.Server.Lint +from Bcfg2.Options import get_option_parser try: import genshi.template.base @@ -19,9 +19,6 @@ except ImportError: HAS_GENSHI = False -SETUP = None - - class BundleFile(Bcfg2.Server.Plugin.StructFile): """ Representation of a bundle XML file """ def get_xml_value(self, metadata): @@ -52,8 +49,9 @@ if HAS_GENSHI: msg = "No parsed template information for %s" % self.name self.logger.error(msg) raise Bcfg2.Server.Plugin.PluginExecutionError(msg) - stream = self.template.generate(metadata=metadata, - repo=SETUP['repo']).filter( + stream = self.template.generate( + metadata=metadata, + repo=get_option_parser()['repo']).filter( Bcfg2.Server.Plugins.TGenshi.removecomment) data = lxml.etree.XML(stream.render('xml', strip_whitespace=False), @@ -102,9 +100,6 @@ class Bundler(Bcfg2.Server.Plugin.Plugin, self.logger.error(msg) raise Bcfg2.Server.Plugin.PluginInitError(msg) - global SETUP - SETUP = core.setup - def template_dispatch(self, name, _): """ Add the correct child entry type to Bundler depending on whether the XML file in question is a plain XML file or a diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgAuthorizedKeysGenerator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgAuthorizedKeysGenerator.py index 824d01023..11c60ad2c 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgAuthorizedKeysGenerator.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgAuthorizedKeysGenerator.py @@ -4,7 +4,7 @@ access. """ import lxml.etree from Bcfg2.Server.Plugin import StructFile, PluginExecutionError -from Bcfg2.Server.Plugins.Cfg import CfgGenerator, SETUP, CFG +from Bcfg2.Server.Plugins.Cfg import CfgGenerator, CFG from Bcfg2.Server.Plugins.Metadata import ClientMetadata @@ -35,9 +35,9 @@ class CfgAuthorizedKeysGenerator(CfgGenerator, StructFile): def category(self): """ The name of the metadata category that generated keys are specific to """ - if (SETUP.cfp.has_section("sshkeys") and - SETUP.cfp.has_option("sshkeys", "category")): - return SETUP.cfp.get("sshkeys", "category") + if (self.setup.cfp.has_section("sshkeys") and + self.setup.cfp.has_option("sshkeys", "category")): + return self.setup.cfp.get("sshkeys", "category") return None def handle_event(self, event): diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgCheetahGenerator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgCheetahGenerator.py index 724164cf5..4c8adceec 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgCheetahGenerator.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgCheetahGenerator.py @@ -3,7 +3,7 @@ :ref:`server-plugins-generators-cfg` files. """ from Bcfg2.Server.Plugin import PluginExecutionError -from Bcfg2.Server.Plugins.Cfg import CfgGenerator, SETUP +from Bcfg2.Server.Plugins.Cfg import CfgGenerator try: from Cheetah.Template import Template @@ -40,6 +40,6 @@ class CfgCheetahGenerator(CfgGenerator): template.name = entry.get('realname', entry.get('name')) template.path = entry.get('realname', entry.get('name')) template.source_path = self.name - template.repo = SETUP['repo'] + template.repo = self.setup['repo'] return template.respond() get_data.__doc__ = CfgGenerator.get_data.__doc__ diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenerator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenerator.py index 3b4703ddb..3b3b95ff5 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenerator.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenerator.py @@ -2,10 +2,9 @@ :ref:`server-plugins-generators-cfg` files on the server. """ from Bcfg2.Server.Plugin import PluginExecutionError -from Bcfg2.Server.Plugins.Cfg import CfgGenerator, SETUP +from Bcfg2.Server.Plugins.Cfg import CfgGenerator try: - from Bcfg2.Encryption import bruteforce_decrypt, EVPError, \ - get_algorithm + from Bcfg2.Encryption import bruteforce_decrypt, EVPError HAS_CRYPTO = True except ImportError: HAS_CRYPTO = False @@ -34,8 +33,7 @@ class CfgEncryptedGenerator(CfgGenerator): return # todo: let the user specify a passphrase by name try: - self.data = bruteforce_decrypt(self.data, setup=SETUP, - algorithm=get_algorithm(SETUP)) + self.data = bruteforce_decrypt(self.data) except EVPError: raise PluginExecutionError("Failed to decrypt %s" % self.name) handle_event.__doc__ = CfgGenerator.handle_event.__doc__ diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenshiGenerator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenshiGenerator.py index 130652aef..215e4c1f1 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenshiGenerator.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenshiGenerator.py @@ -3,11 +3,10 @@ files) """ from Bcfg2.Compat import StringIO from Bcfg2.Server.Plugin import PluginExecutionError -from Bcfg2.Server.Plugins.Cfg import SETUP from Bcfg2.Server.Plugins.Cfg.CfgGenshiGenerator import CfgGenshiGenerator try: - from Bcfg2.Encryption import bruteforce_decrypt, get_algorithm + from Bcfg2.Encryption import bruteforce_decrypt HAS_CRYPTO = True except ImportError: HAS_CRYPTO = False @@ -24,9 +23,7 @@ class EncryptedTemplateLoader(TemplateLoader): the data on the fly as it's read in using :func:`Bcfg2.Encryption.bruteforce_decrypt` """ def _instantiate(self, cls, fileobj, filepath, filename, encoding=None): - plaintext = \ - StringIO(bruteforce_decrypt(fileobj.read(), - algorithm=get_algorithm(SETUP))) + plaintext = StringIO(bruteforce_decrypt(fileobj.read())) return TemplateLoader._instantiate(self, cls, plaintext, filepath, filename, encoding=encoding) diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py index 73550cd9d..b58349fe0 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py @@ -6,7 +6,7 @@ import re import sys import traceback from Bcfg2.Server.Plugin import PluginExecutionError -from Bcfg2.Server.Plugins.Cfg import CfgGenerator, SETUP +from Bcfg2.Server.Plugins.Cfg import CfgGenerator try: import genshi.core @@ -102,12 +102,12 @@ class CfgGenshiGenerator(CfgGenerator): def get_data(self, entry, metadata): fname = entry.get('realname', entry.get('name')) - stream = \ - self.template.generate(name=fname, - metadata=metadata, - path=self.name, - source_path=self.name, - repo=SETUP['repo']).filter(removecomment) + stream = self.template.generate( + name=fname, + metadata=metadata, + path=self.name, + source_path=self.name, + repo=self.setup['repo']).filter(removecomment) try: try: return stream.render('text', encoding=self.encoding, diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgPrivateKeyCreator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgPrivateKeyCreator.py index aaeb65cd6..54fa75b41 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgPrivateKeyCreator.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgPrivateKeyCreator.py @@ -4,8 +4,9 @@ import os import shutil import tempfile import subprocess +from Bcfg2.Options import get_option_parser from Bcfg2.Server.Plugin import PluginExecutionError, StructFile -from Bcfg2.Server.Plugins.Cfg import CfgCreator, CfgCreationError, SETUP +from Bcfg2.Server.Plugins.Cfg import CfgCreator, CfgCreationError from Bcfg2.Server.Plugins.Cfg.CfgPublicKeyCreator import CfgPublicKeyCreator try: import Bcfg2.Encryption @@ -31,24 +32,25 @@ 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) + self.setup = get_option_parser() __init__.__doc__ = CfgCreator.__init__.__doc__ @property def category(self): """ The name of the metadata category that generated keys are specific to """ - if (SETUP.cfp.has_section("sshkeys") and - SETUP.cfp.has_option("sshkeys", "category")): - return SETUP.cfp.get("sshkeys", "category") + if (self.setup.cfp.has_section("sshkeys") and + self.setup.cfp.has_option("sshkeys", "category")): + return self.setup.cfp.get("sshkeys", "category") return None @property def passphrase(self): """ The passphrase used to encrypt private keys """ if (HAS_CRYPTO and - SETUP.cfp.has_section("sshkeys") and - SETUP.cfp.has_option("sshkeys", "passphrase")): - return Bcfg2.Encryption.get_passphrases(SETUP)[SETUP.cfp.get( + self.setup.cfp.has_section("sshkeys") and + self.setup.cfp.has_option("sshkeys", "passphrase")): + return Bcfg2.Encryption.get_passphrases()[self.setup.cfp.get( "sshkeys", "passphrase")] return None @@ -196,10 +198,8 @@ class CfgPrivateKeyCreator(CfgCreator, StructFile): privkey = open(filename).read() if HAS_CRYPTO and self.passphrase: self.debug_log("Cfg: Encrypting key data at %s" % filename) - privkey = Bcfg2.Encryption.ssl_encrypt( - privkey, - self.passphrase, - algorithm=Bcfg2.Encryption.get_algorithm(SETUP)) + privkey = Bcfg2.Encryption.ssl_encrypt(privkey, + self.passphrase) specificity['ext'] = '.crypt' self.write_data(privkey, **specificity) @@ -239,22 +239,16 @@ class CfgPrivateKeyCreator(CfgCreator, StructFile): """ Decrypt a single encrypted element """ if not element.text or not element.text.strip(): return - passes = Bcfg2.Encryption.get_passphrases(SETUP) + passes = Bcfg2.Encryption.get_passphrases() try: passphrase = passes[element.get("encrypted")] try: - return Bcfg2.Encryption.ssl_decrypt( - element.text, - passphrase, - algorithm=Bcfg2.Encryption.get_algorithm(SETUP)) + return Bcfg2.Encryption.ssl_decrypt(element.text, passphrase) 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(), - algorithm=Bcfg2.Encryption.get_algorithm(SETUP)) + return Bcfg2.Encryption.bruteforce_decrypt(element.text) raise Bcfg2.Encryption.EVPError("Failed to decrypt") diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py b/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py index fcfaa393b..53cc90094 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py @@ -16,17 +16,6 @@ from Bcfg2.Compat import u_str, unicode, b64encode, walk_packages, \ any, oct_mode # pylint: enable=W0622 -#: SETUP contains a reference to the -#: :class:`Bcfg2.Options.OptionParser` created by the Bcfg2 core for -#: parsing command-line and config file options. -#: :class:`Bcfg2.Server.Plugins.Cfg.Cfg` stores it in a module global -#: so that the handler objects can access it, because there is no other -#: facility for passing a setup object from a -#: :class:`Bcfg2.Server.Plugin.helpers.GroupSpool` to its -#: :class:`Bcfg2.Server.Plugin.helpers.EntrySet` objects and thence to -#: the EntrySet children. -SETUP = None - #: CFG is a reference to the :class:`Bcfg2.Server.Plugins.Cfg.Cfg` #: plugin object created by the Bcfg2 core. This is provided so that #: the handler objects can access it as necessary, since the existing @@ -86,6 +75,7 @@ class CfgBaseFileMatcher(Bcfg2.Server.Plugin.SpecificData, encoding) Bcfg2.Server.Plugin.Debuggable.__init__(self) self.encoding = encoding + self.setup = Bcfg2.Options.get_option_parser() __init__.__doc__ = Bcfg2.Server.Plugin.SpecificData.__init__.__doc__ + \ """ .. ----- @@ -442,11 +432,11 @@ class CfgDefaultInfo(CfgInfo): bind_info_to_entry.__doc__ = CfgInfo.bind_info_to_entry.__doc__ #: A :class:`CfgDefaultInfo` object instantiated with -#: :attr:`Bcfg2.Server.Plugin.helper.DEFAULT_FILE_METADATA` as its +#: :func:`Bcfg2.Server.Plugin.helper.default_path_metadata` as its #: default metadata. This is used to set a default file metadata set #: on an entry before a "real" :class:`CfgInfo` handler applies its #: metadata to the entry. -DEFAULT_INFO = CfgDefaultInfo(Bcfg2.Server.Plugin.DEFAULT_FILE_METADATA) +DEFAULT_INFO = CfgDefaultInfo(Bcfg2.Server.Plugin.default_path_metadata()) class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet, @@ -460,6 +450,7 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet, Bcfg2.Server.Plugin.Debuggable.__init__(self) self.specific = None self._handlers = None + self.setup = Bcfg2.Options.get_option_parser() __init__.__doc__ = Bcfg2.Server.Plugin.EntrySet.__doc__ def set_debug(self, debug): @@ -585,7 +576,7 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet, for fltr in self.get_handlers(metadata, CfgFilter): data = fltr.modify_data(entry, metadata, data) - if SETUP['validate']: + if self.setup['validate']: try: self._validate_data(entry, metadata, data) except CfgVerificationError: @@ -833,16 +824,16 @@ class Cfg(Bcfg2.Server.Plugin.GroupSpool, es_child_cls = Bcfg2.Server.Plugin.SpecificData def __init__(self, core, datastore): - global SETUP, CFG # pylint: disable=W0603 + global CFG # pylint: disable=W0603 Bcfg2.Server.Plugin.GroupSpool.__init__(self, core, datastore) Bcfg2.Server.Plugin.PullTarget.__init__(self) CFG = self - SETUP = core.setup - if 'validate' not in SETUP: - SETUP.add_option('validate', Bcfg2.Options.CFG_VALIDATION) - SETUP.reparse() + setup = Bcfg2.Options.get_option_parser() + if 'validate' not in setup: + setup.add_option('validate', Bcfg2.Options.CFG_VALIDATION) + setup.reparse() __init__.__doc__ = Bcfg2.Server.Plugin.GroupSpool.__init__.__doc__ def has_generator(self, entry, metadata): diff --git a/src/lib/Bcfg2/Server/Plugins/Properties.py b/src/lib/Bcfg2/Server/Plugins/Properties.py index a51dd8adc..c5b5ea2d1 100644 --- a/src/lib/Bcfg2/Server/Plugins/Properties.py +++ b/src/lib/Bcfg2/Server/Plugins/Properties.py @@ -7,6 +7,7 @@ import sys import copy import logging import lxml.etree +from Bcfg2.Options import get_option_parser import Bcfg2.Server.Plugin from Bcfg2.Server.Plugin import PluginExecutionError try: @@ -33,8 +34,6 @@ except ImportError: LOGGER = logging.getLogger(__name__) -SETUP = None - class PropertyFile(object): """ Base Properties file handler """ @@ -46,13 +45,14 @@ class PropertyFile(object): .. automethod:: _write """ self.name = name + self.setup = get_option_parser() def write(self): """ Write the data in this data structure back to the property file. This public method performs checking to ensure that writing is possible and then calls :func:`_write`. """ - if not SETUP.cfp.getboolean("properties", "writes_enabled", - default=True): + if not self.setup.cfp.getboolean("properties", "writes_enabled", + default=True): msg = "Properties files write-back is disabled in the " + \ "configuration" LOGGER.error(msg) @@ -232,26 +232,22 @@ class XMLPropertyFile(Bcfg2.Server.Plugin.StructFile, PropertyFile): """ Decrypt a single encrypted properties file element """ if not element.text or not element.text.strip(): return - passes = Bcfg2.Encryption.get_passphrases(SETUP) + passes = Bcfg2.Encryption.get_passphrases() try: passphrase = passes[element.get("encrypted")] try: - return Bcfg2.Encryption.ssl_decrypt( - element.text, passphrase, - algorithm=Bcfg2.Encryption.get_algorithm(SETUP)) + return Bcfg2.Encryption.ssl_decrypt(element.text, passphrase) 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(), - algorithm=Bcfg2.Encryption.get_algorithm(SETUP)) + return Bcfg2.Encryption.bruteforce_decrypt(element.text) raise Bcfg2.Encryption.EVPError("Failed to decrypt") def get_additional_data(self, metadata): - if SETUP.cfp.getboolean("properties", "automatch", default=False): + if self.setup.cfp.getboolean("properties", "automatch", default=False): default_automatch = "true" else: default_automatch = "false" @@ -323,10 +319,8 @@ class Properties(Bcfg2.Server.Plugin.Plugin, instances. """ def __init__(self, core, datastore): - global SETUP # pylint: disable=W0603 Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore) Bcfg2.Server.Plugin.Connector.__init__(self) - SETUP = core.setup try: self.store = PropDirectoryBacked(self.data, core.fam) except OSError: diff --git a/src/lib/Bcfg2/Server/models.py b/src/lib/Bcfg2/Server/models.py index 0328c6bea..4ac2be43b 100644 --- a/src/lib/Bcfg2/Server/models.py +++ b/src/lib/Bcfg2/Server/models.py @@ -1,6 +1,7 @@ """ Django database models for all plugins """ import sys +import copy import logging import Bcfg2.Options import Bcfg2.Server.Plugins @@ -19,14 +20,12 @@ def load_models(plugins=None, cfile='/etc/bcfg2.conf', quiet=True): # we want to provide a different default plugin list -- # namely, _all_ plugins, so that the database is guaranteed to # work, even if /etc/bcfg2.conf isn't set up properly - plugin_opt = Bcfg2.Options.SERVER_PLUGINS + plugin_opt = copy.deepcopy(Bcfg2.Options.SERVER_PLUGINS) plugin_opt.default = Bcfg2.Server.Plugins.__all__ - - setup = \ - Bcfg2.Options.OptionParser(dict(plugins=plugin_opt, - configfile=Bcfg2.Options.CFILE), - quiet=quiet) - setup.parse([Bcfg2.Options.CFILE.cmd, cfile]) + setup = Bcfg2.Options.get_option_parser() + setup.add_option("plugins", plugin_opt) + setup.add_option("configfile", Bcfg2.Options.CFILE) + setup.reparse(argv=[Bcfg2.Options.CFILE.cmd, cfile]) plugins = setup['plugins'] if MODELS: diff --git a/src/lib/Bcfg2/settings.py b/src/lib/Bcfg2/settings.py index 190bdff58..da6e2036e 100644 --- a/src/lib/Bcfg2/settings.py +++ b/src/lib/Bcfg2/settings.py @@ -39,20 +39,20 @@ def _default_config(): """ get the default config file. returns /etc/bcfg2-web.conf, UNLESS /etc/bcfg2.conf exists AND /etc/bcfg2-web.conf does not exist. """ - optinfo = dict(cfile=Bcfg2.Options.CFILE, - web_cfile=Bcfg2.Options.WEB_CFILE) - setup = Bcfg2.Options.OptionParser(optinfo, quiet=True) - setup.parse(sys.argv[1:], do_getopt=False) - if (not os.path.exists(setup['web_cfile']) and - os.path.exists(setup['cfile'])): - return setup['cfile'] + setup = Bcfg2.Options.get_option_parser() + setup.add_option("configfile", Bcfg2.Options.CFILE) + setup.add_option("web_configfile", Bcfg2.Options.WEB_CFILE) + setup.reparse(argv=sys.argv[1:], do_getopt=False) + if (not os.path.exists(setup['web_configfile']) and + os.path.exists(setup['configfile'])): + return setup['configfile'] else: - return setup['web_cfile'] + return setup['web_configfile'] DEFAULT_CONFIG = _default_config() -def read_config(cfile=DEFAULT_CONFIG, repo=None, quiet=False): +def read_config(cfile=DEFAULT_CONFIG, repo=None): """ read the config file and set django settings based on it """ # pylint: disable=W0603 global DATABASE_ENGINE, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD, \ @@ -65,15 +65,15 @@ def read_config(cfile=DEFAULT_CONFIG, repo=None, quiet=False): (cfile, DEFAULT_CONFIG)) cfile = DEFAULT_CONFIG - optinfo = Bcfg2.Options.DATABASE_COMMON_OPTIONS - optinfo['repo'] = Bcfg2.Options.SERVER_REPOSITORY # when setting a different config file, it has to be set in either # sys.argv or in the OptionSet() constructor AS WELL AS the argv # that's passed to setup.parse() argv = [Bcfg2.Options.CFILE.cmd, cfile, Bcfg2.Options.WEB_CFILE.cmd, cfile] - setup = Bcfg2.Options.OptionParser(optinfo, argv=argv, quiet=quiet) - setup.parse(argv) + setup = Bcfg2.Options.get_option_parser() + setup.add_options(Bcfg2.Options.DATABASE_COMMON_OPTIONS) + setup.add_option("repo", Bcfg2.Options.SERVER_REPOSITORY) + setup.reparse(argv=argv) if repo is None: repo = setup['repo'] @@ -110,7 +110,7 @@ def read_config(cfile=DEFAULT_CONFIG, repo=None, quiet=False): # initialize settings from /etc/bcfg2-web.conf or /etc/bcfg2.conf, or # set up basic defaults. this lets manage.py work in all cases -read_config(quiet=True) +read_config() ADMINS = (('Root', 'root')) MANAGERS = ADMINS diff --git a/src/sbin/bcfg2 b/src/sbin/bcfg2 index 444e86a7c..e9beb47cd 100755 --- a/src/sbin/bcfg2 +++ b/src/sbin/bcfg2 @@ -3,8 +3,8 @@ import sys import signal -import Bcfg2.Options from Bcfg2.Client.Client import Client +from Bcfg2.Options import get_option_parser, CLIENT_COMMON_OPTIONS def cb_sigint_handler(signum, frame): @@ -13,8 +13,7 @@ def cb_sigint_handler(signum, frame): def main(): - optinfo = Bcfg2.Options.CLIENT_COMMON_OPTIONS - setup = Bcfg2.Options.OptionParser(optinfo) + setup = get_option_parser(CLIENT_COMMON_OPTIONS) setup.parse(sys.argv[1:]) if setup['args']: @@ -23,7 +22,7 @@ def main(): raise SystemExit(1) signal.signal(signal.SIGINT, cb_sigint_handler) - return Client(setup).run() + return Client().run() if __name__ == '__main__': sys.exit(main()) diff --git a/src/sbin/bcfg2-admin b/src/sbin/bcfg2-admin index fa4307702..8f6643ee0 100755 --- a/src/sbin/bcfg2-admin +++ b/src/sbin/bcfg2-admin @@ -41,7 +41,7 @@ def main(): optinfo = dict() optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS) optinfo.update(Bcfg2.Options.SERVER_COMMON_OPTIONS) - setup = Bcfg2.Options.OptionParser(optinfo) + setup = Bcfg2.Options.get_option_parser(optinfo) # override default help message to include description of all modes setup.hm = "Usage:\n\n%s\n%s" % (setup.buildHelpMessage(), create_description()) @@ -80,7 +80,7 @@ def main(): err = sys.exc_info()[1] log.error("Failed to load admin mode %s: %s" % (modname, err)) raise SystemExit(1) - mode = mode_cls(setup) + mode = mode_cls() try: mode(setup['args'][1:]) finally: diff --git a/src/sbin/bcfg2-crypt b/src/sbin/bcfg2-crypt index fde6af582..6a13b9bc5 100755 --- a/src/sbin/bcfg2-crypt +++ b/src/sbin/bcfg2-crypt @@ -27,8 +27,8 @@ class EncryptionChunkingError(Exception): class Encryptor(object): """ Generic encryptor for all files """ - def __init__(self, setup): - self.setup = setup + def __init__(self): + self.setup = Bcfg2.Options.get_option_parser() self.passphrase = None self.pname = None self.logger = logging.getLogger(self.__class__.__name__) @@ -56,7 +56,7 @@ class Encryptor(object): def set_passphrase(self): """ set the passphrase for the current file """ if (not self.setup.cfp.has_section(Bcfg2.Encryption.CFG_SECTION) or - len(Bcfg2.Encryption.get_passphrases(self.setup)) == 0): + len(Bcfg2.Encryption.get_passphrases()) == 0): self.logger.error("No passphrases available in %s" % self.setup['configfile']) return False @@ -83,7 +83,7 @@ class Encryptor(object): (self.pname, self.setup['configfile'])) return False else: - pnames = Bcfg2.Encryption.get_passphrases(self.setup) + pnames = Bcfg2.Encryption.get_passphrases() if len(pnames) == 1: self.pname = pnames.keys()[0] self.passphrase = pnames[self.pname] @@ -127,9 +127,7 @@ class Encryptor(object): # pylint: disable=W0613 def _encrypt(self, plaintext, passphrase, name=None): """ encrypt a single chunk of a file """ - return Bcfg2.Encryption.ssl_encrypt( - plaintext, passphrase, - Bcfg2.Encryption.get_algorithm(self.setup)) + return Bcfg2.Encryption.ssl_encrypt(plaintext, passphrase) # pylint: enable=W0613 def decrypt(self, fname): @@ -162,7 +160,7 @@ class Encryptor(object): except TypeError: pchunk = None for pname, passphrase in \ - Bcfg2.Encryption.get_passphrases(self.setup).items(): + Bcfg2.Encryption.get_passphrases().items(): self.logger.debug("Trying passphrase %s" % pname) try: pchunk = self._decrypt(chunk, passphrase) @@ -196,9 +194,7 @@ class Encryptor(object): def _decrypt(self, crypted, passphrase): """ decrypt a single chunk """ - return Bcfg2.Encryption.ssl_decrypt( - crypted, passphrase, - Bcfg2.Encryption.get_algorithm(self.setup)) + return Bcfg2.Encryption.ssl_decrypt(crypted, passphrase) def write_encrypted(self, fname, data=None): """ write encrypted data to disk """ @@ -287,10 +283,8 @@ class PropertiesEncryptor(Encryptor): if name is None: name = "true" if plaintext.text and plaintext.text.strip(): - plaintext.text = Bcfg2.Encryption.ssl_encrypt( - plaintext.text, - passphrase, - Bcfg2.Encryption.get_algorithm(self.setup)).strip() + plaintext.text = Bcfg2.Encryption.ssl_encrypt(plaintext.text, + passphrase).strip() plaintext.set("encrypted", name) return plaintext @@ -358,10 +352,8 @@ class PropertiesEncryptor(Encryptor): if not crypted.text or not crypted.text.strip(): self.logger.warning("Skipping empty element %s" % crypted.tag) return crypted - decrypted = Bcfg2.Encryption.ssl_decrypt( - crypted.text, - passphrase, - Bcfg2.Encryption.get_algorithm(self.setup)).strip() + decrypted = Bcfg2.Encryption.ssl_decrypt(crypted.text, + passphrase).strip() try: crypted.text = decrypted.encode('ascii', 'xmlcharrefreplace') except UnicodeDecodeError: @@ -379,10 +371,10 @@ def main(): # pylint: disable=R0912,R0915 optinfo = dict(interactive=Bcfg2.Options.INTERACTIVE) optinfo.update(Bcfg2.Options.CRYPT_OPTIONS) optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS) - setup = Bcfg2.Options.OptionParser(optinfo) + setup = Bcfg2.Options.get_option_parser(optinfo) setup.hm = " bcfg2-crypt [options] \nOptions:\n%s" % \ setup.buildHelpMessage() - setup.parse(sys.argv[1:]) + setup.parse() if not setup['args']: print(setup.hm) diff --git a/src/sbin/bcfg2-info b/src/sbin/bcfg2-info index fa8c89b46..c697e9fca 100755 --- a/src/sbin/bcfg2-info +++ b/src/sbin/bcfg2-info @@ -115,9 +115,9 @@ def load_interpreters(): class InfoCore(cmd.Cmd, Bcfg2.Server.Core.BaseCore): """Main class for bcfg2-info.""" - def __init__(self, setup): + def __init__(self): cmd.Cmd.__init__(self) - Bcfg2.Server.Core.BaseCore.__init__(self, setup=setup) + Bcfg2.Server.Core.BaseCore.__init__(self) self.prompt = '> ' self.cont = True self.fam.handle_events_in_interval(4) @@ -751,7 +751,7 @@ def main(): interpreter=Bcfg2.Options.INTERPRETER) optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS) optinfo.update(Bcfg2.Options.SERVER_COMMON_OPTIONS) - setup = Bcfg2.Options.OptionParser(optinfo) + setup = Bcfg2.Options.get_option_parser(optinfo) setup.hm = "\n".join([" bcfg2-info [options] [command ]", "Options:", setup.buildHelpMessage(), @@ -772,12 +772,12 @@ def main(): sys.exit(0) elif setup['profile'] and HAS_PROFILE: prof = profile.Profile() - loop = prof.runcall(InfoCore, setup) + loop = prof.runcall(InfoCore) display_trace(prof) else: if setup['profile']: print("Profiling functionality not available.") - loop = InfoCore(setup) + loop = InfoCore() loop.run(setup['args']) diff --git a/src/sbin/bcfg2-lint b/src/sbin/bcfg2-lint index 959a2d8ed..f12fcc6c4 100755 --- a/src/sbin/bcfg2-lint +++ b/src/sbin/bcfg2-lint @@ -13,37 +13,36 @@ import Bcfg2.Server.Lint LOGGER = logging.getLogger('bcfg2-lint') -def run_serverless_plugins(plugins, setup=None, errorhandler=None, files=None): +def run_serverless_plugins(plugins, errorhandler=None, files=None): """ Run serverless plugins """ LOGGER.debug("Running serverless plugins") for plugin_name, plugin in list(plugins.items()): - run_plugin(plugin, plugin_name, errorhandler=errorhandler, - setup=setup, files=files) + run_plugin(plugin, plugin_name, errorhandler=errorhandler, files=files) -def run_server_plugins(plugins, setup=None, errorhandler=None, files=None): +def run_server_plugins(plugins, errorhandler=None, files=None): """ run plugins that require a running server to run """ - core = load_server(setup) + core = load_server() try: LOGGER.debug("Running server plugins") for plugin_name, plugin in list(plugins.items()): run_plugin(plugin, plugin_name, args=[core], - errorhandler=errorhandler, setup=setup, files=files) + errorhandler=errorhandler, files=files) finally: core.shutdown() -def run_plugin(plugin, plugin_name, setup=None, errorhandler=None, - args=None, files=None): +def run_plugin(plugin, plugin_name, errorhandler=None, args=None, files=None): """ run a single plugin, server-ful or serverless. """ LOGGER.debug(" Running %s" % plugin_name) if args is None: args = [] if errorhandler is None: - errorhandler = get_errorhandler(setup) + errorhandler = get_errorhandler() - if setup is not None and setup.cfp.has_section(plugin_name): + setup = Bcfg2.Options.get_option_parser() + if setup.cfp.has_section(plugin_name): arg = setup for key, val in setup.cfp.items(plugin_name): arg[key] = val @@ -54,8 +53,9 @@ def run_plugin(plugin, plugin_name, setup=None, errorhandler=None, return plugin(*args, files=files, errorhandler=errorhandler).Run() -def get_errorhandler(setup): +def get_errorhandler(): """ get a Bcfg2.Server.Lint.ErrorHandler object """ + setup = Bcfg2.Options.get_option_parser() if setup.cfp.has_section("errors"): conf = dict(setup.cfp.items("errors")) else: @@ -63,9 +63,9 @@ def get_errorhandler(setup): return Bcfg2.Server.Lint.ErrorHandler(config=conf) -def load_server(setup): +def load_server(): """ load server """ - core = Bcfg2.Server.Core.BaseCore(setup) + core = Bcfg2.Server.Core.BaseCore() core.fam.handle_events_in_interval(4) return core @@ -82,8 +82,9 @@ def load_plugin(module, obj_name=None): return getattr(mod, obj_name) -def load_plugins(setup): +def load_plugins(): """ get list of plugins to run """ + setup = Bcfg2.Options.get_option_parser() if setup['args']: plugin_list = setup['args'] elif "bcfg2-repo-validate" in sys.argv[0]: @@ -145,7 +146,7 @@ def main(): lint_plugins=Bcfg2.Options.LINT_PLUGINS) optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS) optinfo.update(Bcfg2.Options.SERVER_COMMON_OPTIONS) - setup = Bcfg2.Options.OptionParser(optinfo) + setup = Bcfg2.Options.get_option_parser(optinfo) setup.parse(sys.argv[1:]) log_args = dict(to_syslog=setup['syslog'], to_console=logging.WARNING) @@ -161,9 +162,8 @@ def main(): else: files = None - (serverlessplugins, serverplugins) = load_plugins(setup) - - errorhandler = get_errorhandler(setup) + (serverlessplugins, serverplugins) = load_plugins() + errorhandler = get_errorhandler() if setup['showerrors']: for plugin in serverplugins.values() + serverlessplugins.values(): @@ -175,7 +175,7 @@ def main(): raise SystemExit(0) run_serverless_plugins(serverlessplugins, errorhandler=errorhandler, - setup=setup, files=files) + files=files) if serverplugins: if errorhandler.errors: @@ -191,7 +191,7 @@ def main(): "plugins") else: run_server_plugins(serverplugins, errorhandler=errorhandler, - setup=setup, files=files) + files=files) if errorhandler.errors or errorhandler.warnings or setup['verbose']: print("%d errors" % errorhandler.errors) diff --git a/src/sbin/bcfg2-report-collector b/src/sbin/bcfg2-report-collector index a0ee2259a..d925023d1 100755 --- a/src/sbin/bcfg2-report-collector +++ b/src/sbin/bcfg2-report-collector @@ -20,8 +20,8 @@ def main(): ) optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS) optinfo.update(Bcfg2.Options.REPORTING_COMMON_OPTIONS) - setup = Bcfg2.Options.OptionParser(optinfo) - setup.parse(sys.argv[1:]) + setup = Bcfg2.Options.get_option_parser(optinfo) + setup.parse() # run collector try: diff --git a/src/sbin/bcfg2-server b/src/sbin/bcfg2-server index 8322edeaa..7e7dede30 100755 --- a/src/sbin/bcfg2-server +++ b/src/sbin/bcfg2-server @@ -16,13 +16,13 @@ def main(): optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS) optinfo.update(Bcfg2.Options.SERVER_COMMON_OPTIONS) optinfo.update(Bcfg2.Options.DAEMON_COMMON_OPTIONS) - setup = Bcfg2.Options.OptionParser(optinfo) + setup = Bcfg2.Options.get_option_parser(args=optinfo) setup.parse(sys.argv[1:]) # check whether the specified bcfg2.conf exists if not os.path.exists(setup['configfile']): print("Could not read %s" % setup['configfile']) sys.exit(1) - + if setup['backend'] not in ['best', 'cherrypy', 'builtin']: print("Unknown server backend %s, using 'best'" % setup['backend']) setup['backend'] = 'best' @@ -37,7 +37,7 @@ def main(): from Bcfg2.Server.BuiltinCore import Core try: - core = Core(setup) + core = Core() core.run() except CoreInitError: msg = sys.exc_info()[1] diff --git a/src/sbin/bcfg2-test b/src/sbin/bcfg2-test index 815d2740c..a708a233a 100755 --- a/src/sbin/bcfg2-test +++ b/src/sbin/bcfg2-test @@ -69,7 +69,7 @@ def main(): validate=Bcfg2.Options.CFG_VALIDATION) optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS) optinfo.update(Bcfg2.Options.SERVER_COMMON_OPTIONS) - setup = Bcfg2.Options.OptionParser(optinfo) + setup = Bcfg2.Options.get_option_parser(args=optinfo) setup.hm = \ "bcfg2-test [options] [client] [client] [...]\nOptions:\n %s" % \ setup.buildHelpMessage() @@ -78,7 +78,7 @@ def main(): if setup['verbose']: Bcfg2.Logger.setup_logging("bcfg2-test", to_syslog=setup['syslog']) - core = Bcfg2.Server.Core.BaseCore(setup) + core = Bcfg2.Server.Core.BaseCore() ignore = dict() for entry in setup['test_ignore']: diff --git a/testsuite/Testsrc/Testlib/TestEncryption.py b/testsuite/Testsrc/Testlib/TestEncryption.py index c03aa66e1..f8fcaa98d 100644 --- a/testsuite/Testsrc/Testlib/TestEncryption.py +++ b/testsuite/Testsrc/Testlib/TestEncryption.py @@ -110,37 +110,17 @@ baz self.assertRaises(EVPError, ssl_decrypt, crypted, passwd) # bogus algorithm - def test_get_algorithm(self): - setup = Mock() - # we don't care what the default is, as long as there is - # one - setup.cfp.get.return_value = ALGORITHM - self.assertRegexpMatches(get_algorithm(setup), - r'^[a-z0-9]+_[a-z0-9_]+$') - setup.cfp.get.assert_called_with(CFG_SECTION, CFG_ALGORITHM, - default=ALGORITHM) - - setup.cfp.get.return_value = self.algo - self.assertEqual(get_algorithm(setup), self.algo) - setup.cfp.get.assert_called_with(CFG_SECTION, CFG_ALGORITHM, - default=ALGORITHM) - - # test that get_algorithm converts algorithms given in - # OpenSSL style to M2Crypto style - setup.cfp.get.return_value = "DES-EDE3-CFB8" - self.assertEqual(get_algorithm(setup), "des_ede3_cfb8") - setup.cfp.get.assert_called_with(CFG_SECTION, CFG_ALGORITHM, - default=ALGORITHM) - - def test_get_passphrases(self): + @patch("Bcfg2.Options.get_option_parser") + def test_get_passphrases(self, mock_get_option_parser): setup = Mock() setup.cfp.has_section.return_value = False - self.assertEqual(get_passphrases(setup), dict()) + mock_get_option_parser.return_value = setup + self.assertEqual(get_passphrases(), dict()) setup.cfp.has_section.return_value = True setup.cfp.options.return_value = ["foo", "bar", CFG_ALGORITHM] setup.cfp.get.return_value = "passphrase" - self.assertItemsEqual(get_passphrases(setup), + self.assertItemsEqual(get_passphrases(), dict(foo="passphrase", bar="passphrase")) @@ -148,14 +128,12 @@ baz def test_bruteforce_decrypt(self, mock_passphrases): passwd = "a simple passphrase" crypted = ssl_encrypt(self.plaintext, passwd) - setup = Mock() # test with no passphrases given nor in config mock_passphrases.return_value = dict() self.assertRaises(EVPError, - bruteforce_decrypt, - crypted, setup=setup) - mock_passphrases.assert_called_with(setup) + bruteforce_decrypt, crypted) + mock_passphrases.assert_called_with() # test with good passphrase given in function call mock_passphrases.reset_mock() @@ -179,15 +157,14 @@ baz real=passwd, bogus2="also bogus") self.assertEqual(self.plaintext, - bruteforce_decrypt(crypted, setup=setup)) - mock_passphrases.assert_called_with(setup) + bruteforce_decrypt(crypted)) + mock_passphrases.assert_called_with() # test that passphrases given in function call take # precedence over config mock_passphrases.reset_mock() self.assertRaises(EVPError, - bruteforce_decrypt, - crypted, setup=setup, + bruteforce_decrypt, crypted, passphrases=["bogus", "also bogus"]) self.assertFalse(mock_passphrases.called) @@ -195,5 +172,4 @@ baz mock_passphrases.reset_mock() crypted = ssl_encrypt(self.plaintext, passwd, algorithm=self.algo) self.assertEqual(self.plaintext, - bruteforce_decrypt(crypted, setup=setup, - algorithm=self.algo)) + bruteforce_decrypt(crypted, algorithm=self.algo)) diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py index 6dbdc7667..75cc41a34 100644 --- a/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py +++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py @@ -1716,16 +1716,17 @@ class TestEntrySet(TestDebuggable): "important: true", "bogus: line"] mock_open.return_value.readlines.return_value = idata + eset.metadata = default_path_metadata() eset.update_metadata(event) - expected = DEFAULT_FILE_METADATA.copy() + expected = default_path_metadata() expected['owner'] = 'owner' expected['group'] = 'GROUP' expected['mode'] = '0775' expected['important'] = 'true' - self.assertItemsEqual(eset.metadata, - expected) + self.assertItemsEqual(eset.metadata, expected) - def test_reset_metadata(self): + @patch("Bcfg2.Server.Plugin.helpers.default_path_metadata") + def test_reset_metadata(self, mock_default_path_metadata): eset = self.get_obj() # test info.xml @@ -1740,7 +1741,8 @@ class TestEntrySet(TestDebuggable): event.filename = fname eset.metadata = Mock() eset.reset_metadata(event) - self.assertItemsEqual(eset.metadata, DEFAULT_FILE_METADATA) + self.assertEqual(eset.metadata, + mock_default_path_metadata.return_value) @patch("Bcfg2.Server.Plugin.helpers.bind_info") def test_bind_info_to_entry(self, mock_bind_info): diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgAuthorizedKeysGenerator.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgAuthorizedKeysGenerator.py index d655a20cd..b77d52033 100644 --- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgAuthorizedKeysGenerator.py +++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgAuthorizedKeysGenerator.py @@ -42,27 +42,25 @@ class TestCfgAuthorizedKeysGenerator(TestCfgGenerator, TestStructFile): def test_category(self): akg = self.get_obj() - cfp = Mock() - cfp.has_section.return_value = False - cfp.has_option.return_value = False - Bcfg2.Server.Plugins.Cfg.CfgAuthorizedKeysGenerator.SETUP = Mock() - Bcfg2.Server.Plugins.Cfg.CfgAuthorizedKeysGenerator.SETUP.cfp = cfp + akg.setup = Mock() + akg.setup.cfp.has_section.return_value = False + akg.setup.cfp.has_option.return_value = False self.assertIsNone(akg.category) - cfp.has_section.assert_called_with("sshkeys") + akg.setup.cfp.has_section.assert_called_with("sshkeys") - cfp.reset_mock() - cfp.has_section.return_value = True + akg.setup.reset_mock() + akg.setup.cfp.has_section.return_value = True self.assertIsNone(akg.category) - cfp.has_section.assert_called_with("sshkeys") - cfp.has_option.assert_called_with("sshkeys", "category") - - cfp.reset_mock() - cfp.has_option.return_value = True - self.assertEqual(akg.category, cfp.get.return_value) - cfp.has_section.assert_called_with("sshkeys") - cfp.has_option.assert_called_with("sshkeys", "category") - cfp.get.assert_called_with("sshkeys", "category") + akg.setup.cfp.has_section.assert_called_with("sshkeys") + akg.setup.cfp.has_option.assert_called_with("sshkeys", "category") + + akg.setup.reset_mock() + akg.setup.cfp.has_option.return_value = True + self.assertEqual(akg.category, akg.setup.cfp.get.return_value) + akg.setup.cfp.has_section.assert_called_with("sshkeys") + akg.setup.cfp.has_option.assert_called_with("sshkeys", "category") + akg.setup.cfp.get.assert_called_with("sshkeys", "category") @patch("Bcfg2.Server.Plugins.Cfg.CfgAuthorizedKeysGenerator.ClientMetadata") @patch("Bcfg2.Server.Plugins.Cfg.CfgAuthorizedKeysGenerator.CfgAuthorizedKeysGenerator.category", "category") diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgCheetahGenerator.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgCheetahGenerator.py index fc5d5e53d..31227329c 100644 --- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgCheetahGenerator.py +++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgCheetahGenerator.py @@ -31,11 +31,11 @@ if HAS_CHEETAH or can_skip: ccg.data = "data" entry = lxml.etree.Element("Path", name="/test.txt") metadata = Mock() - Bcfg2.Server.Plugins.Cfg.CfgCheetahGenerator.SETUP = MagicMock() + ccg.setup = MagicMock() self.assertEqual(ccg.get_data(entry, metadata), mock_Template.return_value.respond.return_value) - Bcfg2.Server.Plugins.Cfg.CfgCheetahGenerator.SETUP.__getitem__.assert_called_with("repo") + ccg.setup.__getitem__.assert_called_with("repo") mock_Template.assert_called_with("data".decode(ccg.encoding), compilerSettings=ccg.settings) tmpl = mock_Template.return_value @@ -44,5 +44,4 @@ if HAS_CHEETAH or can_skip: self.assertEqual(tmpl.name, entry.get("name")) self.assertEqual(tmpl.path, entry.get("name")) self.assertEqual(tmpl.source_path, ccg.name) - self.assertEqual(tmpl.repo, - Bcfg2.Server.Plugins.Cfg.CfgCheetahGenerator.SETUP.__getitem__.return_value) + self.assertEqual(tmpl.repo, ccg.setup.__getitem__.return_value) diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgEncryptedGenerator.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgEncryptedGenerator.py index 71a7410da..f8e9b1990 100644 --- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgEncryptedGenerator.py +++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgEncryptedGenerator.py @@ -26,16 +26,13 @@ if can_skip or HAS_CRYPTO: def setUp(self): pass - @patchIf(HAS_CRYPTO, - "Bcfg2.Server.Plugins.Cfg.CfgEncryptedGenerator.get_algorithm") @patchIf(HAS_CRYPTO, "Bcfg2.Server.Plugins.Cfg.CfgEncryptedGenerator.bruteforce_decrypt") - def test_handle_event(self, mock_decrypt, mock_get_algorithm): + def test_handle_event(self, mock_decrypt): @patch("Bcfg2.Server.Plugins.Cfg.CfgGenerator.handle_event") def inner(mock_handle_event): def reset(): mock_decrypt.reset_mock() - mock_get_algorithm.reset_mock() mock_handle_event.reset_mock() def get_event_data(obj, event): @@ -47,9 +44,7 @@ if can_skip or HAS_CRYPTO: ceg = self.get_obj() ceg.handle_event(event) mock_handle_event.assert_called_with(ceg, event) - mock_decrypt.assert_called_with("encrypted", - setup=SETUP, - algorithm=mock_get_algorithm.return_value) + mock_decrypt.assert_called_with("encrypted") self.assertEqual(ceg.data, "plaintext") reset() diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgGenshiGenerator.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgGenshiGenerator.py index 385f8df77..88f3cf3f7 100644 --- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgGenshiGenerator.py +++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgGenshiGenerator.py @@ -43,6 +43,7 @@ if can_skip or HAS_GENSHI: def test_get_data(self): cgg = self.get_obj() cgg._handle_genshi_exception = Mock() + cgg.setup = MagicMock() cgg.template = Mock() fltr = Mock() cgg.template.generate.return_value = fltr @@ -51,24 +52,23 @@ if can_skip or HAS_GENSHI: entry = lxml.etree.Element("Path", name="/test.txt") metadata = Mock() - Bcfg2.Server.Plugins.Cfg.CfgGenshiGenerator.SETUP = MagicMock() def reset(): cgg.template.reset_mock() cgg._handle_genshi_exception.reset_mock() - Bcfg2.Server.Plugins.Cfg.CfgGenshiGenerator.SETUP.reset_mock() + cgg.setup.reset_mock() template_vars = dict( name=entry.get("name"), metadata=metadata, path=cgg.name, source_path=cgg.name, - repo=Bcfg2.Server.Plugins.Cfg.CfgGenshiGenerator.SETUP.__getitem__.return_value) + repo=cgg.setup.__getitem__.return_value) self.assertEqual(cgg.get_data(entry, metadata), stream.render.return_value) cgg.template.generate.assert_called_with(**template_vars) - Bcfg2.Server.Plugins.Cfg.CfgGenshiGenerator.SETUP.__getitem__.assert_called_with("repo") + cgg.setup.__getitem__.assert_called_with("repo") fltr.filter.assert_called_with(removecomment) stream.render.assert_called_with("text", encoding=cgg.encoding, strip_whitespace=False) @@ -81,7 +81,7 @@ if can_skip or HAS_GENSHI: self.assertEqual(cgg.get_data(entry, metadata), stream.render.return_value) cgg.template.generate.assert_called_with(**template_vars) - Bcfg2.Server.Plugins.Cfg.CfgGenshiGenerator.SETUP.__getitem__.assert_called_with("repo") + cgg.setup.__getitem__.assert_called_with("repo") fltr.filter.assert_called_with(removecomment) self.assertEqual(stream.render.call_args_list, [call("text", encoding=cgg.encoding, @@ -93,7 +93,7 @@ if can_skip or HAS_GENSHI: self.assertRaises(UndefinedError, cgg.get_data, entry, metadata) cgg.template.generate.assert_called_with(**template_vars) - Bcfg2.Server.Plugins.Cfg.CfgGenshiGenerator.SETUP.__getitem__.assert_called_with("repo") + cgg.setup.__getitem__.assert_called_with("repo") fltr.filter.assert_called_with(removecomment) stream.render.assert_called_with("text", encoding=cgg.encoding, strip_whitespace=False) @@ -104,7 +104,7 @@ if can_skip or HAS_GENSHI: self.assertRaises(ValueError, cgg.get_data, entry, metadata) cgg.template.generate.assert_called_with(**template_vars) - Bcfg2.Server.Plugins.Cfg.CfgGenshiGenerator.SETUP.__getitem__.assert_called_with("repo") + cgg.setup.__getitem__.assert_called_with("repo") fltr.filter.assert_called_with(removecomment) stream.render.assert_called_with("text", encoding=cgg.encoding, strip_whitespace=False) diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPrivateKeyCreator.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPrivateKeyCreator.py index dc4b11241..4c8ab8b43 100644 --- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPrivateKeyCreator.py +++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPrivateKeyCreator.py @@ -44,56 +44,56 @@ class TestCfgPrivateKeyCreator(TestCfgCreator, TestStructFile): def test_category(self): pkc = self.get_obj() - cfp = Mock() - cfp.has_section.return_value = False - cfp.has_option.return_value = False - Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.SETUP = Mock() - Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.SETUP.cfp = cfp + pkc.setup = Mock() + pkc.setup.cfp = Mock() + pkc.setup.cfp.has_section.return_value = False + pkc.setup.cfp.has_option.return_value = False self.assertIsNone(pkc.category) - cfp.has_section.assert_called_with("sshkeys") + pkc.setup.cfp.has_section.assert_called_with("sshkeys") - cfp.reset_mock() - cfp.has_section.return_value = True + pkc.setup.reset_mock() + pkc.setup.cfp.has_section.return_value = True self.assertIsNone(pkc.category) - cfp.has_section.assert_called_with("sshkeys") - cfp.has_option.assert_called_with("sshkeys", "category") + pkc.setup.cfp.has_section.assert_called_with("sshkeys") + pkc.setup.cfp.has_option.assert_called_with("sshkeys", "category") - cfp.reset_mock() - cfp.has_option.return_value = True - self.assertEqual(pkc.category, cfp.get.return_value) - cfp.has_section.assert_called_with("sshkeys") - cfp.has_option.assert_called_with("sshkeys", "category") - cfp.get.assert_called_with("sshkeys", "category") + pkc.setup.reset_mock() + pkc.setup.cfp.has_option.return_value = True + self.assertEqual(pkc.category, pkc.setup.cfp.get.return_value) + pkc.setup.cfp.has_section.assert_called_with("sshkeys") + pkc.setup.cfp.has_option.assert_called_with("sshkeys", "category") + pkc.setup.cfp.get.assert_called_with("sshkeys", "category") @skipUnless(HAS_CRYPTO, "No crypto libraries found, skipping") @patchIf(HAS_CRYPTO, "Bcfg2.Encryption.get_passphrases") def test_passphrase(self, mock_get_passphrases): pkc = self.get_obj() - cfp = Mock() - cfp.has_section.return_value = False - cfp.has_option.return_value = False - Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.SETUP = Mock() - Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.SETUP.cfp = cfp + pkc.setup = Mock() + pkc.setup.cfp = Mock() + pkc.setup.cfp.has_section.return_value = False + pkc.setup.cfp.has_option.return_value = False self.assertIsNone(pkc.passphrase) - cfp.has_section.assert_called_with("sshkeys") + pkc.setup.cfp.has_section.assert_called_with("sshkeys") - cfp.reset_mock() - cfp.has_section.return_value = True + pkc.setup.reset_mock() + pkc.setup.cfp.has_section.return_value = True self.assertIsNone(pkc.passphrase) - cfp.has_section.assert_called_with("sshkeys") - cfp.has_option.assert_called_with("sshkeys", "passphrase") + pkc.setup.cfp.has_section.assert_called_with("sshkeys") + pkc.setup.cfp.has_option.assert_called_with("sshkeys", + "passphrase") - cfp.reset_mock() - cfp.get.return_value = "test" + pkc.setup.reset_mock() + pkc.setup.cfp.get.return_value = "test" mock_get_passphrases.return_value = dict(test="foo", test2="bar") - cfp.has_option.return_value = True + pkc.setup.cfp.has_option.return_value = True self.assertEqual(pkc.passphrase, "foo") - cfp.has_section.assert_called_with("sshkeys") - cfp.has_option.assert_called_with("sshkeys", "passphrase") - cfp.get.assert_called_with("sshkeys", "passphrase") - mock_get_passphrases.assert_called_with(Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.SETUP) + pkc.setup.cfp.has_section.assert_called_with("sshkeys") + pkc.setup.cfp.has_option.assert_called_with("sshkeys", + "passphrase") + pkc.setup.cfp.get.assert_called_with("sshkeys", "passphrase") + mock_get_passphrases.assert_called_with() @patch("shutil.rmtree") @patch("tempfile.mkdtemp") @@ -282,8 +282,7 @@ class TestCfgPrivateKeyCreator(TestCfgCreator, TestStructFile): if HAS_CRYPTO: @patch(passphrase, "foo") @patch("Bcfg2.Encryption.ssl_encrypt") - @patch("Bcfg2.Encryption.get_algorithm") - def inner2(mock_get_algorithm, mock_ssl_encrypt): + def inner2(mock_ssl_encrypt): reset() mock_ssl_encrypt.return_value = "encryptedprivatekey" Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.HAS_CRYPTO = True @@ -302,9 +301,7 @@ class TestCfgPrivateKeyCreator(TestCfgCreator, TestStructFile): "ssh-rsa publickey pubkey.filename\n", group="foo") pkc.write_data.assert_called_with("encryptedprivatekey", group="foo", ext=".crypt") - mock_ssl_encrypt.assert_called_with( - "privatekey", "foo", - algorithm=mock_get_algorithm.return_value) + mock_ssl_encrypt.assert_called_with("privatekey", "foo") mock_rmtree.assert_called_with(datastore) inner2() @@ -317,10 +314,9 @@ class TestCfgPrivateKeyCreator(TestCfgCreator, TestStructFile): @skipUnless(HAS_CRYPTO, "No crypto libraries found, skipping") def test_Index_crypto(self): - Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.SETUP = Mock() - Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.SETUP.cfp.get.return_value = "strict" - pkc = self.get_obj() + pkc.setup = Mock() + pkc.setup.cfp.get.return_value = "strict" pkc._decrypt = Mock() pkc._decrypt.return_value = 'plaintext' pkc.data = ''' @@ -348,7 +344,7 @@ class TestCfgPrivateKeyCreator(TestCfgCreator, TestStructFile): self.assertRaises(PluginExecutionError, pkc.Index) # test failed decryption, lax - Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.SETUP.cfp.get.return_value = "lax" + pkc.setup.cfp.get.return_value = "lax" pkc._decrypt.reset_mock() pkc.Index() self.assertItemsEqual( @@ -358,17 +354,13 @@ class TestCfgPrivateKeyCreator(TestCfgCreator, TestStructFile): @skipUnless(HAS_CRYPTO, "No crypto libraries found, skipping") @patchIf(HAS_CRYPTO, "Bcfg2.Encryption.ssl_decrypt") - @patchIf(HAS_CRYPTO, "Bcfg2.Encryption.get_algorithm") @patchIf(HAS_CRYPTO, "Bcfg2.Encryption.get_passphrases") @patchIf(HAS_CRYPTO, "Bcfg2.Encryption.bruteforce_decrypt") - def test_decrypt(self, mock_bruteforce, mock_get_passphrases, - mock_get_algorithm, mock_ssl): + def test_decrypt(self, mock_bruteforce, mock_get_passphrases, mock_ssl): pkc = self.get_obj() - Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.SETUP = MagicMock() def reset(): mock_bruteforce.reset_mock() - mock_get_algorithm.reset_mock() mock_get_passphrases.reset_mock() mock_ssl.reset_mock() @@ -382,29 +374,19 @@ class TestCfgPrivateKeyCreator(TestCfgCreator, TestStructFile): reset() el = lxml.etree.Element("Test", encrypted="foo") el.text = "crypted" - mock_get_passphrases.return_value = dict(foo="foopass", - bar="barpass") - mock_get_algorithm.return_value = "bf_cbc" + mock_get_passphrases.return_value = dict(foo="foopass", bar="barpass") mock_ssl.return_value = "decrypted with ssl" self.assertEqual(pkc._decrypt(el), mock_ssl.return_value) - mock_get_passphrases.assert_called_with( - Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.SETUP) - mock_get_algorithm.assert_called_with( - Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.SETUP) - mock_ssl.assert_called_with(el.text, "foopass", - algorithm="bf_cbc") + mock_get_passphrases.assert_called_with() + 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, pkc._decrypt, el) - mock_get_passphrases.assert_called_with( - Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.SETUP) - mock_get_algorithm.assert_called_with( - Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.SETUP) - mock_ssl.assert_called_with(el.text, "foopass", - algorithm="bf_cbc") + mock_get_passphrases.assert_called_with() + mock_ssl.assert_called_with(el.text, "foopass") self.assertFalse(mock_bruteforce.called) # test element without valid passphrase @@ -412,26 +394,14 @@ class TestCfgPrivateKeyCreator(TestCfgCreator, TestStructFile): el.set("encrypted", "true") mock_bruteforce.return_value = "decrypted with bruteforce" self.assertEqual(pkc._decrypt(el), mock_bruteforce.return_value) - mock_get_passphrases.assert_called_with( - Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.SETUP) - mock_get_algorithm.assert_called_with( - Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.SETUP) - mock_bruteforce.assert_called_with(el.text, - passphrases=["foopass", - "barpass"], - algorithm="bf_cbc") + mock_get_passphrases.assert_called_with() + mock_bruteforce.assert_called_with(el.text) self.assertFalse(mock_ssl.called) # test failure to decrypt element without valid passphrase reset() mock_bruteforce.side_effect = EVPError self.assertRaises(EVPError, pkc._decrypt, el) - mock_get_passphrases.assert_called_with( - Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.SETUP) - mock_get_algorithm.assert_called_with( - Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.SETUP) - mock_bruteforce.assert_called_with(el.text, - passphrases=["foopass", - "barpass"], - algorithm="bf_cbc") + mock_get_passphrases.assert_called_with() + mock_bruteforce.assert_called_with(el.text) self.assertFalse(mock_ssl.called) diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/Test_init.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/Test_init.py index 2e758774e..ee0b0be9d 100644 --- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/Test_init.py +++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/Test_init.py @@ -439,8 +439,6 @@ class TestCfgEntrySet(TestEntrySet): @patch("Bcfg2.Server.Plugins.Cfg.u_str") @patch("Bcfg2.Server.Plugins.Cfg.b64encode") def test_bind_entry(self, mock_b64encode, mock_u_str): - Bcfg2.Server.Plugins.Cfg.SETUP = dict(validate=False) - mock_u_str.side_effect = lambda x: x eset = self.get_obj() @@ -448,6 +446,7 @@ class TestCfgEntrySet(TestEntrySet): eset._generate_data = Mock() eset.get_handlers = Mock() eset._validate_data = Mock() + eset.setup = dict(validate=False) def reset(): mock_b64encode.reset_mock() @@ -523,7 +522,7 @@ class TestCfgEntrySet(TestEntrySet): # test successful validation entry = reset() - Bcfg2.Server.Plugins.Cfg.SETUP['validate'] = True + eset.setup['validate'] = True bound = eset.bind_entry(entry, metadata) eset.bind_info_to_entry.assert_called_with(entry, metadata) eset._generate_data.assert_called_with(entry, metadata) @@ -753,31 +752,39 @@ class TestCfg(TestGroupSpool, TestPullTarget): def get_obj(self, core=None): if core is None: core = Mock() - core.setup = MagicMock() return TestGroupSpool.get_obj(self, core=core) + @patch("Bcfg2.Options.get_option_parser") @patch("Bcfg2.Server.Plugin.GroupSpool.__init__") @patch("Bcfg2.Server.Plugin.PullTarget.__init__") - def test__init(self, mock_pulltarget_init, mock_groupspool_init): + def test__init(self, mock_pulltarget_init, mock_groupspool_init, + mock_get_option_parser): + setup = MagicMock() + setup.__contains__.return_value = False + mock_get_option_parser.return_value = setup + + def reset(): + core.reset_mock() + setup.reset_mock() + mock_pulltarget_init.reset_mock() + mock_groupspool_init.reset_mock() + core = Mock() - core.setup = MagicMock() cfg = self.test_obj(core, datastore) mock_pulltarget_init.assert_called_with(cfg) mock_groupspool_init.assert_called_with(cfg, core, datastore) - core.setup.add_option.assert_called_with("validate", - Bcfg2.Options.CFG_VALIDATION) - core.setup.reparse.assert_called_with() - - core.reset_mock() - core.setup.reset_mock() - mock_pulltarget_init.reset_mock() - mock_groupspool_init.reset_mock() - core.setup.__contains__.return_value = True + setup.add_option.assert_called_with( + "validate", + Bcfg2.Options.CFG_VALIDATION) + mock_get_option_parser.return_value.reparse.assert_called_with() + + reset() + setup.__contains__.return_value = True cfg = self.test_obj(core, datastore) mock_pulltarget_init.assert_called_with(cfg) mock_groupspool_init.assert_called_with(cfg, core, datastore) - self.assertFalse(core.setup.add_option.called) - self.assertFalse(core.setup.reparse.called) + self.assertFalse(setup.add_option.called) + self.assertFalse(setup.reparse.called) def test_has_generator(self): cfg = self.get_obj() diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestProperties.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestProperties.py index d66780a20..b0ca77a78 100644 --- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestProperties.py +++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestProperties.py @@ -41,10 +41,10 @@ class TestPropertyFile(Bcfg2TestCase): return self.test_obj(path) def test_write(self): - Bcfg2.Server.Plugins.Properties.SETUP = MagicMock() pf = self.get_obj() pf.validate_data = Mock() pf._write = Mock() + pf.setup = Mock() xstr = u("\n") pf.xdata = lxml.etree.XML(xstr) @@ -52,20 +52,20 @@ class TestPropertyFile(Bcfg2TestCase): def reset(): pf.validate_data.reset_mock() pf._write.reset_mock() - Bcfg2.Server.Plugins.Properties.SETUP.reset_mock() + pf.setup.reset_mock() # test writes disabled - Bcfg2.Server.Plugins.Properties.SETUP.cfp.getboolean.return_value = False + pf.setup.cfp.getboolean.return_value = False self.assertRaises(PluginExecutionError, pf.write) self.assertFalse(pf.validate_data.called) self.assertFalse(pf._write.called) - Bcfg2.Server.Plugins.Properties.SETUP.cfp.getboolean.assert_called_with("properties", + pf.setup.cfp.getboolean.assert_called_with("properties", "writes_enabled", default=True) # test successful write reset() - Bcfg2.Server.Plugins.Properties.SETUP.cfp.getboolean.return_value = True + pf.setup.cfp.getboolean.return_value = True self.assertEqual(pf.write(), pf._write.return_value) pf.validate_data.assert_called_with() pf._write.assert_called_with() @@ -301,17 +301,13 @@ class TestXMLPropertyFile(TestPropertyFile, TestStructFile): @skipUnless(HAS_CRYPTO, "No crypto libraries found, skipping") @patchIf(HAS_CRYPTO, "Bcfg2.Encryption.ssl_decrypt") - @patchIf(HAS_CRYPTO, "Bcfg2.Encryption.get_algorithm") @patchIf(HAS_CRYPTO, "Bcfg2.Encryption.get_passphrases") @patchIf(HAS_CRYPTO, "Bcfg2.Encryption.bruteforce_decrypt") - def test_decrypt(self, mock_bruteforce, mock_get_passphrases, - mock_get_algorithm, mock_ssl): + def test_decrypt(self, mock_bruteforce, mock_get_passphrases, mock_ssl): pf = self.get_obj() - Bcfg2.Server.Plugins.Properties.SETUP = MagicMock() def reset(): mock_bruteforce.reset_mock() - mock_get_algorithm.reset_mock() mock_get_passphrases.reset_mock() mock_ssl.reset_mock() @@ -325,29 +321,19 @@ class TestXMLPropertyFile(TestPropertyFile, TestStructFile): reset() el = lxml.etree.Element("Test", encrypted="foo") el.text = "crypted" - mock_get_passphrases.return_value = dict(foo="foopass", - bar="barpass") - mock_get_algorithm.return_value = "bf_cbc" + mock_get_passphrases.return_value = dict(foo="foopass", bar="barpass") mock_ssl.return_value = "decrypted with ssl" self.assertEqual(pf._decrypt(el), mock_ssl.return_value) - mock_get_passphrases.assert_called_with( - Bcfg2.Server.Plugins.Properties.SETUP) - mock_get_algorithm.assert_called_with( - Bcfg2.Server.Plugins.Properties.SETUP) - mock_ssl.assert_called_with(el.text, "foopass", - algorithm="bf_cbc") + mock_get_passphrases.assert_called_with() + 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, pf._decrypt, el) - mock_get_passphrases.assert_called_with( - Bcfg2.Server.Plugins.Properties.SETUP) - mock_get_algorithm.assert_called_with( - Bcfg2.Server.Plugins.Properties.SETUP) - mock_ssl.assert_called_with(el.text, "foopass", - algorithm="bf_cbc") + mock_get_passphrases.assert_called_with() + mock_ssl.assert_called_with(el.text, "foopass") self.assertFalse(mock_bruteforce.called) # test element without valid passphrase @@ -355,77 +341,73 @@ class TestXMLPropertyFile(TestPropertyFile, TestStructFile): el.set("encrypted", "true") mock_bruteforce.return_value = "decrypted with bruteforce" self.assertEqual(pf._decrypt(el), mock_bruteforce.return_value) - mock_get_passphrases.assert_called_with( - Bcfg2.Server.Plugins.Properties.SETUP) - mock_get_algorithm.assert_called_with( - Bcfg2.Server.Plugins.Properties.SETUP) - mock_bruteforce.assert_called_with(el.text, - passphrases=["foopass", - "barpass"], - algorithm="bf_cbc") + mock_get_passphrases.assert_called_with() + mock_bruteforce.assert_called_with(el.text) self.assertFalse(mock_ssl.called) # test failure to decrypt element without valid passphrase reset() mock_bruteforce.side_effect = EVPError self.assertRaises(EVPError, pf._decrypt, el) - mock_get_passphrases.assert_called_with( - Bcfg2.Server.Plugins.Properties.SETUP) - mock_get_algorithm.assert_called_with( - Bcfg2.Server.Plugins.Properties.SETUP) - mock_bruteforce.assert_called_with(el.text, - passphrases=["foopass", - "barpass"], - algorithm="bf_cbc") + mock_get_passphrases.assert_called_with() + mock_bruteforce.assert_called_with(el.text) self.assertFalse(mock_ssl.called) @patch("copy.copy") def test_get_additional_data(self, mock_copy): - Bcfg2.Server.Plugins.Properties.SETUP = Mock() pf = self.get_obj() + pf.setup = Mock() pf.XMLMatch = Mock() metadata = Mock() def reset(): mock_copy.reset_mock() pf.XMLMatch.reset_mock() - Bcfg2.Server.Plugins.Properties.SETUP.reset_mock() + pf.setup.reset_mock() pf.xdata = lxml.etree.Element("Properties", automatch="true") for automatch in [True, False]: reset() - Bcfg2.Server.Plugins.Properties.SETUP.cfp.getboolean.return_value = automatch + pf.setup.cfp.getboolean.return_value = automatch self.assertEqual(pf.get_additional_data(metadata), pf.XMLMatch.return_value) pf.XMLMatch.assert_called_with(metadata) - Bcfg2.Server.Plugins.Properties.SETUP.cfp.getboolean.assert_called_with("properties", "automatch", default=False) + pf.setup.cfp.getboolean.assert_called_with("properties", + "automatch", + default=False) self.assertFalse(mock_copy.called) pf.xdata = lxml.etree.Element("Properties", automatch="false") for automatch in [True, False]: reset() - Bcfg2.Server.Plugins.Properties.SETUP.cfp.getboolean.return_value = automatch + pf.setup.cfp.getboolean.return_value = automatch self.assertEqual(pf.get_additional_data(metadata), mock_copy.return_value) mock_copy.assert_called_with(pf) self.assertFalse(pf.XMLMatch.called) - Bcfg2.Server.Plugins.Properties.SETUP.cfp.getboolean.assert_called_with("properties", "automatch", default=False) + pf.setup.cfp.getboolean.assert_called_with("properties", + "automatch", + default=False) pf.xdata = lxml.etree.Element("Properties") reset() - Bcfg2.Server.Plugins.Properties.SETUP.cfp.getboolean.return_value = False + pf.setup.cfp.getboolean.return_value = False self.assertEqual(pf.get_additional_data(metadata), mock_copy.return_value) mock_copy.assert_called_with(pf) self.assertFalse(pf.XMLMatch.called) - Bcfg2.Server.Plugins.Properties.SETUP.cfp.getboolean.assert_called_with("properties", "automatch", default=False) + pf.setup.cfp.getboolean.assert_called_with("properties", + "automatch", + default=False) reset() - Bcfg2.Server.Plugins.Properties.SETUP.cfp.getboolean.return_value = True + pf.setup.cfp.getboolean.return_value = True self.assertEqual(pf.get_additional_data(metadata), pf.XMLMatch.return_value) pf.XMLMatch.assert_called_with(metadata) - Bcfg2.Server.Plugins.Properties.SETUP.cfp.getboolean.assert_called_with("properties", "automatch", default=False) + pf.setup.cfp.getboolean.assert_called_with("properties", + "automatch", + default=False) self.assertFalse(mock_copy.called) @@ -449,7 +431,6 @@ class TestProperties(TestPlugin, TestConnector): core = Mock() p = self.get_obj(core=core) self.assertIsInstance(p.store, PropDirectoryBacked) - self.assertEqual(Bcfg2.Server.Plugins.Properties.SETUP, core.setup) @patch("copy.copy") def test_get_additional_data(self, mock_copy): -- cgit v1.2.3-1-g7c22