summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/lib/Bcfg2/Client/Tools/Action.py2
-rw-r--r--src/lib/Bcfg2/Client/Tools/DebInit.py5
-rw-r--r--src/lib/Bcfg2/Client/Tools/POSIXUsers.py1
-rw-r--r--src/lib/Bcfg2/Options/Actions.py4
-rw-r--r--src/lib/Bcfg2/Options/Common.py2
-rw-r--r--src/lib/Bcfg2/Options/OptionGroups.py7
-rw-r--r--src/lib/Bcfg2/Options/Options.py10
-rw-r--r--src/lib/Bcfg2/Options/Parser.py22
-rw-r--r--src/lib/Bcfg2/Options/Types.py2
-rw-r--r--src/lib/Bcfg2/Server/Admin.py56
-rwxr-xr-xsrc/lib/Bcfg2/Server/Encryption.py5
-rw-r--r--src/lib/Bcfg2/Server/Info.py26
-rw-r--r--src/lib/Bcfg2/Server/Lint/Bundler.py3
-rw-r--r--src/lib/Bcfg2/Server/Lint/Cfg.py12
-rwxr-xr-xsrc/lib/Bcfg2/Server/Lint/Genshi.py1
-rw-r--r--src/lib/Bcfg2/Server/Lint/GroupPatterns.py3
-rw-r--r--src/lib/Bcfg2/Server/Lint/MergeFiles.py8
-rw-r--r--src/lib/Bcfg2/Server/Lint/Metadata.py3
-rw-r--r--src/lib/Bcfg2/Server/Lint/Pkgmgr.py3
-rw-r--r--src/lib/Bcfg2/Server/Lint/TemplateHelper.py3
-rw-r--r--src/lib/Bcfg2/Server/Lint/__init__.py3
-rw-r--r--src/lib/Bcfg2/Server/MultiprocessingCore.py3
-rw-r--r--src/lib/Bcfg2/Server/Plugin/__init__.py2
-rw-r--r--src/lib/Bcfg2/Server/Plugin/helpers.py1
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py11
-rw-r--r--src/lib/Bcfg2/Server/Plugins/FileProbes.py4
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Metadata.py8
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Collection.py1
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Source.py1
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/YumHelper.py17
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/__init__.py3
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Probes.py5
-rw-r--r--src/lib/Bcfg2/Server/Plugins/SSHbase.py4
-rw-r--r--src/lib/Bcfg2/Server/Test.py2
-rw-r--r--testsuite/requirements.txt1
35 files changed, 176 insertions, 68 deletions
diff --git a/src/lib/Bcfg2/Client/Tools/Action.py b/src/lib/Bcfg2/Client/Tools/Action.py
index 921d5723e..db1ff500e 100644
--- a/src/lib/Bcfg2/Client/Tools/Action.py
+++ b/src/lib/Bcfg2/Client/Tools/Action.py
@@ -1,7 +1,5 @@
"""Action driver"""
-import os
-import sys
import Bcfg2.Client.Tools
from Bcfg2.Utils import safe_input
from Bcfg2.Client import matches_white_list, passes_black_list
diff --git a/src/lib/Bcfg2/Client/Tools/DebInit.py b/src/lib/Bcfg2/Client/Tools/DebInit.py
index b544e44d4..0433ac80d 100644
--- a/src/lib/Bcfg2/Client/Tools/DebInit.py
+++ b/src/lib/Bcfg2/Client/Tools/DebInit.py
@@ -3,6 +3,7 @@
import glob
import os
import re
+import Bcfg2.Options
import Bcfg2.Client.Tools
# Debian squeeze and beyond uses a dependecy based boot sequence
@@ -137,10 +138,10 @@ class DebInit(Bcfg2.Client.Tools.SvcTool):
bootcmd = '/usr/sbin/update-rc.d -f %s remove' % \
entry.get('name')
bootcmdrv = self.cmd.run(bootcmd)
- if self.setup['servicemode'] == 'disabled':
+ if Bcfg2.Options.setup.service_mode == 'disabled':
# 'disabled' means we don't attempt to modify running svcs
return bootcmdrv and seqcmdrv
- buildmode = self.setup['servicemode'] == 'build'
+ buildmode = Bcfg2.Options.setup.service_mode == 'build'
if (entry.get('status') == 'on' and not buildmode) and \
entry.get('current_status') == 'off':
svccmdrv = self.start_service(entry)
diff --git a/src/lib/Bcfg2/Client/Tools/POSIXUsers.py b/src/lib/Bcfg2/Client/Tools/POSIXUsers.py
index 19657f12a..aeafc3817 100644
--- a/src/lib/Bcfg2/Client/Tools/POSIXUsers.py
+++ b/src/lib/Bcfg2/Client/Tools/POSIXUsers.py
@@ -9,6 +9,7 @@ from Bcfg2.Utils import PackedDigitRange
def uid_range_type(val):
+ """ Option type to unpack a list of numerical ranges """
return PackedDigitRange(*Bcfg2.Options.Types.comma_list(val))
diff --git a/src/lib/Bcfg2/Options/Actions.py b/src/lib/Bcfg2/Options/Actions.py
index 7a30d9623..637a09577 100644
--- a/src/lib/Bcfg2/Options/Actions.py
+++ b/src/lib/Bcfg2/Options/Actions.py
@@ -2,7 +2,7 @@
import sys
import argparse
-from Parser import get_parser
+from Parser import get_parser # pylint: disable=W0403
__all__ = ["ConfigFileAction", "ComponentAction", "PluginsAction"]
@@ -88,6 +88,8 @@ class ComponentAction(argparse.Action):
argparse.Action.__init__(self, *args, **kwargs)
def _import(self, module, name):
+ """ Import the given name from the given module, handling
+ errors """
try:
return getattr(__import__(module, fromlist=[name]), name)
except (AttributeError, ImportError):
diff --git a/src/lib/Bcfg2/Options/Common.py b/src/lib/Bcfg2/Options/Common.py
index 302be61f4..b44c58990 100644
--- a/src/lib/Bcfg2/Options/Common.py
+++ b/src/lib/Bcfg2/Options/Common.py
@@ -1,9 +1,11 @@
""" Common options used in multiple different contexts. """
+# pylint: disable=W0403
import Types
from Actions import PluginsAction, ComponentAction
from Parser import repository as _repository_option
from Options import Option, PathOption, BooleanOption
+# pylint: enable=W0403
__all__ = ["Common"]
diff --git a/src/lib/Bcfg2/Options/OptionGroups.py b/src/lib/Bcfg2/Options/OptionGroups.py
index 537deaa61..6cbe1a8e3 100644
--- a/src/lib/Bcfg2/Options/OptionGroups.py
+++ b/src/lib/Bcfg2/Options/OptionGroups.py
@@ -3,17 +3,12 @@
import re
import copy
import fnmatch
-from Options import Option
+from Options import Option # pylint: disable=W0403
from itertools import chain
__all__ = ["OptionGroup", "ExclusiveOptionGroup", "Subparser",
"WildcardSectionGroup"]
-#: A dict that records a mapping of argparse action name (e.g.,
-#: "store_true") to the argparse Action class for it. See
-#: :func:`_get_action_class`
-_action_map = dict()
-
class OptionContainer(list):
""" Parent class of all option groups """
diff --git a/src/lib/Bcfg2/Options/Options.py b/src/lib/Bcfg2/Options/Options.py
index ca0261907..d60c536cf 100644
--- a/src/lib/Bcfg2/Options/Options.py
+++ b/src/lib/Bcfg2/Options/Options.py
@@ -4,7 +4,7 @@ need to be associated with an option parser; it exists on its own."""
import os
import copy
-import Types
+import Types # pylint: disable=W0403
import fnmatch
import argparse
from Bcfg2.Compat import ConfigParser
@@ -15,7 +15,7 @@ __all__ = ["Option", "BooleanOption", "PathOption", "PositionalArgument"]
#: A dict that records a mapping of argparse action name (e.g.,
#: "store_true") to the argparse Action class for it. See
#: :func:`_get_action_class`
-_action_map = dict()
+_action_map = dict() # pylint: disable=C0103
def _get_action_class(action_name):
@@ -82,7 +82,7 @@ class Option(object):
#: The tuple giving the section and option name for this
#: option in the config file
- self.cf = None
+ self.cf = None # pylint: disable=C0103
#: The environment variable that this option can take its
#: value from
@@ -214,9 +214,11 @@ class Option(object):
self.default = val
def _get_default(self):
+ """ Getter for the ``default`` property """
return self._default
def _set_default(self, value):
+ """ Setter for the ``default`` property """
self._default = value
for action in self.actions.values():
action.default = value
@@ -225,9 +227,11 @@ class Option(object):
default = property(_get_default, _set_default)
def _get_dest(self):
+ """ Getter for the ``dest`` property """
return self._dest
def _set_dest(self, value):
+ """ Setter for the ``dest`` property """
self._dest = value
for action in self.actions.values():
action.dest = value
diff --git a/src/lib/Bcfg2/Options/Parser.py b/src/lib/Bcfg2/Options/Parser.py
index 343399db9..dd7874d35 100644
--- a/src/lib/Bcfg2/Options/Parser.py
+++ b/src/lib/Bcfg2/Options/Parser.py
@@ -5,7 +5,7 @@ import sys
import argparse
from Bcfg2.version import __version__
from Bcfg2.Compat import ConfigParser
-from Options import Option, PathOption, BooleanOption
+from Options import Option, PathOption, BooleanOption # pylint: disable=W0403
__all__ = ["setup", "OptionParserException", "Parser", "get_parser"]
@@ -13,14 +13,14 @@ __all__ = ["setup", "OptionParserException", "Parser", "get_parser"]
#: The repository option. This is specified here (and imported into
#: :module:`Bcfg2.Options.Common`) rather than vice-versa due to
#: circular imports.
-repository = PathOption(
+repository = PathOption( # pylint: disable=C0103
'-Q', '--repository', cf=('server', 'repository'),
default='var/lib/bcfg2', help="Server repository path")
#: A module-level :class:`argparse.Namespace` object that stores all
#: configuration for Bcfg2.
-setup = argparse.Namespace(version=__version__,
+setup = argparse.Namespace(version=__version__, # pylint: disable=C0103
name="Bcfg2",
uri='http://trac.mcs.anl.gov/projects/bcfg2')
@@ -115,6 +115,9 @@ class Parser(argparse.ArgumentParser):
self.add_options(getattr(component, "options"))
def _set_defaults(self):
+ """ Set defaults from the config file for all options that can
+ come from the config file, but haven't yet had their default
+ set """
for opt in self.option_list:
if opt not in self._defaults_set:
opt.default_from_config(self._cfp)
@@ -137,10 +140,16 @@ class Parser(argparse.ArgumentParser):
setattr(self.namespace, opt.dest, value)
def _finalize(self):
+ """ Finalize the value of any options that require that
+ additional post-processing step. (Mostly
+ :class:`Bcfg2.Options.Actions.ComponentAction` subclasses.)
+ """
for opt in self.option_list[:]:
opt.finalize(self.namespace)
def _reset_namespace(self):
+ """ Delete all options from the namespace except for a few
+ predefined values and config file options. """
self.parsed = False
for attr in dir(self.namespace):
if (not attr.startswith("_") and
@@ -200,11 +209,10 @@ class Parser(argparse.ArgumentParser):
# components, until all components have been loaded. On each
# iteration, set defaults from config file/environment
# variables
- remaining = self.argv
while not self.parsed:
self.parsed = True
self._set_defaults()
- self.parse_known_args(namespace=self.namespace)[1]
+ self.parse_known_args(namespace=self.namespace)
self._parse_config_options()
self._finalize()
self._parse_config_options()
@@ -227,7 +235,7 @@ class Parser(argparse.ArgumentParser):
#: A module-level :class:`Bcfg2.Options.Parser` object that is used
#: for all parsing
-_parser = Parser()
+_parser = Parser() # pylint: disable=C0103
#: Track whether or not the module-level parser has been initialized
#: yet. We track this separately because some things (e.g., modules
@@ -235,7 +243,7 @@ _parser = Parser()
#: been initialized, so we can't just set
#: :attr:`Bcfg2.Options._parser` to None and wait for
#: :func:`Bcfg2.Options.get_parser` to be called.
-_parser_initialized = False
+_parser_initialized = False # pylint: disable=C0103
def get_parser(description=None, components=None, namespace=None):
diff --git a/src/lib/Bcfg2/Options/Types.py b/src/lib/Bcfg2/Options/Types.py
index 5769d674a..2f0fd7d52 100644
--- a/src/lib/Bcfg2/Options/Types.py
+++ b/src/lib/Bcfg2/Options/Types.py
@@ -83,6 +83,7 @@ def timeout(value):
return rv
+# pylint: disable=C0103
_bytes_multipliers = dict(k=1,
m=2,
g=3,
@@ -90,6 +91,7 @@ _bytes_multipliers = dict(k=1,
_suffixes = "".join(_bytes_multipliers.keys()).lower()
_suffixes += _suffixes.upper()
_bytes_re = re.compile(r'(?P<value>\d+)(?P<multiplier>[%s])?' % _suffixes)
+# pylint: enable=C0103
def size(value):
diff --git a/src/lib/Bcfg2/Server/Admin.py b/src/lib/Bcfg2/Server/Admin.py
index 7c2241f58..62b5cd0ac 100644
--- a/src/lib/Bcfg2/Server/Admin.py
+++ b/src/lib/Bcfg2/Server/Admin.py
@@ -39,7 +39,8 @@ except ImportError:
HAS_REPORTS = False
-class ccolors:
+class ccolors: # pylint: disable=C0103
+ """ ANSI color escapes to make colorizing text easier """
# pylint: disable=W1401
ADDED = '\033[92m'
CHANGED = '\033[93m'
@@ -47,8 +48,9 @@ class ccolors:
ENDC = '\033[0m'
# pylint: enable=W1401
- @staticmethod
+ @classmethod
def disable(cls):
+ """ Disable all coloration """
cls.ADDED = ''
cls.CHANGED = ''
cls.REMOVED = ''
@@ -94,6 +96,7 @@ def print_table(rows, justify='left', hdr=True, vdelim=" ", padding=1):
class AdminCmd(Bcfg2.Options.Subcommand):
+ """ Base class for all bcfg2-admin modes """
def setup(self):
""" Perform post-init (post-options parsing), pre-run setup
tasks """
@@ -106,12 +109,16 @@ class AdminCmd(Bcfg2.Options.Subcommand):
class _ServerAdminCmd(AdminCmd):
- """Base class for admin modes that run a Bcfg2 server."""
+ """ Base class for admin modes that run a Bcfg2 server. """
__plugin_whitelist__ = None
__plugin_blacklist__ = None
options = AdminCmd.options + Bcfg2.Server.Core.Core.options
+ def __init__(self):
+ AdminCmd.__init__(self)
+ self.metadata = None
+
def setup(self):
if self.__plugin_whitelist__ is not None:
Bcfg2.Options.setup.plugins = [
@@ -224,23 +231,28 @@ class Compare(AdminCmd):
changes = dict()
def removed(self, msg, host):
+ """ Record a removed element """
self.record("%sRemoved: %s%s" % (ccolors.REMOVED, msg, ccolors.ENDC),
host)
def added(self, msg, host):
+ """ Record an removed element """
self.record("%sAdded: %s%s" % (ccolors.ADDED, msg, ccolors.ENDC), host)
def changed(self, msg, host):
+ """ Record a changed element """
self.record("%sChanged: %s%s" % (ccolors.CHANGED, msg, ccolors.ENDC),
host)
def record(self, msg, host):
+ """ Record a new removed/added/changed message for the given
+ host """
if msg not in self.changes:
self.changes[msg] = [host]
else:
self.changes[msg].append(host)
- def udiff(self, l1, l2, **kwargs):
+ def udiff(self, lines1, lines2, **kwargs):
""" get a unified diff with control lines stripped """
lines = None
if "lines" in kwargs:
@@ -251,7 +263,7 @@ class Compare(AdminCmd):
return []
kwargs['n'] = 0
diff = []
- for line in difflib.unified_diff(l1, l2, **kwargs):
+ for line in difflib.unified_diff(lines1, lines2, **kwargs):
if (line.startswith("--- ") or line.startswith("+++ ") or
line.startswith("@@ ")):
continue
@@ -259,24 +271,23 @@ class Compare(AdminCmd):
diff.append(" ...")
break
if line.startswith("+"):
- for l in line.splitlines():
- diff.append(" %s%s%s" % (ccolors.ADDED, l, ccolors.ENDC))
+ diff.extend(" %s%s%s" % (ccolors.ADDED, l, ccolors.ENDC)
+ for l in line.splitlines())
elif line.startswith("-"):
- for l in line.splitlines():
- diff.append(" %s%s%s" % (ccolors.REMOVED, l,
- ccolors.ENDC))
+ diff.extend(" %s%s%s" % (ccolors.REMOVED, l, ccolors.ENDC)
+ for l in line.splitlines())
return diff
def _bundletype(self, el):
+ """ Get a human-friendly representation of the type of the
+ given bundle -- independent or not """
if el.get("tag") == "Independent":
return "Independent bundle"
else:
return "Bundle"
- def run(self, setup):
- if not sys.stdout.isatty() and not setup.color:
- ccolors.disable(ccolors)
-
+ def _get_filelists(self, setup):
+ """ Get a list of 2-tuples of files to compare """
files = []
if os.path.isdir(setup.path1) and os.path.isdir(setup.path1):
for fpath in glob.glob(os.path.join(setup.path1, '*')):
@@ -302,8 +313,13 @@ class Compare(AdminCmd):
files.append((setup.path1, setup.path2))
else:
self.errExit("Cannot diff a file and a directory")
+ return files
+
+ def run(self, setup): # pylint: disable=R0912,R0914,R0915
+ if not sys.stdout.isatty() and not setup.color:
+ ccolors.disable(ccolors)
- for file1, file2 in files:
+ for file1, file2 in self._get_filelists():
host = None
if os.path.basename(file1) == os.path.basename(file2):
fname = os.path.basename(file1)
@@ -400,6 +416,9 @@ class Help(AdminCmd, Bcfg2.Options.HelpCommand):
def command_registry(self):
return CLI.commands
+ def run(self, setup):
+ Bcfg2.Options.HelpCommand.run(self, setup)
+
class Init(AdminCmd):
"""Interactively initialize a new repository."""
@@ -480,6 +499,8 @@ bcfg2 = %s
self.data['certpath'] = os.path.join(basepath, 'bcfg2.crt')
def input_with_default(self, msg, default_name):
+ """ Prompt for input with the given message, taking the
+ default from ``self.data`` """
val = safe_input("%s [%s]: " % (msg, self.data[default_name]))
if val:
self.data[default_name] = val
@@ -803,6 +824,8 @@ class Pull(_ServerAdminCmd):
class _ReportsCmd(AdminCmd):
+ """ Base command for all admin modes dealing with the reporting
+ subsystem """
def __init__(self):
AdminCmd.__init__(self)
self.reports_entries = ()
@@ -832,6 +855,8 @@ class _ReportsCmd(AdminCmd):
if HAS_DJANGO:
class _DjangoProxyCmd(AdminCmd):
+ """ Base for admin modes that proxy a command through the
+ Django management system """
command = None
args = []
@@ -1151,5 +1176,6 @@ class CLI(Bcfg2.Options.CommandRegistry):
parser.parse()
def run(self):
+ """ Run bcfg2-admin """
self.commands[Bcfg2.Options.setup.subcommand].setup()
return self.runcommand()
diff --git a/src/lib/Bcfg2/Server/Encryption.py b/src/lib/Bcfg2/Server/Encryption.py
index 7e1294587..e64a6627f 100755
--- a/src/lib/Bcfg2/Server/Encryption.py
+++ b/src/lib/Bcfg2/Server/Encryption.py
@@ -32,6 +32,8 @@ IV = r'\0' * 16
class _OptionContainer(object):
+ """ Container for options loaded at import-time to configure
+ encryption """
options = [
Bcfg2.Options.BooleanOption(
cf=("encryption", "lax_decryption"),
@@ -371,7 +373,7 @@ class PropertiesCryptoMixin(object):
if pname:
self.logger.warning("Passphrase %s not found in %s, "
"using passphrase given on command line" %
- (pname, Bcfg2.Option.setup.configfile))
+ (pname, Bcfg2.Options.setup.configfile))
passphrase = self.passphrase
pname = self.pname
else:
@@ -502,6 +504,7 @@ class CLI(object):
return False
def run(self): # pylint: disable=R0912,R0915
+ """ Run bcfg2-crypt """
for fname in Bcfg2.Options.setup.files:
if not os.path.exists(fname):
self.logger.error("%s does not exist, skipping" % fname)
diff --git a/src/lib/Bcfg2/Server/Info.py b/src/lib/Bcfg2/Server/Info.py
index 24d7cc637..2b2149606 100644
--- a/src/lib/Bcfg2/Server/Info.py
+++ b/src/lib/Bcfg2/Server/Info.py
@@ -89,6 +89,8 @@ class InfoCmd(Bcfg2.Options.Subcommand):
""" Base class for bcfg2-info subcommands """
def _expand_globs(self, globs, candidates):
+ """ Given a list of globs, select the items from candidates
+ that match the globs """
# special cases to speed things up:
if globs is None or '*' in globs:
return candidates
@@ -264,6 +266,7 @@ class BuildAllMixin(object):
return cls
def run(self, setup):
+ """ Run the command """
try:
os.makedirs(setup.directory)
except OSError:
@@ -278,6 +281,8 @@ class BuildAllMixin(object):
self._parent.run(self, csetup) # pylint: disable=E1101
def _get_setup(self, client, setup):
+ """ This can be overridden by children to populate individual
+ setup options on a per-client basis """
raise NotImplementedError
@@ -335,7 +340,7 @@ class Buildbundle(InfoCmd):
pretty_print=True).decode('UTF-8'))
except: # pylint: disable=W0702
print("Failed to render bundle %s for host %s: %s" %
- (setup.bundle, client, sys.exc_info()[1]))
+ (setup.bundle, setup.hostname, sys.exc_info()[1]))
raise
@@ -379,10 +384,10 @@ class ExpireCache(InfoCmd):
def run(self, setup):
if setup.clients:
for client in self.get_client_list(setup.clients):
- self.expire_caches_by_type(Bcfg2.Server.Plugin.Metadata,
- key=client)
+ self.core.expire_caches_by_type(Bcfg2.Server.Plugin.Metadata,
+ key=client)
else:
- self.expire_caches_by_type(Bcfg2.Server.Plugin.Metadata)
+ self.core.expire_caches_by_type(Bcfg2.Server.Plugin.Metadata)
class Bundles(InfoCmd):
@@ -506,6 +511,7 @@ class Groups(InfoCmd):
options = [Bcfg2.Options.PositionalArgument("group", nargs='*')]
def _profile_flag(self, group):
+ """ Whether or not the group is a profile group """
if self.core.metadata.groups[group].is_profile:
return 'yes'
else:
@@ -681,7 +687,6 @@ class Shell(InfoCmd):
'Type "help" for more information')
except KeyboardInterrupt:
print("Ctrl-C pressed, exiting...")
- loop = False
class ProfileTemplates(InfoCmd):
@@ -699,6 +704,7 @@ class ProfileTemplates(InfoCmd):
help="Profile the named templates instead of all templates")]
def profile_entry(self, entry, metadata, runs=5):
+ """ Profile a single entry """
times = []
for i in range(runs): # pylint: disable=W0612
start = time.time()
@@ -715,6 +721,7 @@ class ProfileTemplates(InfoCmd):
return times
def profile_struct(self, struct, metadata, templates=None, runs=5):
+ """ Profile all entries in a given structure """
times = dict()
entries = struct.xpath("//Path")
entry_count = 0
@@ -730,6 +737,7 @@ class ProfileTemplates(InfoCmd):
return times
def profile_client(self, metadata, templates=None, runs=5):
+ """ Profile all structures for a given client """
structs = self.core.GetStructures(metadata)
struct_count = 0
times = dict()
@@ -744,6 +752,7 @@ class ProfileTemplates(InfoCmd):
return times
def stdev(self, nums):
+ """ Calculate the standard deviation of a list of numbers """
mean = float(sum(nums)) / len(nums)
return math.sqrt(sum((n - mean) ** 2 for n in nums) / float(len(nums)))
@@ -804,6 +813,8 @@ class InfoCore(cmd.Cmd,
self.prompt = 'bcfg2-info> '
def get_locals(self):
+ """ Expose the local variables of the core to subcommands that
+ need to reference them (i.e., the interactive interpreter) """
return locals()
def do_quit(self, _):
@@ -827,9 +838,6 @@ class InfoCore(cmd.Cmd,
self.load_plugins()
self.block_for_fam_events(handle_events=True)
- def _daemonize(self):
- pass
-
def _run(self):
pass
@@ -842,6 +850,7 @@ class InfoCore(cmd.Cmd,
class CLI(object):
+ """ The bcfg2-info CLI """
options = [Bcfg2.Options.BooleanOption("-p", "--profile", help="Profile")]
def __init__(self):
@@ -865,6 +874,7 @@ class CLI(object):
command.core = self.core
def run(self):
+ """ Run bcfg2-info """
if Bcfg2.Options.setup.subcommand != 'help':
self.core.run()
return self.core.runcommand()
diff --git a/src/lib/Bcfg2/Server/Lint/Bundler.py b/src/lib/Bcfg2/Server/Lint/Bundler.py
index b41313349..0caf4d7ed 100644
--- a/src/lib/Bcfg2/Server/Lint/Bundler.py
+++ b/src/lib/Bcfg2/Server/Lint/Bundler.py
@@ -1,3 +1,6 @@
+""" ``bcfg2-lint`` plugin for :ref:`Bundler
+<server-plugins-structures-bundler-index>` """
+
from Bcfg2.Server.Lint import ServerPlugin
diff --git a/src/lib/Bcfg2/Server/Lint/Cfg.py b/src/lib/Bcfg2/Server/Lint/Cfg.py
index 4cdf5c48a..2cdb1f7b8 100644
--- a/src/lib/Bcfg2/Server/Lint/Cfg.py
+++ b/src/lib/Bcfg2/Server/Lint/Cfg.py
@@ -1,4 +1,10 @@
+""" ``bcfg2-lint`` plugin for :ref:`Cfg
+<server-plugins-generators-cfg>` """
+
+
import os
+import Bcfg2.Options
+from fnmatch import fnmatch
from Bcfg2.Server.Lint import ServerPlugin
@@ -55,7 +61,7 @@ class Cfg(ServerPlugin):
# first, collect ignore patterns from handlers
ignore = set()
- for hdlr in handlers():
+ for hdlr in cfg.handlers():
ignore.update(hdlr.__ignore__)
# next, get a list of all non-ignored files on the filesystem
@@ -67,9 +73,9 @@ class Cfg(ServerPlugin):
# 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
+ for p in Bcfg2.Options.setup.ignore_files) and
not any(fnmatch(c, p)
- for p in self.config['ignore']
+ for p in sBcfg2.Options.setup.ignore_files
for c in self._list_path_components(fpath))):
all_files.add(fpath)
diff --git a/src/lib/Bcfg2/Server/Lint/Genshi.py b/src/lib/Bcfg2/Server/Lint/Genshi.py
index 76e1986f9..e3a0004a6 100755
--- a/src/lib/Bcfg2/Server/Lint/Genshi.py
+++ b/src/lib/Bcfg2/Server/Lint/Genshi.py
@@ -22,6 +22,7 @@ class Genshi(Bcfg2.Server.Lint.ServerPlugin):
"unknown-genshi-error": "error"}
def check_template(self, loader, fname, cls=None):
+ """ Generic check for all genshi templates (XML and text) """
try:
loader.load(fname, cls=cls)
except TemplateSyntaxError:
diff --git a/src/lib/Bcfg2/Server/Lint/GroupPatterns.py b/src/lib/Bcfg2/Server/Lint/GroupPatterns.py
index 8a0ab4f18..d8142cab9 100644
--- a/src/lib/Bcfg2/Server/Lint/GroupPatterns.py
+++ b/src/lib/Bcfg2/Server/Lint/GroupPatterns.py
@@ -1,3 +1,6 @@
+""" ``bcfg2-lint`` plugin for :ref:`GroupPatterns
+<server-plugins-grouping-grouppatterns>` """
+
import sys
from Bcfg2.Server.Lint import ServerPlugin
from Bcfg2.Server.Plugins.GroupPatterns import PatternMap
diff --git a/src/lib/Bcfg2/Server/Lint/MergeFiles.py b/src/lib/Bcfg2/Server/Lint/MergeFiles.py
index dff95fbf3..972475d91 100644
--- a/src/lib/Bcfg2/Server/Lint/MergeFiles.py
+++ b/src/lib/Bcfg2/Server/Lint/MergeFiles.py
@@ -11,10 +11,10 @@ from Bcfg2.Server.Plugins.Cfg import CfgGenerator
def threshold(val):
""" Option type processor to accept either a percentage (e.g.,
"threshold=75") or a ratio (e.g., "threshold=.75") """
- threshold = float(val)
- if threshold > 1:
- threshold /= 100
- return threshold
+ rv = float(val)
+ if rv > 1:
+ rv /= 100
+ return rv
class MergeFiles(Bcfg2.Server.Lint.ServerPlugin):
diff --git a/src/lib/Bcfg2/Server/Lint/Metadata.py b/src/lib/Bcfg2/Server/Lint/Metadata.py
index a349805fd..3c8f2831d 100644
--- a/src/lib/Bcfg2/Server/Lint/Metadata.py
+++ b/src/lib/Bcfg2/Server/Lint/Metadata.py
@@ -1,3 +1,6 @@
+""" ``bcfg2-lint`` plugin for :ref:`Metadata
+<server-plugins-grouping-metadata>` """
+
from Bcfg2.Server.Lint import ServerPlugin
diff --git a/src/lib/Bcfg2/Server/Lint/Pkgmgr.py b/src/lib/Bcfg2/Server/Lint/Pkgmgr.py
index 54f6f07d1..6b718d8b5 100644
--- a/src/lib/Bcfg2/Server/Lint/Pkgmgr.py
+++ b/src/lib/Bcfg2/Server/Lint/Pkgmgr.py
@@ -1,3 +1,6 @@
+""" ``bcfg2-lint`` plugin for :ref:`Pkgmgr
+<server-plugins-generators-pkgmgr>` """
+
import os
import glob
import lxml.etree
diff --git a/src/lib/Bcfg2/Server/Lint/TemplateHelper.py b/src/lib/Bcfg2/Server/Lint/TemplateHelper.py
index a24d70cab..1b4642a95 100644
--- a/src/lib/Bcfg2/Server/Lint/TemplateHelper.py
+++ b/src/lib/Bcfg2/Server/Lint/TemplateHelper.py
@@ -1,3 +1,6 @@
+""" ``bcfg2-lint`` plugin for :ref:`TemplateHelper
+<server-plugins-connectors-templatehelper>` """
+
import sys
import imp
from Bcfg2.Server.Lint import ServerPlugin
diff --git a/src/lib/Bcfg2/Server/Lint/__init__.py b/src/lib/Bcfg2/Server/Lint/__init__.py
index 4f64fd006..c8cdb5be1 100644
--- a/src/lib/Bcfg2/Server/Lint/__init__.py
+++ b/src/lib/Bcfg2/Server/Lint/__init__.py
@@ -346,7 +346,6 @@ class CLI(object):
except ImportError:
# no lint plugin for this server plugin
self.logger.debug("No lint plugin for %s" % plugin.__name__)
- pass
except AttributeError:
self.logger.error("Failed to load plugin %s: %s" %
(plugin.__name__, sys.exc_info()[1]))
@@ -369,6 +368,7 @@ class CLI(object):
self.serverlessplugins.append(plugin)
def run(self):
+ """ Run bcfg2-lint """
if Bcfg2.Options.setup.list_errors:
for plugin in self.serverplugins + self.serverlessplugins:
self.errorhandler.RegisterErrors(getattr(plugin, 'Errors')())
@@ -441,6 +441,7 @@ class CLI(object):
core.shutdown()
def _run_plugin(self, plugin, args=None):
+ """ Run a single bcfg2-lint plugin """
if args is None:
args = []
start = time.time()
diff --git a/src/lib/Bcfg2/Server/MultiprocessingCore.py b/src/lib/Bcfg2/Server/MultiprocessingCore.py
index d83080058..cce6bc0c3 100644
--- a/src/lib/Bcfg2/Server/MultiprocessingCore.py
+++ b/src/lib/Bcfg2/Server/MultiprocessingCore.py
@@ -225,9 +225,6 @@ class ChildCore(Core):
def _run(self):
return True
- def _daemonize(self):
- return True
-
def _dispatch(self, address, data):
""" Method dispatcher used for commands received from
the RPC queue. """
diff --git a/src/lib/Bcfg2/Server/Plugin/__init__.py b/src/lib/Bcfg2/Server/Plugin/__init__.py
index a85867134..6599aa7a5 100644
--- a/src/lib/Bcfg2/Server/Plugin/__init__.py
+++ b/src/lib/Bcfg2/Server/Plugin/__init__.py
@@ -25,6 +25,8 @@ from Bcfg2.Server.Plugin.exceptions import *
class _OptionContainer(object):
+ """ Container for plugin options that are loaded at import time
+ """
options = [
Bcfg2.Options.Common.default_paranoid,
Bcfg2.Options.Option(
diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py
index 186837923..225b3491c 100644
--- a/src/lib/Bcfg2/Server/Plugin/helpers.py
+++ b/src/lib/Bcfg2/Server/Plugin/helpers.py
@@ -13,7 +13,6 @@ import lxml.etree
import Bcfg2.Server
import Bcfg2.Options
import Bcfg2.Server.FileMonitor
-from Bcfg2.Utils import ClassName
from Bcfg2.Logger import Debuggable
from Bcfg2.Compat import CmpMixin, wraps
from Bcfg2.Server.Plugin.base import Plugin
diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py b/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py
index a7fa92201..99afac7eb 100644
--- a/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py
+++ b/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py
@@ -763,6 +763,7 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet):
class CfgHandlerAction(Bcfg2.Options.ComponentAction):
+ """ Option parser action to load Cfg handlers """
bases = ['Bcfg2.Server.Plugins.Cfg']
@@ -796,10 +797,18 @@ class Cfg(Bcfg2.Server.Plugin.GroupSpool,
global CFG # pylint: disable=W0603
Bcfg2.Server.Plugin.GroupSpool.__init__(self, core, datastore)
Bcfg2.Server.Plugin.PullTarget.__init__(self)
-
+ self._handlers = None
CFG = self
__init__.__doc__ = Bcfg2.Server.Plugin.GroupSpool.__init__.__doc__
+ @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 has_generator(self, entry, metadata):
""" Return True if the given entry can be generated for the
given metadata; False otherwise
diff --git a/src/lib/Bcfg2/Server/Plugins/FileProbes.py b/src/lib/Bcfg2/Server/Plugins/FileProbes.py
index 45511eb52..51eb6e09a 100644
--- a/src/lib/Bcfg2/Server/Plugins/FileProbes.py
+++ b/src/lib/Bcfg2/Server/Plugins/FileProbes.py
@@ -147,7 +147,7 @@ class FileProbes(Bcfg2.Server.Plugin.Plugin,
self.write_file(fileloc, contents)
self.verify_file(filename, contents, metadata)
infoxml = os.path.join(cfg.data, filename.lstrip("/"), "info.xml")
- self.write_infoxml(infoxml, entry, data)
+ self.write_infoxml(infoxml, data)
elif entrydata == contents:
self.debug_log("Existing %s contents match probed contents" %
filename)
@@ -213,7 +213,7 @@ class FileProbes(Bcfg2.Server.Plugin.Plugin,
updated = True
tries += 1
- def write_infoxml(self, infoxml, entry, data):
+ def write_infoxml(self, infoxml, data):
""" write an info.xml for the file """
if os.path.exists(infoxml):
return
diff --git a/src/lib/Bcfg2/Server/Plugins/Metadata.py b/src/lib/Bcfg2/Server/Plugins/Metadata.py
index f27910eb8..e2da2a6d4 100644
--- a/src/lib/Bcfg2/Server/Plugins/Metadata.py
+++ b/src/lib/Bcfg2/Server/Plugins/Metadata.py
@@ -20,12 +20,18 @@ from Bcfg2.Compat import MutableMapping, all, wraps # pylint: disable=W0622
from Bcfg2.version import Bcfg2VersionInfo
+# pylint: disable=C0103
+ClientVersions = None
MetadataClientModel = None
+# pylint: enable=C0103
HAS_DJANGO = False
def load_django_models():
+ """ Load models for Django after option parsing has completed """
+ # pylint: disable=W0602
global MetadataClientModel, ClientVersions, HAS_DJANGO
+ # pylint: enable=W0602
try:
from django.db import models
@@ -674,7 +680,9 @@ class Metadata(Bcfg2.Server.Plugin.Metadata,
try:
client = MetadataClientModel.objects.get(hostname=client_name)
except MetadataClientModel.DoesNotExist:
+ # pylint: disable=E1102
client = MetadataClientModel(hostname=client_name)
+ # pylint: enable=E1102
client.save()
self.clients = self.list_clients()
return client
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Collection.py b/src/lib/Bcfg2/Server/Plugins/Packages/Collection.py
index 0df8624f6..8b20df58a 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Collection.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Collection.py
@@ -595,7 +595,6 @@ def get_collection_class(source_type):
:type source_type: string
:returns: type - the Collection subclass that should be used to
instantiate an object to contain sources of the given type. """
- cls = None
for mod in Bcfg2.Options.setup.packages_backends:
if mod.__name__.endswith(".%s" % source_type.title()):
return getattr(mod, "%sCollection" % source_type.title())
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Source.py b/src/lib/Bcfg2/Server/Plugins/Packages/Source.py
index e1659dbb3..4b6130f72 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Source.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Source.py
@@ -49,7 +49,6 @@ in your ``Source`` subclass. For an example of this kind of
import os
import re
import sys
-import Bcfg2.Server.Plugin
from Bcfg2.Logger import Debuggable
from Bcfg2.Compat import HTTPError, HTTPBasicAuthHandler, \
HTTPPasswordMgrWithDefaultRealm, install_opener, build_opener, urlopen, \
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/YumHelper.py b/src/lib/Bcfg2/Server/Plugins/Packages/YumHelper.py
index 32db0b32d..dcb8718a0 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/YumHelper.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/YumHelper.py
@@ -266,6 +266,8 @@ class CacheManager(YumHelper):
class HelperSubcommand(Bcfg2.Options.Subcommand):
+ """ Base class for all yum helper subcommands """
+
# the value to JSON encode and print out if the command fails
fallback = None
@@ -300,10 +302,14 @@ class HelperSubcommand(Bcfg2.Options.Subcommand):
return 0
def _run(self, setup, data):
+ """ Actually run the command """
raise NotImplementedError
class DepSolverSubcommand(HelperSubcommand):
+ """ Base class for helper commands that use the depsolver (i.e.,
+ only resolve dependencies, don't modify the cache) """
+
def __init__(self):
HelperSubcommand.__init__(self)
self.depsolver = DepSolver(Bcfg2.Options.setup.yum_config,
@@ -311,6 +317,8 @@ class DepSolverSubcommand(HelperSubcommand):
class CacheManagerSubcommand(HelperSubcommand):
+ """ Base class for helper commands that use the cachemanager
+ (i.e., modify the cache) """
fallback = False
accept_input = False
@@ -321,18 +329,22 @@ class CacheManagerSubcommand(HelperSubcommand):
class Clean(CacheManagerSubcommand):
+ """ Clean the cache """
def _run(self, setup, data): # pylint: disable=W0613
self.cachemgr.clean_cache()
return True
class MakeCache(CacheManagerSubcommand):
+ """ Update the on-disk cache """
def _run(self, setup, data): # pylint: disable=W0613
self.cachemgr.populate_cache()
return True
class Complete(DepSolverSubcommand):
+ """ Given an initial set of packages, get a complete set of
+ packages with all dependencies resolved """
fallback = dict(packages=[], unknown=[])
def _run(self, _, data):
@@ -344,6 +356,7 @@ class Complete(DepSolverSubcommand):
class GetGroups(DepSolverSubcommand):
+ """ Resolve the given package groups """
def _run(self, _, data):
rv = dict()
for gdata in data:
@@ -356,10 +369,11 @@ class GetGroups(DepSolverSubcommand):
return rv
-Get_Groups = GetGroups
+Get_Groups = GetGroups # pylint: disable=C0103
class CLI(Bcfg2.Options.CommandRegistry):
+ """ The bcfg2-yum-helper CLI """
options = [
Bcfg2.Options.PathOption(
"-c", "--yum-config", help="Yum config file"),
@@ -377,6 +391,7 @@ class CLI(Bcfg2.Options.CommandRegistry):
self.logger = logging.getLogger(parser.prog)
def run(self):
+ """ Run bcfg2-yum-helper """
if not os.path.exists(Bcfg2.Options.setup.yum_config):
self.logger.error("Config file %s not found" %
Bcfg2.Options.setup.yum_config)
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py b/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py
index e6240f39a..efd0bbe4a 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py
@@ -124,7 +124,8 @@ class Packages(Bcfg2.Server.Plugin.Plugin,
Bcfg2.Options.PathOption(
cf=("packages", "apt_config"),
help="The default path for generated apt configs",
- default="/etc/apt/sources.list.d/bcfg2-packages-generated-sources.list")]
+ default=
+ "/etc/apt/sources.list.d/bcfg2-packages-generated-sources.list")]
#: Packages is an alternative to
#: :mod:`Bcfg2.Server.Plugins.Pkgmgr` and conflicts with it.
diff --git a/src/lib/Bcfg2/Server/Plugins/Probes.py b/src/lib/Bcfg2/Server/Plugins/Probes.py
index 21bb331cd..012c1958a 100644
--- a/src/lib/Bcfg2/Server/Plugins/Probes.py
+++ b/src/lib/Bcfg2/Server/Plugins/Probes.py
@@ -13,12 +13,17 @@ import Bcfg2.Server.FileMonitor
from Bcfg2.Server.Statistics import track_statistics
HAS_DJANGO = False
+# pylint: disable=C0103
ProbesDataModel = None
ProbesGroupsModel = None
+# pylint: enable=C0103
def load_django_models():
+ """ Load models for Django after option parsing has completed """
+ # pylint: disable=W0602
global ProbesDataModel, ProbesGroupsModel, HAS_DJANGO
+ # pylint: enable=W0602
try:
from django.db import models
HAS_DJANGO = True
diff --git a/src/lib/Bcfg2/Server/Plugins/SSHbase.py b/src/lib/Bcfg2/Server/Plugins/SSHbase.py
index c858b881b..8ce4e8a54 100644
--- a/src/lib/Bcfg2/Server/Plugins/SSHbase.py
+++ b/src/lib/Bcfg2/Server/Plugins/SSHbase.py
@@ -76,10 +76,6 @@ class HostKeyEntrySet(Bcfg2.Server.Plugin.EntrySet):
else:
self.metadata['mode'] = '0600'
- def get_keydata_object(self, filepath, specificity):
- return KeyData(filepath, specificity,
- self.encoding or Bcfg2.Options.setup.encoding)
-
class KnownHostsEntrySet(Bcfg2.Server.Plugin.EntrySet):
""" EntrySet to handle the ssh_known_hosts file """
diff --git a/src/lib/Bcfg2/Server/Test.py b/src/lib/Bcfg2/Server/Test.py
index 912a8f19c..08b4665aa 100644
--- a/src/lib/Bcfg2/Server/Test.py
+++ b/src/lib/Bcfg2/Server/Test.py
@@ -165,6 +165,7 @@ class ClientTest(TestCase):
class CLI(object):
+ """ The bcfg2-test CLI """
options = [
Bcfg2.Options.PositionalArgument(
"clients", help="Specific clients to build", nargs="*"),
@@ -230,6 +231,7 @@ class CLI(object):
core.shutdown()
def run(self):
+ """ Run bcfg2-test """
core = self.get_core()
clients = Bcfg2.Options.setup.clients or core.metadata.clients
ignore = self.get_ignore()
diff --git a/testsuite/requirements.txt b/testsuite/requirements.txt
index 4733d045c..d7eaa1ac9 100644
--- a/testsuite/requirements.txt
+++ b/testsuite/requirements.txt
@@ -6,3 +6,4 @@ pylint<1.0
pep8
python-daemon
genshi
+argparse