summaryrefslogtreecommitdiffstats
path: root/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py
diff options
context:
space:
mode:
authorChris St. Pierre <chris.a.st.pierre@gmail.com>2013-08-08 13:35:20 -0400
committerChris St. Pierre <chris.a.st.pierre@gmail.com>2013-08-08 13:35:20 -0400
commit73c61dd6c0c464f06637db750484417bc8bbb6de (patch)
tree01381b324b6e0a44ebe49660752f31a4abca648a /src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py
parente1e194a573b3803fa7f45a646bbb36b2f164a3e1 (diff)
parentcd14868d4db8eaa7e9421e1d5fe8653294ac1e38 (diff)
downloadbcfg2-73c61dd6c0c464f06637db750484417bc8bbb6de.tar.gz
bcfg2-73c61dd6c0c464f06637db750484417bc8bbb6de.tar.bz2
bcfg2-73c61dd6c0c464f06637db750484417bc8bbb6de.zip
Merge branch 'options-rewrite'
Conflicts: src/lib/Bcfg2/Client/Frame.py src/lib/Bcfg2/Options.py src/lib/Bcfg2/Server/Admin/Init.py src/lib/Bcfg2/Server/Admin/Xcmd.py src/lib/Bcfg2/Server/BuiltinCore.py src/lib/Bcfg2/Server/Core.py src/lib/Bcfg2/Server/MultiprocessingCore.py src/lib/Bcfg2/Server/Plugin/base.py src/lib/Bcfg2/Server/Plugin/helpers.py src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py src/lib/Bcfg2/Server/Plugins/Packages/Yum.py src/lib/Bcfg2/Server/Plugins/Packages/__init__.py src/lib/Bcfg2/Server/SSLServer.py src/lib/Bcfg2/Utils.py src/lib/Bcfg2/settings.py src/sbin/bcfg2-crypt src/sbin/bcfg2-info src/sbin/bcfg2-lint src/sbin/bcfg2-test src/sbin/bcfg2-yum-helper tools/bcfg2-profile-templates.py
Diffstat (limited to 'src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py')
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py198
1 files changed, 48 insertions, 150 deletions
diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py b/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py
index fc3de3d68..a7fa92201 100644
--- a/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py
+++ b/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py
@@ -3,18 +3,14 @@
import re
import os
import sys
-import stat
import errno
import operator
import lxml.etree
import Bcfg2.Options
import Bcfg2.Server.Plugin
-import Bcfg2.Server.Lint
-from fnmatch import fnmatch
from Bcfg2.Server.Plugin import PluginExecutionError
# pylint: disable=W0622
-from Bcfg2.Compat import u_str, unicode, b64encode, walk_packages, \
- any, oct_mode
+from Bcfg2.Compat import u_str, unicode, b64encode, any, oct_mode
# pylint: enable=W0622
#: CFG is a reference to the :class:`Bcfg2.Server.Plugins.Cfg.Cfg`
@@ -25,27 +21,8 @@ from Bcfg2.Compat import u_str, unicode, b64encode, walk_packages, \
#: facility for passing it otherwise.
CFG = None
-_HANDLERS = []
-
-def handlers():
- """ A list of Cfg handler classes. Loading the handlers must
- be done at run-time, not at compile-time, or it causes a
- circular import and Bad Things Happen."""
- if not _HANDLERS:
- for submodule in walk_packages(path=__path__, prefix=__name__ + "."):
- mname = submodule[1].rsplit('.', 1)[-1]
- module = getattr(__import__(submodule[1]).Server.Plugins.Cfg,
- mname)
- hdlr = getattr(module, mname)
- if issubclass(hdlr, CfgBaseFileMatcher):
- _HANDLERS.append(hdlr)
- _HANDLERS.sort(key=operator.attrgetter("__priority__"))
- return _HANDLERS
-
-
-class CfgBaseFileMatcher(Bcfg2.Server.Plugin.SpecificData,
- Bcfg2.Server.Plugin.Debuggable):
+class CfgBaseFileMatcher(Bcfg2.Server.Plugin.SpecificData):
""" .. currentmodule:: Bcfg2.Server.Plugins.Cfg
CfgBaseFileMatcher is the parent class for all Cfg handler
@@ -89,12 +66,8 @@ class CfgBaseFileMatcher(Bcfg2.Server.Plugin.SpecificData,
#: Flag to indicate an experimental handler.
experimental = False
- def __init__(self, name, specific, encoding):
- Bcfg2.Server.Plugin.SpecificData.__init__(self, name, specific,
- encoding)
- Bcfg2.Server.Plugin.Debuggable.__init__(self)
- self.encoding = encoding
- self.setup = Bcfg2.Options.get_option_parser()
+ def __init__(self, name, specific):
+ Bcfg2.Server.Plugin.SpecificData.__init__(self, name, specific)
__init__.__doc__ = Bcfg2.Server.Plugin.SpecificData.__init__.__doc__ + \
"""
.. -----
@@ -185,7 +158,7 @@ class CfgGenerator(CfgBaseFileMatcher):
client. See :class:`Bcfg2.Server.Plugin.helpers.EntrySet` for more
details on how the best handler is chosen."""
- def __init__(self, name, specific, encoding):
+ def __init__(self, name, specific):
# we define an __init__ that just calls the parent __init__,
# so that we can set the docstring on __init__ to something
# different from the parent __init__ -- namely, the parent
@@ -193,7 +166,7 @@ class CfgGenerator(CfgBaseFileMatcher):
# which we use to delineate the actual docs from the
# .. autoattribute hacks we have to do to get private
# attributes included in sphinx 1.0 """
- CfgBaseFileMatcher.__init__(self, name, specific, encoding)
+ CfgBaseFileMatcher.__init__(self, name, specific)
__init__.__doc__ = CfgBaseFileMatcher.__init__.__doc__.split(".. -----")[0]
def get_data(self, entry, metadata): # pylint: disable=W0613
@@ -213,9 +186,9 @@ class CfgFilter(CfgBaseFileMatcher):
""" CfgFilters modify the initial content of a file after it has
been generated by a :class:`Bcfg2.Server.Plugins.Cfg.CfgGenerator`. """
- def __init__(self, name, specific, encoding):
+ def __init__(self, name, specific):
# see comment on CfgGenerator.__init__ above
- CfgBaseFileMatcher.__init__(self, name, specific, encoding)
+ CfgBaseFileMatcher.__init__(self, name, specific)
__init__.__doc__ = CfgBaseFileMatcher.__init__.__doc__.split(".. -----")[0]
def modify_data(self, entry, metadata, data):
@@ -253,7 +226,7 @@ class CfgInfo(CfgBaseFileMatcher):
.. -----
.. autoattribute:: Bcfg2.Server.Plugins.Cfg.CfgInfo.__specific__
"""
- CfgBaseFileMatcher.__init__(self, fname, None, None)
+ CfgBaseFileMatcher.__init__(self, fname, None)
def bind_info_to_entry(self, entry, metadata):
""" Assign the appropriate attributes to the entry, modifying
@@ -276,9 +249,9 @@ class CfgVerifier(CfgBaseFileMatcher):
etc.), or both.
"""
- def __init__(self, name, specific, encoding):
+ def __init__(self, name, specific):
# see comment on CfgGenerator.__init__ above
- CfgBaseFileMatcher.__init__(self, name, specific, encoding)
+ CfgBaseFileMatcher.__init__(self, name, specific)
__init__.__doc__ = CfgBaseFileMatcher.__init__.__doc__.split(".. -----")[0]
def verify_entry(self, entry, metadata, data):
@@ -317,7 +290,7 @@ class CfgCreator(CfgBaseFileMatcher):
.. -----
.. autoattribute:: Bcfg2.Server.Plugins.Cfg.CfgCreator.__specific__
"""
- CfgBaseFileMatcher.__init__(self, fname, None, None)
+ CfgBaseFileMatcher.__init__(self, fname, None)
def create_data(self, entry, metadata):
""" Create new data for the given entry and write it to disk
@@ -431,26 +404,30 @@ class CfgDefaultInfo(CfgInfo):
bind_info_to_entry.__doc__ = CfgInfo.bind_info_to_entry.__doc__
-class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet,
- Bcfg2.Server.Plugin.Debuggable):
+class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet):
""" Handle a collection of host- and group-specific Cfg files with
multiple different Cfg handlers in a single directory. """
- def __init__(self, basename, path, entry_type, encoding):
- Bcfg2.Server.Plugin.EntrySet.__init__(self, basename, path,
- entry_type, encoding)
- Bcfg2.Server.Plugin.Debuggable.__init__(self)
+ def __init__(self, basename, path, entry_type):
+ Bcfg2.Server.Plugin.EntrySet.__init__(self, basename, path, entry_type)
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):
- rv = Bcfg2.Server.Plugin.Debuggable.set_debug(self, debug)
+ rv = Bcfg2.Server.Plugin.EntrySet.set_debug(self, debug)
for entry in self.entries.values():
entry.set_debug(debug)
return rv
+ @property
+ def handlers(self):
+ """ A list of Cfg handler classes. """
+ if self._handlers is None:
+ self._handlers = Bcfg2.Options.setup.cfg_handlers
+ self._handlers.sort(key=operator.attrgetter("__priority__"))
+ return self._handlers
+
def handle_event(self, event):
""" Dispatch a FAM event to :func:`entry_init` or the
appropriate child handler object.
@@ -467,7 +444,7 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet,
# process a bogus changed event like a created
return
- for hdlr in handlers():
+ for hdlr in self.handlers:
if hdlr.handles(event, basename=self.path):
if action == 'changed':
# warn about a bogus 'changed' event, but
@@ -560,7 +537,7 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet,
# most specific to least specific.
data = fltr.modify_data(entry, metadata, data)
- if self.setup['validate']:
+ if Bcfg2.Options.setup.cfg_validation:
try:
self._validate_data(entry, metadata, data)
except CfgVerificationError:
@@ -576,7 +553,7 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet,
if not isinstance(data, unicode):
if not isinstance(data, str):
data = data.decode('utf-8')
- data = u_str(data, self.encoding)
+ data = u_str(data, Bcfg2.Options.setup.encoding)
except UnicodeDecodeError:
msg = "Failed to decode %s: %s" % (entry.get('name'),
sys.exc_info()[1])
@@ -757,10 +734,10 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet,
self.logger.error(msg)
raise PluginExecutionError(msg)
try:
- etext = new_entry['text'].encode(self.encoding)
+ etext = new_entry['text'].encode(Bcfg2.Options.setup.encoding)
except:
msg = "Cfg: Cannot encode content of %s as %s" % \
- (name, self.encoding)
+ (name, Bcfg2.Options.setup.encoding)
self.logger.error(msg)
raise PluginExecutionError(msg)
open(name, 'w').write(etext)
@@ -785,6 +762,10 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet,
flag=log)
+class CfgHandlerAction(Bcfg2.Options.ComponentAction):
+ bases = ['Bcfg2.Server.Plugins.Cfg']
+
+
class Cfg(Bcfg2.Server.Plugin.GroupSpool,
Bcfg2.Server.Plugin.PullTarget):
""" The Cfg plugin provides a repository to describe configuration
@@ -796,17 +777,27 @@ class Cfg(Bcfg2.Server.Plugin.GroupSpool,
es_cls = CfgEntrySet
es_child_cls = Bcfg2.Server.Plugin.SpecificData
+ options = Bcfg2.Server.Plugin.GroupSpool.options + [
+ Bcfg2.Options.BooleanOption(
+ '--cfg-validation', cf=('cfg', 'validation'), default=True,
+ help='Run validation on Cfg files'),
+ Bcfg2.Options.Option(
+ cf=("cfg", "handlers"), dest="cfg_handlers",
+ help="Cfg handlers to load",
+ type=Bcfg2.Options.Types.comma_list, action=CfgHandlerAction,
+ default=['CfgAuthorizedKeysGenerator', 'CfgEncryptedGenerator',
+ 'CfgCheetahGenerator', 'CfgEncryptedCheetahGenerator',
+ 'CfgGenshiGenerator', 'CfgEncryptedGenshiGenerator',
+ 'CfgExternalCommandVerifier', 'CfgInfoXML',
+ 'CfgPlaintextGenerator',
+ 'CfgPrivateKeyCreator', 'CfgPublicKeyCreator'])]
+
def __init__(self, core, datastore):
global CFG # pylint: disable=W0603
Bcfg2.Server.Plugin.GroupSpool.__init__(self, core, datastore)
Bcfg2.Server.Plugin.PullTarget.__init__(self)
CFG = self
-
- 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):
@@ -840,96 +831,3 @@ class Cfg(Bcfg2.Server.Plugin.GroupSpool,
log)
AcceptPullData.__doc__ = \
Bcfg2.Server.Plugin.PullTarget.AcceptPullData.__doc__
-
-
-class CfgLint(Bcfg2.Server.Lint.ServerPlugin):
- """ warn about usage of .cat and .diff files """
-
- def Run(self):
- for basename, entry in list(self.core.plugins['Cfg'].entries.items()):
- self.check_pubkey(basename, entry)
- self.check_missing_files()
-
- @classmethod
- def Errors(cls):
- return {"no-pubkey-xml": "warning",
- "unknown-cfg-files": "error",
- "extra-cfg-files": "error"}
-
- def check_pubkey(self, basename, entry):
- """ check that privkey.xml files have corresponding pubkey.xml
- files """
- if "privkey.xml" not in entry.entries:
- return
- privkey = entry.entries["privkey.xml"]
- if not self.HandlesFile(privkey.name):
- return
-
- pubkey = basename + ".pub"
- if pubkey not in self.core.plugins['Cfg'].entries:
- self.LintError("no-pubkey-xml",
- "%s has no corresponding pubkey.xml at %s" %
- (basename, pubkey))
- else:
- pubset = self.core.plugins['Cfg'].entries[pubkey]
- if "pubkey.xml" not in pubset.entries:
- self.LintError("no-pubkey-xml",
- "%s has no corresponding pubkey.xml at %s" %
- (basename, pubkey))
-
- def _list_path_components(self, path):
- """ Get a list of all components of a path. E.g.,
- ``self._list_path_components("/foo/bar/foobaz")`` would return
- ``["foo", "bar", "foo", "baz"]``. The list is not guaranteed
- to be in order."""
- rv = []
- remaining, component = os.path.split(path)
- while component != '':
- rv.append(component)
- remaining, component = os.path.split(remaining)
- return rv
-
- def check_missing_files(self):
- """ check that all files on the filesystem are known to Cfg """
- cfg = self.core.plugins['Cfg']
-
- # first, collect ignore patterns from handlers
- ignore = set()
- for hdlr in handlers():
- ignore.update(hdlr.__ignore__)
-
- # next, get a list of all non-ignored files on the filesystem
- all_files = set()
- for root, _, files in os.walk(cfg.data):
- for fname in files:
- fpath = os.path.join(root, fname)
- # check against the handler ignore patterns and the
- # global FAM ignore list
- if (not any(fname.endswith("." + i) for i in ignore) and
- not any(fnmatch(fpath, p)
- for p in self.config['ignore']) and
- not any(fnmatch(c, p)
- for p in self.config['ignore']
- for c in self._list_path_components(fpath))):
- all_files.add(fpath)
-
- # next, get a list of all files known to Cfg
- cfg_files = set()
- for root, eset in cfg.entries.items():
- cfg_files.update(os.path.join(cfg.data, root.lstrip("/"), fname)
- for fname in eset.entries.keys())
-
- # finally, compare the two
- unknown_files = all_files - cfg_files
- extra_files = cfg_files - all_files
- if unknown_files:
- self.LintError(
- "unknown-cfg-files",
- "Files on the filesystem could not be understood by Cfg: %s" %
- "; ".join(unknown_files))
- if extra_files:
- self.LintError(
- "extra-cfg-files",
- "Cfg has entries for files that do not exist on the "
- "filesystem: %s\nThis is probably a bug." %
- "; ".join(extra_files))