summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/development/cfg.txt1
-rw-r--r--doc/server/encryption.txt9
-rw-r--r--doc/server/plugins/generators/cfg.txt3
-rw-r--r--schemas/types.xsd8
-rw-r--r--src/lib/Bcfg2/Client/Client.py4
-rwxr-xr-xsrc/lib/Bcfg2/Encryption.py53
-rw-r--r--src/lib/Bcfg2/Options.py73
-rw-r--r--src/lib/Bcfg2/Server/Admin/Compare.py4
-rw-r--r--src/lib/Bcfg2/Server/Admin/Init.py24
-rw-r--r--src/lib/Bcfg2/Server/Admin/Perf.py22
-rw-r--r--src/lib/Bcfg2/Server/Admin/Pull.py4
-rw-r--r--src/lib/Bcfg2/Server/Admin/Reports.py4
-rw-r--r--src/lib/Bcfg2/Server/Admin/Snapshots.py4
-rw-r--r--src/lib/Bcfg2/Server/Admin/Syncdb.py10
-rw-r--r--src/lib/Bcfg2/Server/Admin/Xcmd.py29
-rw-r--r--src/lib/Bcfg2/Server/Admin/__init__.py20
-rw-r--r--src/lib/Bcfg2/Server/BuiltinCore.py4
-rw-r--r--src/lib/Bcfg2/Server/CherryPyCore.py4
-rw-r--r--src/lib/Bcfg2/Server/Core.py65
-rw-r--r--src/lib/Bcfg2/Server/Plugin/helpers.py99
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Bundler.py19
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/CfgAuthorizedKeysGenerator.py8
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/CfgCheetahGenerator.py4
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenerator.py8
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenshiGenerator.py7
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py14
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/CfgPrivateKeyCreator.py71
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/CfgPublicKeyCreator.py3
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py29
-rw-r--r--src/lib/Bcfg2/Server/Plugins/FileProbes.py13
-rw-r--r--src/lib/Bcfg2/Server/Plugins/NagiosGen.py4
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Apt.py2
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Collection.py8
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py11
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Source.py7
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Yum.py14
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/__init__.py3
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Properties.py57
-rw-r--r--src/lib/Bcfg2/Server/Plugins/SSLCA.py1
-rw-r--r--src/lib/Bcfg2/Server/models.py13
-rw-r--r--src/lib/Bcfg2/settings.py28
-rwxr-xr-xsrc/sbin/bcfg27
-rwxr-xr-xsrc/sbin/bcfg2-admin4
-rwxr-xr-xsrc/sbin/bcfg2-crypt34
-rwxr-xr-xsrc/sbin/bcfg2-info10
-rwxr-xr-xsrc/sbin/bcfg2-lint40
-rwxr-xr-xsrc/sbin/bcfg2-report-collector4
-rwxr-xr-xsrc/sbin/bcfg2-server6
-rwxr-xr-xsrc/sbin/bcfg2-test4
-rw-r--r--testsuite/Testsrc/Testlib/TestEncryption.py46
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py121
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgAuthorizedKeysGenerator.py32
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgCheetahGenerator.py7
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgEncryptedGenerator.py9
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgGenshiGenerator.py14
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPrivateKeyCreator.py199
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/Test_init.py41
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestProperties.py181
58 files changed, 676 insertions, 851 deletions
diff --git a/doc/development/cfg.txt b/doc/development/cfg.txt
index 6533e0d7a..c3b8d12af 100644
--- a/doc/development/cfg.txt
+++ b/doc/development/cfg.txt
@@ -58,7 +58,6 @@ exceptions:
Global Variables
================
-.. autodata:: Bcfg2.Server.Plugins.Cfg.SETUP
.. autodata:: Bcfg2.Server.Plugins.Cfg.CFG
Existing Cfg Handlers
diff --git a/doc/server/encryption.txt b/doc/server/encryption.txt
index e84b9fb31..1f6cb72e6 100644
--- a/doc/server/encryption.txt
+++ b/doc/server/encryption.txt
@@ -23,7 +23,7 @@ separations between teams, environments, etc.
single Bcfg2 repository with multiple admins who should not
necessarily have access to each other's sensitive data.
-Two types of data can be encrypted:
+Two basic types of data can be encrypted:
* :ref:`server-plugins-generators-cfg` files can be encrypted
as whole files. See :ref:`server-plugins-generators-cfg-encryption`
@@ -50,6 +50,13 @@ In general, Properties encryption is preferred for a few reasons:
amongst different teams, this lets teams collaborate more closely on
files and other data.
+Other types of data that can be encrypted are:
+
+* Text content of Path tags in
+ :ref:`server-plugins-structures-bundler-index`
+* Passphrases in XML description files for generated
+ :ref:`server-plugins-generators-cfg-sshkeys`
+
.. _bcfg2-crypt:
bcfg2-crypt
diff --git a/doc/server/plugins/generators/cfg.txt b/doc/server/plugins/generators/cfg.txt
index e843b1d2d..1cb4b8727 100644
--- a/doc/server/plugins/generators/cfg.txt
+++ b/doc/server/plugins/generators/cfg.txt
@@ -583,6 +583,9 @@ influenced by several options in the ``[sshkeys]`` section of
| | group from. | | |
+----------------+---------------------------------------------------------+-----------------------+------------+
+See :ref:`server-encryption` for more details on encryption in Bcfg2
+in general.
+
Deltas
======
diff --git a/schemas/types.xsd b/schemas/types.xsd
index 524b327c5..144ef7337 100644
--- a/schemas/types.xsd
+++ b/schemas/types.xsd
@@ -371,6 +371,14 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
+ <xsd:attribute type="xsd:string" name="encrypted">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of the encryption passphrase that the text content
+ of this tag is encrypted with.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
<xsd:attributeGroup ref="py:genshiAttrs"/>
</xsd:complexType>
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 ``<passphrase name>``: ``<passphrase>``
- """
- 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 ``<passphrase name>``: ``<passphrase>``
"""
- 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 07d089f05..11c61a634 100644
--- a/src/lib/Bcfg2/Options.py
+++ b/src/lib/Bcfg2/Options.py
@@ -1126,6 +1126,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,
@@ -1214,10 +1222,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:]
@@ -1232,17 +1241,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)
@@ -1251,6 +1264,48 @@ 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 load_option_parser(args, argv=None, quiet=False):
+ """ Load an :class:`Bcfg2.Options.OptionParser` object, caching it
+ in :attr:`_PARSER` for later retrieval via
+ :func:`get_option_parser`.
+
+ :param args: The argument set to parse.
+ :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
+ _PARSER = OptionParser(args, argv=argv, quiet=quiet)
+ return _PARSER
+
+
+def get_option_parser():
+ """ Get an already-created :class:`Bcfg2.Options.OptionParser` object. If
+ :attr:`_PARSER` has not been populated, then a new OptionParser
+ will be created with basic arguments.
+
+ :returns: :class:`Bcfg2.Options.OptionParser`
+ """
+ if _PARSER is None:
+ return load_option_parser(CLI_COMMON_OPTIONS)
+ 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__ = ("<old> <new>\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__ = "<command>"
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 <xmlrpc method> <optional arguments>")
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 41c450b4e..399ab6679 100644
--- a/src/lib/Bcfg2/Server/Plugin/helpers.py
+++ b/src/lib/Bcfg2/Server/Plugin/helpers.py
@@ -18,25 +18,17 @@ from Bcfg2.Server.Plugin.exceptions import SpecificityError, \
PluginExecutionError
try:
+ import Bcfg2.Encryption
+ HAS_CRYPTO = True
+except ImportError:
+ HAS_CRYPTO = False
+
+try:
import django # pylint: disable=W0611
HAS_DJANGO = True
except ImportError:
HAS_DJANGO = False
-#: A dict containing default metadata for Path entries from bcfg2.conf
-DEFAULT_FILE_METADATA = Bcfg2.Options.OptionParser(dict(
- configfile=Bcfg2.Options.CFILE,
- 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([Bcfg2.Options.CFILE.cmd, Bcfg2.Options.CFILE])
-del DEFAULT_FILE_METADATA['args']
-del DEFAULT_FILE_METADATA['configfile']
-
LOGGER = logging.getLogger(__name__)
#: a compiled regular expression for parsing info and :info files
@@ -51,7 +43,20 @@ INFO_REGEX = re.compile('owner:(\s)*(?P<owner>\S+)|' +
'mtime:(\s)*(?P<mtime>\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(argv=[Bcfg2.Options.CFILE.cmd, Bcfg2.Options.CFILE])
+ 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.
@@ -68,6 +73,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:
@@ -570,13 +577,69 @@ class XMLFileBacked(FileBacked):
class StructFile(XMLFileBacked):
""" StructFiles are XML files that contain a set of structure file
formatting logic for handling ``<Group>`` and ``<Client>``
- tags. """
+ tags.
+
+ .. -----
+ .. autoattribute:: __identifier__
+ """
#: If ``__identifier__`` is not None, then it must be the name of
#: an XML attribute that will be required on the top-level tag of
#: the file being cached
__identifier__ = None
+ #: Whether or not encryption support is enabled in this file
+ encryption = True
+
+ def __init__(self, filename, fam=None, should_monitor=False):
+ XMLFileBacked.__init__(self, filename, fam=fam,
+ should_monitor=should_monitor)
+ self.setup = Bcfg2.Options.get_option_parser()
+
+ def Index(self):
+ XMLFileBacked.Index(self)
+ if self.encryption:
+ strict = self.xdata.get(
+ "decrypt",
+ self.setup.cfp.get(Bcfg2.Encryption.CFG_SECTION, "decrypt",
+ default="strict")) == "strict"
+ for el in self.xdata.xpath("//*[@encrypted]"):
+ if not HAS_CRYPTO:
+ raise PluginExecutionError("%s: M2Crypto is not available"
+ % self.name)
+ try:
+ el.text = self._decrypt(el).encode('ascii',
+ 'xmlcharrefreplace')
+ except UnicodeDecodeError:
+ LOGGER.info("%s: Decrypted %s to gibberish, skipping" %
+ (self.name, el.tag))
+ except Bcfg2.Encryption.EVPError:
+ msg = "Failed to decrypt %s element in %s" % (el.tag,
+ self.name)
+ if strict:
+ raise PluginExecutionError(msg)
+ else:
+ LOGGER.warning(msg)
+ Index.__doc__ = XMLFileBacked.Index.__doc__
+
+ def _decrypt(self, element):
+ """ Decrypt a single encrypted properties file element """
+ if not element.text or not element.text.strip():
+ return
+ passes = Bcfg2.Encryption.get_passphrases()
+ try:
+ passphrase = passes[element.get("encrypted")]
+ try:
+ 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)
+ raise Bcfg2.Encryption.EVPError("Failed to decrypt")
+
def _include_element(self, item, metadata):
""" determine if an XML element matches the metadata """
if isinstance(item, lxml.etree._Comment): # pylint: disable=W0212
@@ -1156,7 +1219,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
@@ -1378,7 +1441,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..4d6639e4d 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.Server.Plugin import PluginExecutionError, StructFile
-from Bcfg2.Server.Plugins.Cfg import CfgCreator, CfgCreationError, SETUP
+from Bcfg2.Options import get_option_parser
+from Bcfg2.Server.Plugin import StructFile
+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)
@@ -211,50 +211,3 @@ class CfgPrivateKeyCreator(CfgCreator, StructFile):
finally:
shutil.rmtree(os.path.dirname(filename))
# pylint: enable=W0221
-
- def Index(self):
- StructFile.Index(self)
- if HAS_CRYPTO:
- strict = self.xdata.get(
- "decrypt",
- SETUP.cfp.get(Bcfg2.Encryption.CFG_SECTION, "decrypt",
- default="strict")) == "strict"
- for el in self.xdata.xpath("//*[@encrypted]"):
- try:
- el.text = self._decrypt(el).encode('ascii',
- 'xmlcharrefreplace')
- except UnicodeDecodeError:
- self.logger.info("Cfg: Decrypted %s to gibberish, skipping"
- % el.tag)
- except Bcfg2.Encryption.EVPError:
- msg = "Cfg: Failed to decrypt %s element in %s" % \
- (el.tag, self.name)
- if strict:
- raise PluginExecutionError(msg)
- else:
- self.logger.warning(msg)
- Index.__doc__ = StructFile.Index.__doc__
-
- def _decrypt(self, element):
- """ Decrypt a single encrypted element """
- if not element.text or not element.text.strip():
- return
- passes = Bcfg2.Encryption.get_passphrases(SETUP)
- try:
- passphrase = passes[element.get("encrypted")]
- try:
- return Bcfg2.Encryption.ssl_decrypt(
- element.text,
- passphrase,
- algorithm=Bcfg2.Encryption.get_algorithm(SETUP))
- except Bcfg2.Encryption.EVPError:
- # error is raised below
- pass
- except KeyError:
- # bruteforce_decrypt raises an EVPError with a sensible
- # error message, so we just let it propagate up the stack
- return Bcfg2.Encryption.bruteforce_decrypt(
- element.text,
- passphrases=passes.values(),
- algorithm=Bcfg2.Encryption.get_algorithm(SETUP))
- raise Bcfg2.Encryption.EVPError("Failed to decrypt")
diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgPublicKeyCreator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgPublicKeyCreator.py
index 6be438462..4c61e338e 100644
--- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgPublicKeyCreator.py
+++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgPublicKeyCreator.py
@@ -23,6 +23,9 @@ class CfgPublicKeyCreator(CfgCreator, StructFile):
#: Handle XML specifications of private keys
__basenames__ = ['pubkey.xml']
+ #: No text content on any tags, so encryption support disabled
+ encryption = False
+
def __init__(self, fname):
CfgCreator.__init__(self, fname)
StructFile.__init__(self, fname)
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/FileProbes.py b/src/lib/Bcfg2/Server/Plugins/FileProbes.py
index 5ec0d7280..365549e85 100644
--- a/src/lib/Bcfg2/Server/Plugins/FileProbes.py
+++ b/src/lib/Bcfg2/Server/Plugins/FileProbes.py
@@ -51,6 +51,11 @@ print(Bcfg2.Client.XML.tostring(data, xml_declaration=False).decode('UTF-8'))
"""
+class FileProbesConfig(Bcfg2.Server.Plugin.StructFile):
+ """ Config file for FileProbes """
+ encryption = False
+
+
class FileProbes(Bcfg2.Server.Plugin.Plugin,
Bcfg2.Server.Plugin.Probing):
""" This module allows you to probe a client for a file, which is then
@@ -63,11 +68,9 @@ class FileProbes(Bcfg2.Server.Plugin.Plugin,
def __init__(self, core, datastore):
Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
Bcfg2.Server.Plugin.Probing.__init__(self)
- self.config = \
- Bcfg2.Server.Plugin.StructFile(os.path.join(self.data,
- 'config.xml'),
- fam=core.fam,
- should_monitor=True)
+ self.config = FileProbesConfig(os.path.join(self.data, 'config.xml'),
+ fam=core.fam,
+ should_monitor=True)
self.entries = dict()
self.probes = dict()
diff --git a/src/lib/Bcfg2/Server/Plugins/NagiosGen.py b/src/lib/Bcfg2/Server/Plugins/NagiosGen.py
index c39bd4c42..baea5fe23 100644
--- a/src/lib/Bcfg2/Server/Plugins/NagiosGen.py
+++ b/src/lib/Bcfg2/Server/Plugins/NagiosGen.py
@@ -15,12 +15,14 @@ LOGGER = logging.getLogger(__name__)
class NagiosGenConfig(Bcfg2.Server.Plugin.StructFile):
""" NagiosGen config file handler """
+ encryption = False
+
def __init__(self, filename, fam):
# create config.xml if missing
if not os.path.exists(filename):
LOGGER.warning("NagiosGen: %s missing. "
"Creating empty one for you." % filename)
- open(filename, "w").write("<NagiosGen></NagiosGen>")
+ open(filename, "w").write("<NagiosGen/>")
Bcfg2.Server.Plugin.StructFile.__init__(self, filename, fam=fam,
should_monitor=True)
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py b/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py
index ec0d8e828..27f493677 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py
@@ -35,7 +35,7 @@ class AptCollection(Collection):
for source in self:
if source.rawurl:
- self.logger.info("Packages: Skipping rawurl %s" %
+ self.logger.info("Packages: Skipping rawurl %s" %
source.rawurl)
else:
lines.append("deb %s %s %s" % (source.url, source.version,
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Collection.py b/src/lib/Bcfg2/Server/Plugins/Packages/Collection.py
index f9bb9e1a2..2c59b9a5a 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Collection.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Collection.py
@@ -78,6 +78,7 @@ import copy
import logging
import lxml.etree
import Bcfg2.Server.Plugin
+from Bcfg2.Options import get_option_parser
from Bcfg2.Compat import any, md5 # pylint: disable=W0622
LOGGER = logging.getLogger(__name__)
@@ -128,12 +129,11 @@ class Collection(list, Bcfg2.Server.Plugin.Debuggable):
self.cachepath = cachepath
self.virt_pkgs = dict()
self.fam = fam
+ self.setup = get_option_parser()
try:
- self.setup = sources[0].setup
self.ptype = sources[0].ptype
except IndexError:
- self.setup = None
self.ptype = "unknown"
@property
@@ -264,7 +264,7 @@ class Collection(list, Bcfg2.Server.Plugin.Debuggable):
support multiple package types in package groups
(e.g., "recommended," "optional," etc.)
:type ptype: string
- :returns: list of strings - package names, but see
+ :returns: list of strings - package names, but see
:ref:`pkg-objects`
"""
if not self.__package_groups__:
@@ -467,7 +467,7 @@ class Collection(list, Bcfg2.Server.Plugin.Debuggable):
included in the client configuration. See :ref:`pkg-objects`
for more details.
- :param pkglist: A list of packages as returned by
+ :param pkglist: A list of packages as returned by
:func:`complete`
:type pkglist: list of strings, but see :ref:`pkg-objects`
:param entry: The base XML entry to add all of the Package
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py b/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py
index 2735e389a..f528076c4 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py
@@ -4,6 +4,7 @@
import os
import sys
import Bcfg2.Server.Plugin
+from Bcfg2.Options import get_option_parser
from Bcfg2.Server.Plugins.Packages.Source import SourceInitError
@@ -17,7 +18,9 @@ class PackagesSources(Bcfg2.Server.Plugin.StructFile,
__identifier__ = None
- def __init__(self, filename, cachepath, fam, packages, setup):
+ encryption = False
+
+ def __init__(self, filename, cachepath, fam, packages):
"""
:param filename: The full path to ``sources.xml``
:type filename: string
@@ -32,8 +35,6 @@ class PackagesSources(Bcfg2.Server.Plugin.StructFile,
being parsed on behalf of (i.e., the calling
object)
:type packages: Bcfg2.Server.Plugins.Packages.Packages
- :param setup: A Bcfg2 options dict
- :type setup: dict
:raises: :class:`Bcfg2.Server.Plugin.exceptions.PluginInitError` -
If ``sources.xml`` cannot be read
@@ -62,7 +63,7 @@ class PackagesSources(Bcfg2.Server.Plugin.StructFile,
self.logger.error("Could not create Packages cache at %s: %s" %
(self.cachepath, err))
#: The Bcfg2 options dict
- self.setup = setup
+ self.setup = get_option_parser()
#: The :class:`Bcfg2.Server.Plugins.Packages.Packages` that
#: instantiated this ``PackagesSources`` object
@@ -157,7 +158,7 @@ class PackagesSources(Bcfg2.Server.Plugin.StructFile,
return None
try:
- source = cls(self.cachepath, xsource, self.setup)
+ source = cls(self.cachepath, xsource)
except SourceInitError:
err = sys.exc_info()[1]
self.logger.error("Packages: %s" % err)
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Source.py b/src/lib/Bcfg2/Server/Plugins/Packages/Source.py
index 985405e65..33eff60c8 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Source.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Source.py
@@ -51,6 +51,7 @@ import os
import re
import sys
import Bcfg2.Server.Plugin
+from Bcfg2.Options import get_option_parser
from Bcfg2.Compat import HTTPError, HTTPBasicAuthHandler, \
HTTPPasswordMgrWithDefaultRealm, install_opener, build_opener, \
urlopen, cPickle, md5
@@ -116,15 +117,13 @@ class Source(Bcfg2.Server.Plugin.Debuggable): # pylint: disable=R0902
#: when they are handled by :mod:`Bcfg2.Server.Plugins.Packages`.
ptype = None
- def __init__(self, basepath, xsource, setup): # pylint: disable=R0912
+ def __init__(self, basepath, xsource): # pylint: disable=R0912
"""
:param basepath: The base filesystem path under which cache
data for this source should be stored
:type basepath: string
:param xsource: The XML tag that describes this source
:type source: lxml.etree._Element
- :param setup: A Bcfg2 options dict
- :type setup: dict
:raises: :class:`Bcfg2.Server.Plugins.Packages.Source.SourceInitError`
"""
Bcfg2.Server.Plugin.Debuggable.__init__(self)
@@ -137,7 +136,7 @@ class Source(Bcfg2.Server.Plugin.Debuggable): # pylint: disable=R0902
self.xsource = xsource
#: A Bcfg2 options dict
- self.setup = setup
+ self.setup = get_option_parser()
#: A set of package names that are deemed "essential" by this
#: source
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py
index 37171e1b1..1ad699208 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py
@@ -60,6 +60,7 @@ import logging
import lxml.etree
from subprocess import Popen, PIPE
import Bcfg2.Server.Plugin
+from Bcfg2.Options import get_option_parser
# pylint: disable=W0622
from Bcfg2.Compat import StringIO, cPickle, HTTPError, URLError, \
ConfigParser, any
@@ -106,13 +107,11 @@ PULPCONFIG = None
HELPER = None
-def _setup_pulp(setup):
+def _setup_pulp():
""" Connect to a Pulp server and pass authentication credentials.
This only needs to be called once, but multiple calls won't hurt
anything.
- :param setup: A Bcfg2 options dict
- :type setup: dict
:returns: :class:`pulp.client.api.server.PulpServer`
"""
global PULPSERVER, PULPCONFIG
@@ -123,6 +122,7 @@ def _setup_pulp(setup):
raise Bcfg2.Server.Plugin.PluginInitError(msg)
if PULPSERVER is None:
+ setup = get_option_parser()
try:
username = setup.cfp.get("packages:pulp", "username")
password = setup.cfp.get("packages:pulp", "password")
@@ -293,7 +293,7 @@ class YumCollection(Collection):
self.cachefile = None
if HAS_PULP and self.has_pulp_sources:
- _setup_pulp(self.setup)
+ _setup_pulp()
if self.pulp_cert_set is None:
certdir = os.path.join(
self.basepath,
@@ -940,13 +940,13 @@ class YumSource(Source):
#: YumSource sets the ``type`` on Package entries to "yum"
ptype = 'yum'
- def __init__(self, basepath, xsource, setup):
- Source.__init__(self, basepath, xsource, setup)
+ def __init__(self, basepath, xsource):
+ Source.__init__(self, basepath, xsource)
self.pulp_id = None
if HAS_PULP and xsource.get("pulp_id"):
self.pulp_id = xsource.get("pulp_id")
- _setup_pulp(self.setup)
+ _setup_pulp()
repoapi = RepositoryAPI()
try:
self.repo = repoapi.repository(self.pulp_id)
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py b/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py
index f30e060bd..db64cf309 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py
@@ -79,8 +79,7 @@ class Packages(Bcfg2.Server.Plugin.Plugin,
#: :class:`Bcfg2.Server.Plugins.Packages.Source.Source` objects for
#: this plugin.
self.sources = PackagesSources(os.path.join(self.data, "sources.xml"),
- self.cachepath, core.fam, self,
- self.core.setup)
+ self.cachepath, core.fam, self)
#: We cache
#: :class:`Bcfg2.Server.Plugins.Packages.Collection.Collection`
diff --git a/src/lib/Bcfg2/Server/Plugins/Properties.py b/src/lib/Bcfg2/Server/Plugins/Properties.py
index 3ebad40e3..24daa2107 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)
@@ -203,53 +203,8 @@ class XMLPropertyFile(Bcfg2.Server.Plugin.StructFile, PropertyFile):
return True
validate_data.__doc__ = PropertyFile.validate_data.__doc__
- def Index(self):
- Bcfg2.Server.Plugin.StructFile.Index(self)
- if HAS_CRYPTO:
- strict = self.xdata.get(
- "decrypt",
- SETUP.cfp.get(Bcfg2.Encryption.CFG_SECTION, "decrypt",
- default="strict")) == "strict"
- for el in self.xdata.xpath("//*[@encrypted]"):
- try:
- el.text = self._decrypt(el).encode('ascii',
- 'xmlcharrefreplace')
- except UnicodeDecodeError:
- LOGGER.info("Properties: Decrypted %s to gibberish, "
- "skipping" % el.tag)
- except Bcfg2.Encryption.EVPError:
- msg = "Properties: Failed to decrypt %s element in %s" % \
- (el.tag, self.name)
- if strict:
- raise PluginExecutionError(msg)
- else:
- LOGGER.warning(msg)
- Index.__doc__ = Bcfg2.Server.Plugin.StructFile.Index.__doc__
-
- def _decrypt(self, element):
- """ Decrypt a single encrypted properties file element """
- if not element.text or not element.text.strip():
- return
- passes = Bcfg2.Encryption.get_passphrases(SETUP)
- try:
- passphrase = passes[element.get("encrypted")]
- try:
- return Bcfg2.Encryption.ssl_decrypt(
- element.text, passphrase,
- algorithm=Bcfg2.Encryption.get_algorithm(SETUP))
- except Bcfg2.Encryption.EVPError:
- # error is raised below
- pass
- except KeyError:
- # bruteforce_decrypt raises an EVPError with a sensible
- # error message, so we just let it propagate up the stack
- return Bcfg2.Encryption.bruteforce_decrypt(
- element.text, passphrases=passes.values(),
- algorithm=Bcfg2.Encryption.get_algorithm(SETUP))
- 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"
@@ -321,10 +276,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/Plugins/SSLCA.py b/src/lib/Bcfg2/Server/Plugins/SSLCA.py
index 0d51adf18..cc1a2ceac 100644
--- a/src/lib/Bcfg2/Server/Plugins/SSLCA.py
+++ b/src/lib/Bcfg2/Server/Plugins/SSLCA.py
@@ -17,6 +17,7 @@ LOGGER = logging.getLogger(__name__)
class SSLCAXMLSpec(Bcfg2.Server.Plugin.StructFile):
""" Base class to handle key.xml and cert.xml """
+ encryption = False
attrs = dict()
tag = None
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..62f749b80 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 load_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 = load_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..3c63cd3f5 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.load_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..0bee7e9b9 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.load_option_parser(optinfo)
setup.hm = " bcfg2-crypt [options] <filename>\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..60b099284 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.load_option_parser(optinfo)
setup.hm = "\n".join([" bcfg2-info [options] [command <command args>]",
"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..557a03405 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.load_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..403775251 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.load_option_parser(optinfo)
+ setup.parse()
# run collector
try:
diff --git a/src/sbin/bcfg2-server b/src/sbin/bcfg2-server
index 8322edeaa..8e96d65f2 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.load_option_parser(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..28023a0f2 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.load_option_parser(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..3d4df3e0b 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py
@@ -1,5 +1,4 @@
import os
-import re
import sys
import copy
import lxml.etree
@@ -21,6 +20,12 @@ from common import *
from TestServer.TestPlugin.Testbase import TestPlugin, TestDebuggable
from TestServer.TestPlugin.Testinterfaces import TestGenerator
+try:
+ from Bcfg2.Encryption import EVPError
+ HAS_CRYPTO = True
+except:
+ HAS_CRYPTO = False
+
def tostring(el):
return lxml.etree.tostring(el, xml_declaration=False).decode('UTF-8')
@@ -674,6 +679,108 @@ class TestStructFile(TestXMLFileBacked):
children[4] = standalone
return (xdata, groups, subgroups, children, subchildren, standalone)
+ def test_Index(self):
+ has_crypto = Bcfg2.Server.Plugin.helpers.HAS_CRYPTO
+ Bcfg2.Server.Plugin.helpers.HAS_CRYPTO = False
+ TestXMLFileBacked.test_Index(self)
+ Bcfg2.Server.Plugin.helpers.HAS_CRYPTO = has_crypto
+
+ @skipUnless(HAS_CRYPTO, "No crypto libraries found, skipping")
+ def test_Index_crypto(self):
+ if not self.test_obj.encryption:
+ return skip("Encryption disabled on %s objects, skipping" %
+ self.test_obj.__name__)
+
+ sf = self.get_obj()
+ sf.setup = Mock()
+ sf.setup.cfp.get.return_value = "strict"
+ sf._decrypt = Mock()
+ sf._decrypt.return_value = 'plaintext'
+ sf.data = '''
+<EncryptedData>
+ <Group name="test">
+ <Datum encrypted="foo">crypted</Datum>
+ </Group>
+ <Group name="test" negate="true">
+ <Datum>plain</Datum>
+ </Group>
+</EncryptedData>'''
+
+ # test successful decryption
+ sf.Index()
+ self.assertItemsEqual(
+ sf._decrypt.call_args_list,
+ [call(el) for el in sf.xdata.xpath("//*[@encrypted]")])
+ for el in sf.xdata.xpath("//*[@encrypted]"):
+ self.assertEqual(el.text, sf._decrypt.return_value)
+
+ # test failed decryption, strict
+ sf._decrypt.reset_mock()
+ sf._decrypt.side_effect = EVPError
+ self.assertRaises(PluginExecutionError, sf.Index)
+
+ # test failed decryption, lax
+ sf.setup.cfp.get.return_value = "lax"
+ sf._decrypt.reset_mock()
+ sf.Index()
+ self.assertItemsEqual(
+ sf._decrypt.call_args_list,
+ [call(el) for el in sf.xdata.xpath("//*[@encrypted]")])
+
+ @skipUnless(HAS_CRYPTO, "No crypto libraries found, skipping")
+ @patchIf(HAS_CRYPTO, "Bcfg2.Encryption.ssl_decrypt")
+ @patchIf(HAS_CRYPTO, "Bcfg2.Encryption.get_passphrases")
+ @patchIf(HAS_CRYPTO, "Bcfg2.Encryption.bruteforce_decrypt")
+ def test_decrypt(self, mock_bruteforce, mock_get_passphrases, mock_ssl):
+ sf = self.get_obj()
+
+ def reset():
+ mock_bruteforce.reset_mock()
+ mock_get_passphrases.reset_mock()
+ mock_ssl.reset_mock()
+
+ # test element without text contents
+ self.assertIsNone(sf._decrypt(lxml.etree.Element("Test")))
+ self.assertFalse(mock_bruteforce.called)
+ self.assertFalse(mock_get_passphrases.called)
+ self.assertFalse(mock_ssl.called)
+
+ # test element with a passphrase in the config file
+ reset()
+ el = lxml.etree.Element("Test", encrypted="foo")
+ el.text = "crypted"
+ mock_get_passphrases.return_value = dict(foo="foopass", bar="barpass")
+ mock_ssl.return_value = "decrypted with ssl"
+ self.assertEqual(sf._decrypt(el), mock_ssl.return_value)
+ 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, sf._decrypt, el)
+ mock_get_passphrases.assert_called_with()
+ mock_ssl.assert_called_with(el.text, "foopass")
+ self.assertFalse(mock_bruteforce.called)
+
+ # test element without valid passphrase
+ reset()
+ el.set("encrypted", "true")
+ mock_bruteforce.return_value = "decrypted with bruteforce"
+ self.assertEqual(sf._decrypt(el), mock_bruteforce.return_value)
+ mock_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, sf._decrypt, el)
+ mock_get_passphrases.assert_called_with()
+ mock_bruteforce.assert_called_with(el.text)
+ self.assertFalse(mock_ssl.called)
+
def test_include_element(self):
sf = self.get_obj()
metadata = Mock()
@@ -1716,16 +1823,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 +1848,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
@@ -27,15 +27,12 @@ if can_skip or HAS_CRYPTO:
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..bf34d4c3c 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,136 +301,8 @@ 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()
- def test_Index(self):
- has_crypto = Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.HAS_CRYPTO
- Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.HAS_CRYPTO = False
- TestStructFile.test_Index(self)
- Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.HAS_CRYPTO = has_crypto
-
- @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._decrypt = Mock()
- pkc._decrypt.return_value = 'plaintext'
- pkc.data = '''
-<PrivateKey>
- <Group name="test">
- <Passphrase encrypted="foo">crypted</Passphrase>
- </Group>
- <Group name="test" negate="true">
- <Passphrase>plain</Passphrase>
- </Group>
-</PrivateKey>'''
-
- # test successful decryption
- pkc.Index()
- self.assertItemsEqual(
- pkc._decrypt.call_args_list,
- [call(el)
- for el in pkc.xdata.xpath("//Passphrase[@encrypted]")])
- for el in pkc.xdata.xpath("//Crypted"):
- self.assertEqual(el.text, pkc._decrypt.return_value)
-
- # test failed decryption, strict
- pkc._decrypt.reset_mock()
- pkc._decrypt.side_effect = EVPError
- self.assertRaises(PluginExecutionError, pkc.Index)
-
- # test failed decryption, lax
- Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.SETUP.cfp.get.return_value = "lax"
- pkc._decrypt.reset_mock()
- pkc.Index()
- self.assertItemsEqual(
- pkc._decrypt.call_args_list,
- [call(el)
- for el in pkc.xdata.xpath("//Passphrase[@encrypted]")])
-
- @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):
- 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()
-
- # test element without text contents
- self.assertIsNone(pkc._decrypt(lxml.etree.Element("Test")))
- self.assertFalse(mock_bruteforce.called)
- self.assertFalse(mock_get_passphrases.called)
- self.assertFalse(mock_ssl.called)
-
- # test element with a passphrase in the config file
- 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_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")
- 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")
- self.assertFalse(mock_bruteforce.called)
-
- # test element without valid passphrase
- reset()
- 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")
- 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")
- 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..b63d08524 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestProperties.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestProperties.py
@@ -19,12 +19,6 @@ from TestPlugin import TestStructFile, TestFileBacked, TestConnector, \
TestPlugin, TestDirectoryBacked
try:
- from Bcfg2.Encryption import EVPError
- HAS_CRYPTO = True
-except:
- HAS_CRYPTO = False
-
-try:
import json
JSON = "json"
except ImportError:
@@ -41,10 +35,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("<Properties/>\n")
pf.xdata = lxml.etree.XML(xstr)
@@ -52,20 +46,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()
@@ -243,189 +237,61 @@ class TestXMLPropertyFile(TestPropertyFile, TestStructFile):
mock_exists.assert_called_with(schemafile)
mock_XMLSchema.assert_called_with(file=schemafile)
- def test_Index(self):
- TestStructFile.test_Index(self)
-
- pf = self.get_obj()
- pf.xdata = lxml.etree.Element("Properties")
- lxml.etree.SubElement(pf.xdata, "Crypted", encrypted="foo")
- pf.data = lxml.etree.tostring(pf.xdata)
- # extra test: crypto is not available, but properties file is
- # encrypted
- has_crypto = Bcfg2.Server.Plugins.Properties.HAS_CRYPTO
- Bcfg2.Server.Plugins.Properties.HAS_CRYPTO = False
- try:
- self.assertRaises(PluginExecutionError, pf.Index)
- finally:
- Bcfg2.Server.Plugins.Properties.HAS_CRYPTO = has_crypto
-
- @skipUnless(HAS_CRYPTO, "No crypto libraries found, skipping")
- def test_Index_crypto(self):
- pf = self.get_obj()
- pf._decrypt = Mock()
- pf._decrypt.return_value = 'plaintext'
- pf.data = '''
-<Properties decrypt="strict">
- <Crypted encrypted="foo">
- crypted
- <Plain foo="bar">plain</Plain>
- </Crypted>
- <Crypted encrypted="bar">crypted</Crypted>
- <Plain bar="baz">plain</Plain>
- <Plain>
- <Crypted encrypted="foo">crypted</Crypted>
- </Plain>
-</Properties>'''
-
- print "HAS_CRYPTO: %s" % HAS_CRYPTO
- print "Properties HAS_CRYPTO: %s" % Bcfg2.Server.Plugins.Properties.HAS_CRYPTO
-
- # test successful decryption
- pf.Index()
- self.assertItemsEqual(pf._decrypt.call_args_list,
- [call(el) for el in pf.xdata.xpath("//Crypted")])
- for el in pf.xdata.xpath("//Crypted"):
- self.assertEqual(el.text, pf._decrypt.return_value)
-
- # test failed decryption, strict
- pf._decrypt.reset_mock()
- pf._decrypt.side_effect = EVPError
- self.assertRaises(PluginExecutionError, pf.Index)
-
- # test failed decryption, lax
- pf.data = pf.data.replace("strict", "lax")
- pf._decrypt.reset_mock()
- pf.Index()
- self.assertItemsEqual(pf._decrypt.call_args_list,
- [call(el) for el in pf.xdata.xpath("//Crypted")])
-
- @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):
- 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()
-
- # test element without text contents
- self.assertIsNone(pf._decrypt(lxml.etree.Element("Test")))
- self.assertFalse(mock_bruteforce.called)
- self.assertFalse(mock_get_passphrases.called)
- self.assertFalse(mock_ssl.called)
-
- # test element with a passphrase in the config file
- 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_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")
- 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")
- self.assertFalse(mock_bruteforce.called)
-
- # test element without valid passphrase
- reset()
- 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")
- 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")
- 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 +315,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):