summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris St. Pierre <chris.a.st.pierre@gmail.com>2015-02-18 08:47:30 -0600
committerChris St. Pierre <chris.a.st.pierre@gmail.com>2015-02-18 08:47:30 -0600
commitdb4a3b0426f4912639c142366ff27594d54ce360 (patch)
treefe258d4b663b9607230e456cfa25cdfe29cb3a70
parented9920711a6020fa01d564db34e0ee4800718cc6 (diff)
parent89e7afbf74ffbbb54dd892bf2c4245aedee2a832 (diff)
downloadbcfg2-db4a3b0426f4912639c142366ff27594d54ce360.tar.gz
bcfg2-db4a3b0426f4912639c142366ff27594d54ce360.tar.bz2
bcfg2-db4a3b0426f4912639c142366ff27594d54ce360.zip
Merge pull request #250 from stpierre/blanket-except-plugins-lint
Remove blanket excepts from plugins and lint
-rw-r--r--src/lib/Bcfg2/Server/Lint/GroupPatterns.py5
-rw-r--r--src/lib/Bcfg2/Server/Lint/__init__.py4
-rw-r--r--src/lib/Bcfg2/Server/Plugin/helpers.py10
-rw-r--r--src/lib/Bcfg2/Server/Plugin/interfaces.py10
-rw-r--r--src/lib/Bcfg2/Server/Plugins/AWSTags.py18
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Bundler.py4
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py11
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/CfgPrivateKeyCreator.py33
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py16
-rw-r--r--src/lib/Bcfg2/Server/Plugins/FileProbes.py4
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Git.py27
-rw-r--r--src/lib/Bcfg2/Server/Plugins/GroupPatterns.py72
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Guppy.py41
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Hg.py11
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Metadata.py25
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Ohai.py4
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Apt.py2
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Pac.py2
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Pkgng.py2
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Source.py18
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Yum.py8
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/YumHelper.py4
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/__init__.py4
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Pkgmgr.py8
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Probes.py9
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Properties.py8
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Reporting.py9
-rw-r--r--src/lib/Bcfg2/Server/Plugins/SSHbase.py17
-rw-r--r--src/lib/Bcfg2/Server/Plugins/TemplateHelper.py4
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgGenshiGenerator.py2
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPrivateKeyCreator.py94
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/Test_init.py2
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestMetadata.py7
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestProperties.py2
-rw-r--r--testsuite/Testsrc/test_code_checks.py5
-rw-r--r--testsuite/common.py27
-rwxr-xr-xtestsuite/install.sh2
37 files changed, 260 insertions, 271 deletions
diff --git a/src/lib/Bcfg2/Server/Lint/GroupPatterns.py b/src/lib/Bcfg2/Server/Lint/GroupPatterns.py
index deb91020d..e9813b7e9 100644
--- a/src/lib/Bcfg2/Server/Lint/GroupPatterns.py
+++ b/src/lib/Bcfg2/Server/Lint/GroupPatterns.py
@@ -4,7 +4,8 @@
import sys
from Bcfg2.Server.Lint import ServerPlugin
-from Bcfg2.Server.Plugins.GroupPatterns import PatternMap
+from Bcfg2.Server.Plugins.GroupPatterns import PatternMap, \
+ PatternInitializationError
class GroupPatterns(ServerPlugin):
@@ -36,7 +37,7 @@ class GroupPatterns(ServerPlugin):
PatternMap(pat, None, groups)
else:
PatternMap(None, pat, groups)
- except: # pylint: disable=W0702
+ except PatternInitializationError:
err = sys.exc_info()[1]
self.LintError("pattern-fails-to-initialize",
"Failed to initialize %s %s for %s: %s" %
diff --git a/src/lib/Bcfg2/Server/Lint/__init__.py b/src/lib/Bcfg2/Server/Lint/__init__.py
index 903ee6326..61f704206 100644
--- a/src/lib/Bcfg2/Server/Lint/__init__.py
+++ b/src/lib/Bcfg2/Server/Lint/__init__.py
@@ -26,7 +26,7 @@ def _ioctl_GWINSZ(fd): # pylint: disable=C0103
from the given file descriptor """
try:
return struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234'))
- except: # pylint: disable=W0702
+ except (IOError, struct.error):
return None
@@ -40,7 +40,7 @@ def get_termsize():
fd = os.open(os.ctermid(), os.O_RDONLY)
dims = _ioctl_GWINSZ(fd)
os.close(fd)
- except: # pylint: disable=W0702
+ except IOError:
pass
if not dims:
try:
diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py
index 2aab231c6..5cfc8998c 100644
--- a/src/lib/Bcfg2/Server/Plugin/helpers.py
+++ b/src/lib/Bcfg2/Server/Plugin/helpers.py
@@ -266,7 +266,7 @@ class FileBacked(Debuggable):
self.fam = Bcfg2.Server.FileMonitor.get_fam()
def HandleEvent(self, event=None):
- """ HandleEvent is called whenever the FAM registers an event.
+ """HandleEvent is called whenever the FAM registers an event.
:param event: The event object
:type event: Bcfg2.Server.FileMonitor.Event
@@ -276,13 +276,11 @@ class FileBacked(Debuggable):
return
try:
self.data = open(self.name).read()
- self.Index()
except IOError:
err = sys.exc_info()[1]
self.logger.error("Failed to read file %s: %s" % (self.name, err))
- except:
- err = sys.exc_info()[1]
- self.logger.error("Failed to parse file %s: %s" % (self.name, err))
+
+ self.Index()
def Index(self):
""" Index() is called by :func:`HandleEvent` every time the
@@ -1196,7 +1194,7 @@ class SpecificData(Debuggable):
self.data = open(self.name).read()
except UnicodeDecodeError:
self.data = open(self.name, mode='rb').read()
- except: # pylint: disable=W0201
+ except IOError:
self.logger.error("Failed to read file %s" % self.name)
diff --git a/src/lib/Bcfg2/Server/Plugin/interfaces.py b/src/lib/Bcfg2/Server/Plugin/interfaces.py
index c45d6fa84..da39ac77a 100644
--- a/src/lib/Bcfg2/Server/Plugin/interfaces.py
+++ b/src/lib/Bcfg2/Server/Plugin/interfaces.py
@@ -445,8 +445,14 @@ class ThreadedStatistics(Statistics, Threaded, threading.Thread):
except Empty:
continue
except:
- err = sys.exc_info()[1]
- self.logger.error("ThreadedStatistics: %s" % err)
+ # we want to catch all exceptions here so that a stray
+ # error doesn't kill the entire statistics thread. For
+ # instance, if a bad value gets pushed onto the queue
+ # and the assignment above raises TypeError, we want
+ # to report the error, ignore the bad value, and
+ # continue processing statistics.
+ self.logger.error("Unknown error processing statistics: %s" %
+ sys.exc_info()[1])
continue
self.handle_statistic(client, xdata)
if self.work_queue is not None and not self.work_queue.empty():
diff --git a/src/lib/Bcfg2/Server/Plugins/AWSTags.py b/src/lib/Bcfg2/Server/Plugins/AWSTags.py
index 3f92542e7..0d6eefaaa 100644
--- a/src/lib/Bcfg2/Server/Plugins/AWSTags.py
+++ b/src/lib/Bcfg2/Server/Plugins/AWSTags.py
@@ -1,4 +1,4 @@
-""" Query tags from AWS via boto, optionally setting group membership """
+"""Query tags from AWS via boto, optionally setting group membership."""
import os
import re
@@ -82,22 +82,17 @@ class PatternFile(Bcfg2.Server.Plugin.XMLFileBacked):
self.tags.append(AWSTagPattern(entry.get("name"),
entry.get("value"),
groups))
- except: # pylint: disable=W0702
+ except re.error:
self.logger.error("AWSTags: Failed to initialize pattern %s: "
"%s" % (entry.get("name"),
sys.exc_info()[1]))
- def get_groups(self, hostname, tags):
+ def get_groups(self, tags):
""" return a list of groups that should be added to the given
- client based on patterns that match the hostname """
+ client based on patterns that match the tags """
ret = []
for pattern in self.tags:
- try:
- ret.extend(pattern.get_groups(tags))
- except: # pylint: disable=W0702
- self.logger.error("AWSTags: Failed to process pattern %s for "
- "%s" % (pattern, hostname),
- exc_info=1)
+ ret.extend(pattern.get_groups(tags))
return ret
@@ -182,5 +177,4 @@ class AWSTags(Bcfg2.Server.Plugin.Plugin,
return self.get_tags(metadata)
def get_additional_groups(self, metadata):
- return self.config.get_groups(metadata.hostname,
- self.get_tags(metadata))
+ return self.config.get_groups(self.get_tags(metadata))
diff --git a/src/lib/Bcfg2/Server/Plugins/Bundler.py b/src/lib/Bcfg2/Server/Plugins/Bundler.py
index 6c35ada59..e38eeea89 100644
--- a/src/lib/Bcfg2/Server/Plugins/Bundler.py
+++ b/src/lib/Bcfg2/Server/Plugins/Bundler.py
@@ -92,10 +92,6 @@ class Bundler(Plugin,
self.logger.error("Bundler: Failed to render templated bundle "
"%s: %s" % (bundlename, err))
continue
- except:
- self.logger.error("Bundler: Unexpected bundler error for %s" %
- bundlename, exc_info=1)
- continue
if data.get("independent", "false").lower() == "true":
data.tag = "Independent"
diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py
index ef4e6a656..c3bf9569b 100644
--- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py
+++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py
@@ -10,6 +10,7 @@ from Bcfg2.Server.Plugin import PluginExecutionError, removecomment, \
DefaultTemplateDataProvider, get_template_data
from Bcfg2.Server.Plugins.Cfg import CfgGenerator
from genshi.template import TemplateLoader, NewTextTemplate
+from genshi.template.base import TemplateError
from genshi.template.eval import UndefinedError, Suite
@@ -117,6 +118,8 @@ class CfgGenshiGenerator(CfgGenerator):
quad[2]))
raise
except:
+ # this needs to be a blanket except, since it can catch
+ # any error raised by the genshi template.
self._handle_genshi_exception(sys.exc_info())
get_data.__doc__ = CfgGenerator.get_data.__doc__
@@ -184,10 +187,10 @@ class CfgGenshiGenerator(CfgGenerator):
def handle_event(self, event):
CfgGenerator.handle_event(self, event)
try:
- self.template = \
- self.loader.load(self.name, cls=NewTextTemplate,
- encoding=Bcfg2.Options.setup.encoding)
- except:
+ self.template = self.loader.load(
+ self.name, cls=NewTextTemplate,
+ encoding=Bcfg2.Options.setup.encoding)
+ except TemplateError:
raise PluginExecutionError("Failed to load template: %s" %
sys.exc_info()[1])
handle_event.__doc__ = CfgGenerator.handle_event.__doc__
diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgPrivateKeyCreator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgPrivateKeyCreator.py
index 8cc3f7b21..43035b410 100644
--- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgPrivateKeyCreator.py
+++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgPrivateKeyCreator.py
@@ -47,7 +47,7 @@ class CfgPrivateKeyCreator(XMLCfgCreator):
the given client metadata, and may be obtained by
doing ``self.XMLMatch(metadata)``
:type spec: lxml.etree._Element
- :returns: string - The filename of the private key
+ :returns: tuple - (private key data, public key data)
"""
if spec is None:
spec = self.XMLMatch(metadata)
@@ -91,10 +91,9 @@ class CfgPrivateKeyCreator(XMLCfgCreator):
"with errors: %s" % (filename,
metadata.hostname,
result.stderr))
- return filename
- except:
+ return (open(filename).read(), open(filename + ".pub").read())
+ finally:
shutil.rmtree(tempdir)
- raise
# pylint: disable=W0221
def create_data(self, entry, metadata):
@@ -109,21 +108,17 @@ class CfgPrivateKeyCreator(XMLCfgCreator):
"""
spec = self.XMLMatch(metadata)
specificity = self.get_specificity(metadata)
- filename = self._gen_keypair(metadata, spec)
+ privkey, pubkey = self._gen_keypair(metadata, spec)
- try:
- # write the public key, stripping the comment and
- # replacing it with a comment that specifies the filename.
- kdata = open(filename + ".pub").read().split()[:2]
- kdata.append(self.pubkey_creator.get_filename(**specificity))
- pubkey = " ".join(kdata) + "\n"
- self.pubkey_creator.write_data(pubkey, **specificity)
+ # write the public key, stripping the comment and
+ # replacing it with a comment that specifies the filename.
+ kdata = pubkey.split()[:2]
+ kdata.append(self.pubkey_creator.get_filename(**specificity))
+ pubkey = " ".join(kdata) + "\n"
+ self.pubkey_creator.write_data(pubkey, **specificity)
- # encrypt the private key, write to the proper place, and
- # return it
- privkey = open(filename).read()
- self.write_data(privkey, **specificity)
- return privkey
- finally:
- shutil.rmtree(os.path.dirname(filename))
+ # encrypt the private key, write to the proper place, and
+ # return it
+ self.write_data(privkey, **specificity)
+ return privkey
# pylint: enable=W0221
diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py b/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py
index 5dc3d98eb..355e53588 100644
--- a/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py
+++ b/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py
@@ -553,12 +553,7 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet):
% (action, event.filename))
self.debug_log("%s handling %s event on %s" %
(hdlr.__name__, action, event.filename))
- try:
- self.entry_init(event, hdlr)
- except: # pylint: disable=W0702
- err = sys.exc_info()[1]
- self.logger.error("Cfg: Failed to parse %s: %s" %
- (event.filename, err))
+ self.entry_init(event, hdlr)
return
elif hdlr.ignore(event, basename=self.path):
return
@@ -732,7 +727,7 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet):
try:
return creator.create_data(entry, metadata)
- except:
+ except CfgCreationError:
raise PluginExecutionError("Cfg: Error creating data for %s: %s" %
(entry.get("name"), sys.exc_info()[1]))
@@ -760,6 +755,9 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet):
try:
return (generator.get_data(entry, metadata), generator)
except:
+ # TODO: the exceptions raised by ``get_data`` are not
+ # constrained in any way, so for now this needs to be a
+ # blanket except.
msg = "Cfg: Error rendering %s: %s" % (entry.get("name"),
sys.exc_info()[1])
self.logger.error(msg)
@@ -803,7 +801,7 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet):
try:
best = self.best_matching(metadata, generators)
rv.append(best.specific)
- except: # pylint: disable=W0702
+ except PluginExecutionError:
pass
if not rv or not rv[0].hostname:
@@ -835,7 +833,7 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet):
raise PluginExecutionError(msg)
try:
etext = new_entry['text'].encode(Bcfg2.Options.setup.encoding)
- except:
+ except UnicodeDecodeError:
msg = "Cfg: Cannot encode content of %s as %s" % \
(name, Bcfg2.Options.setup.encoding)
self.logger.error(msg)
diff --git a/src/lib/Bcfg2/Server/Plugins/FileProbes.py b/src/lib/Bcfg2/Server/Plugins/FileProbes.py
index 38f9403f5..b7d78bf75 100644
--- a/src/lib/Bcfg2/Server/Plugins/FileProbes.py
+++ b/src/lib/Bcfg2/Server/Plugins/FileProbes.py
@@ -38,7 +38,7 @@ if not os.path.exists(path):
try:
stat = os.stat(path)
-except:
+except OSError:
sys.stderr.write("Could not stat %%s: %%s" %% (path, sys.exc_info()[1]))
raise SystemExit(0)
data = Bcfg2.Client.XML.Element("ProbedFileData",
@@ -48,7 +48,7 @@ data = Bcfg2.Client.XML.Element("ProbedFileData",
mode=oct_mode(stat[0] & 4095))
try:
data.text = b64encode(open(path).read())
-except:
+except IOError:
sys.stderr.write("Could not read %%s: %%s" %% (path, sys.exc_info()[1]))
raise SystemExit(0)
print(Bcfg2.Client.XML.tostring(data, xml_declaration=False).decode('UTF-8'))
diff --git a/src/lib/Bcfg2/Server/Plugins/Git.py b/src/lib/Bcfg2/Server/Plugins/Git.py
index 9012fceb0..d0ae010fa 100644
--- a/src/lib/Bcfg2/Server/Plugins/Git.py
+++ b/src/lib/Bcfg2/Server/Plugins/Git.py
@@ -41,22 +41,17 @@ class Git(Version):
def get_revision(self):
"""Read git revision information for the Bcfg2 repository."""
- try:
- if HAS_GITPYTHON:
- return self.repo.head.commit.hexsha
- else:
- cmd = ["git", "--git-dir", self.vcs_path,
- "--work-tree", Bcfg2.Options.setup.vcs_root,
- "rev-parse", "HEAD"]
- self.debug_log("Git: Running %s" % cmd)
- result = self.cmd.run(cmd)
- if not result.success:
- raise Exception(result.stderr)
- return result.stdout
- except:
- raise PluginExecutionError("Git: Error getting revision from %s: "
- "%s" % (Bcfg2.Options.setup.vcs_root,
- sys.exc_info()[1]))
+ if HAS_GITPYTHON:
+ return self.repo.head.commit.hexsha
+ else:
+ cmd = ["git", "--git-dir", self.vcs_path,
+ "--work-tree", Bcfg2.Options.setup.vcs_root,
+ "rev-parse", "HEAD"]
+ self.debug_log("Git: Running %s" % cmd)
+ result = self.cmd.run(cmd)
+ if not result.success:
+ raise PluginExecutionError(result.stderr)
+ return result.stdout
def Update(self, ref=None):
""" Git.Update() => True|False
diff --git a/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py b/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py
index 7fa95fd05..9874977df 100644
--- a/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py
+++ b/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py
@@ -8,34 +8,43 @@ import Bcfg2.Server.Plugin
from Bcfg2.Utils import PackedDigitRange
+class PatternInitializationError(Exception):
+ """Raised when creating a PatternMap object fails."""
+
+
class PatternMap(object):
- """ Handler for a single pattern or range """
+ """Handler for a single pattern or range."""
def __init__(self, pattern, rangestr, groups):
self.pattern = pattern
self.rangestr = rangestr
self.groups = groups
- if pattern is not None:
- self.re = re.compile(pattern)
- self.process = self.process_re
- elif rangestr is not None:
- if '\\' in rangestr:
- raise Exception("Backslashes are not allowed in NameRanges")
- range_finder = r'\[\[[\d\-,]+\]\]'
- self.process = self.process_range
- self.re = re.compile(r'^' + re.sub(range_finder, r'(\d+)',
- rangestr))
- dmatcher = re.compile(re.sub(range_finder,
- r'\[\[([\d\-,]+)\]\]',
- rangestr))
- self.dranges = [PackedDigitRange(x)
- for x in dmatcher.match(rangestr).groups()]
- else:
- raise Exception("No pattern or range given")
+ try:
+ if pattern is not None:
+ self._re = re.compile(pattern)
+ self.process = self.process_re
+ elif rangestr is not None:
+ if '\\' in rangestr:
+ raise PatternInitializationError(
+ "Backslashes are not allowed in NameRanges")
+ range_finder = r'\[\[[\d\-,]+\]\]'
+ self.process = self.process_range
+ self._re = re.compile(r'^' + re.sub(range_finder, r'(\d+)',
+ rangestr))
+ dmatcher = re.compile(re.sub(range_finder,
+ r'\[\[([\d\-,]+)\]\]',
+ rangestr))
+ self.dranges = [PackedDigitRange(x)
+ for x in dmatcher.match(rangestr).groups()]
+ else:
+ raise PatternInitializationError("No pattern or range given")
+ except re.error:
+ raise PatternInitializationError(
+ "Could not compile pattern regex: %s" % sys.exc_info()[1])
def process_range(self, name):
- """ match the given hostname against a range-based NameRange """
- match = self.re.match(name)
+ """match the given hostname against a range-based NameRange."""
+ match = self._re.match(name)
if not match:
return None
digits = match.groups()
@@ -45,11 +54,11 @@ class PatternMap(object):
return self.groups
def process_re(self, name):
- """ match the given hostname against a regex-based NamePattern """
- match = self.re.search(name)
+ """match the given hostname against a regex-based NamePattern."""
+ match = self._re.search(name)
if not match:
return None
- ret = list()
+ ret = []
sub = match.groups()
for group in self.groups:
newg = group
@@ -64,7 +73,7 @@ class PatternMap(object):
class PatternFile(Bcfg2.Server.Plugin.XMLFileBacked):
- """ representation of GroupPatterns config.xml """
+ """representation of GroupPatterns config.xml."""
__identifier__ = None
create = 'GroupPatterns'
@@ -89,7 +98,7 @@ class PatternFile(Bcfg2.Server.Plugin.XMLFileBacked):
for range_ent in entry.findall('NameRange'):
rng = range_ent.text
self.patterns.append(PatternMap(None, rng, groups))
- except: # pylint: disable=W0702
+ except PatternInitializationError:
self.logger.error("GroupPatterns: Failed to initialize "
"pattern %s: %s" % (entry.text,
sys.exc_info()[1]))
@@ -99,20 +108,15 @@ class PatternFile(Bcfg2.Server.Plugin.XMLFileBacked):
client based on patterns that match the hostname """
ret = []
for pattern in self.patterns:
- try:
- grps = pattern.process(hostname)
- if grps is not None:
- ret.extend(grps)
- except: # pylint: disable=W0702
- self.logger.error("GroupPatterns: Failed to process pattern "
- "%s for %s" % (pattern.pattern, hostname),
- exc_info=1)
+ grps = pattern.process(hostname)
+ if grps is not None:
+ ret.extend(grps)
return ret
class GroupPatterns(Bcfg2.Server.Plugin.Plugin,
Bcfg2.Server.Plugin.Connector):
- """ set group membership based on client hostnames """
+ """set group membership based on client hostnames."""
def __init__(self, core):
Bcfg2.Server.Plugin.Plugin.__init__(self, core)
diff --git a/src/lib/Bcfg2/Server/Plugins/Guppy.py b/src/lib/Bcfg2/Server/Plugins/Guppy.py
index 8427a56c3..de994a2db 100644
--- a/src/lib/Bcfg2/Server/Plugins/Guppy.py
+++ b/src/lib/Bcfg2/Server/Plugins/Guppy.py
@@ -1,9 +1,9 @@
-"""
-This plugin is used to trace memory leaks within the bcfg2-server
-process using Guppy. By default the remote debugger is started
-when this plugin is enabled. The debugger can be shutoff in a running
-process using "bcfg2-admin xcmd Guppy.Disable" and reenabled using
-"bcfg2-admin xcmd Guppy.Enable".
+"""Debugging plugin to trace memory leaks within the bcfg2-server process.
+
+By default the remote debugger is started when this plugin is enabled.
+The debugger can be shutoff in a running process using "bcfg2-admin
+xcmd Guppy.Disable" and reenabled using "bcfg2-admin xcmd
+Guppy.Enable".
To attach the console run:
@@ -23,36 +23,27 @@ Remote connection 1. To return to Monitor, type <Ctrl-C> or .<RETURN>
Remote interactive console. To return to Annex, type '-'.
>>> hp.heap()
...
-
-
"""
import Bcfg2.Server.Plugin
from guppy.heapy import Remote
class Guppy(Bcfg2.Server.Plugin.Plugin):
- """Guppy is a debugging plugin to help trace memory leaks"""
+ """Guppy is a debugging plugin to help trace memory leaks."""
__author__ = 'bcfg-dev@mcs.anl.gov'
__rmi__ = Bcfg2.Server.Plugin.Plugin.__rmi__ + ['Enable', 'Disable']
__child_rmi__ = __rmi__[:]
def __init__(self, core):
Bcfg2.Server.Plugin.Plugin.__init__(self, core)
-
self.Enable()
- def Enable(self):
- """Enable remote debugging"""
- try:
- Remote.on()
- except:
- self.logger.error("Failed to create Heapy context")
- raise Bcfg2.Server.Plugin.PluginInitError
-
- def Disable(self):
- """Disable remote debugging"""
- try:
- Remote.off()
- except:
- self.logger.error("Failed to disable Heapy")
- raise Bcfg2.Server.Plugin.PluginInitError
+ @staticmethod
+ def Enable():
+ """Enable remote debugging."""
+ Remote.on()
+
+ @staticmethod
+ def Disable():
+ """Disable remote debugging."""
+ Remote.off()
diff --git a/src/lib/Bcfg2/Server/Plugins/Hg.py b/src/lib/Bcfg2/Server/Plugins/Hg.py
index 7554b4d52..3260908d8 100644
--- a/src/lib/Bcfg2/Server/Plugins/Hg.py
+++ b/src/lib/Bcfg2/Server/Plugins/Hg.py
@@ -1,5 +1,5 @@
-""" The Hg plugin provides a revision interface for Bcfg2 repos using
-mercurial. """
+"""Revision interface for Bcfg2 repos using mercurial.
+"""
import sys
from mercurial import ui, hg
@@ -7,8 +7,9 @@ import Bcfg2.Server.Plugin
class Hg(Bcfg2.Server.Plugin.Version):
- """ The Hg plugin provides a revision interface for Bcfg2 repos
- using mercurial. """
+ """Revision interface for Bcfg2 repos using mercurial.
+ """
+
__author__ = 'bcfg-dev@mcs.anl.gov'
__vcs_metadata_path__ = ".hg"
@@ -24,7 +25,7 @@ class Hg(Bcfg2.Server.Plugin.Version):
repo = hg.repository(ui.ui(), repo_path)
tip = repo.changelog.tip()
return repo.changelog.rev(tip)
- except:
+ except hg.error.RepoError:
err = sys.exc_info()[1]
msg = "Failed to read hg repository: %s" % err
self.logger.error(msg)
diff --git a/src/lib/Bcfg2/Server/Plugins/Metadata.py b/src/lib/Bcfg2/Server/Plugins/Metadata.py
index 26f39e50d..b850c1870 100644
--- a/src/lib/Bcfg2/Server/Plugins/Metadata.py
+++ b/src/lib/Bcfg2/Server/Plugins/Metadata.py
@@ -7,7 +7,6 @@ import sys
import time
import copy
import errno
-import fcntl
import socket
import logging
import lxml.etree
@@ -201,15 +200,7 @@ class XMLMetadataConfig(Bcfg2.Server.Plugin.XMLFileBacked):
while locked(fd):
pass
- try:
- datafile.write(newcontents)
- except:
- fcntl.lockf(fd, fcntl.LOCK_UN)
- msg = "Metadata: Failed to write new xml data to %s: %s" % \
- (tmpfile, sys.exc_info()[1])
- self.logger.error(msg, exc_info=1)
- os.unlink(tmpfile)
- raise Bcfg2.Server.Plugin.MetadataRuntimeError(msg)
+ datafile.write(newcontents)
datafile.close()
# check if clients.xml is a symlink
if os.path.islink(fname):
@@ -217,10 +208,10 @@ class XMLMetadataConfig(Bcfg2.Server.Plugin.XMLFileBacked):
try:
os.rename(tmpfile, fname)
- except: # pylint: disable=W0702
+ except OSError:
try:
os.unlink(tmpfile)
- except: # pylint: disable=W0702
+ except OSError:
pass
msg = "Metadata: Failed to rename %s: %s" % (tmpfile,
sys.exc_info()[1])
@@ -594,14 +585,8 @@ class Metadata(Bcfg2.Server.Plugin.Metadata,
def _handle_file(self, fname):
""" set up the necessary magic for handling a metadata file
(clients.xml or groups.xml, e.g.) """
- try:
- Bcfg2.Server.FileMonitor.get_fam().AddMonitor(
- os.path.join(self.data, fname), self)
- except:
- err = sys.exc_info()[1]
- msg = "Unable to add file monitor for %s: %s" % (fname, err)
- self.logger.error(msg)
- raise Bcfg2.Server.Plugin.PluginInitError(msg)
+ Bcfg2.Server.FileMonitor.get_fam().AddMonitor(
+ os.path.join(self.data, fname), self)
self.states[fname] = False
xmlcfg = XMLMetadataConfig(self, fname)
aname = re.sub(r'[^A-z0-9_]', '_', os.path.basename(fname))
diff --git a/src/lib/Bcfg2/Server/Plugins/Ohai.py b/src/lib/Bcfg2/Server/Plugins/Ohai.py
index c5fb46c97..461be9ba8 100644
--- a/src/lib/Bcfg2/Server/Plugins/Ohai.py
+++ b/src/lib/Bcfg2/Server/Plugins/Ohai.py
@@ -51,7 +51,7 @@ class OhaiCache(object):
if item not in self.cache:
try:
data = open(self.hostpath(item)).read()
- except:
+ except IOError:
raise KeyError(item)
self.cache[item] = json.loads(data)
return self.cache[item]
@@ -61,7 +61,7 @@ class OhaiCache(object):
del self.cache[item]
try:
os.unlink(self.hostpath(item))
- except:
+ except OSError:
raise IndexError("Could not unlink %s: %s" % (self.hostpath(item),
sys.exc_info()[1]))
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py b/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py
index cfabd8457..7de79e2f3 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py
@@ -89,7 +89,7 @@ class AptSource(Source):
bprov[barch] = dict()
try:
reader = gzip.GzipFile(fname)
- except:
+ except IOError:
self.logger.error("Packages: Failed to read file %s" % fname)
raise
for line in reader.readlines():
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Pac.py b/src/lib/Bcfg2/Server/Plugins/Packages/Pac.py
index 5f4d2ea41..0e15d2e15 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Pac.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Pac.py
@@ -67,7 +67,7 @@ class PacSource(Source):
try:
self.debug_log("Packages: try to read %s" % fname)
tar = tarfile.open(fname, "r")
- except:
+ except (IOError, tarfile.TarError):
self.logger.error("Packages: Failed to read file %s" % fname)
raise
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Pkgng.py b/src/lib/Bcfg2/Server/Plugins/Packages/Pkgng.py
index e393cabfe..736cdcdd4 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Pkgng.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Pkgng.py
@@ -71,7 +71,7 @@ class PkgngSource(Source):
try:
tar = tarfile.open(fileobj=lzma.LZMAFile(fname))
reader = tar.extractfile('packagesite.yaml')
- except:
+ except (IOError, tarfile.TarError):
self.logger.error("Packages: Failed to read file %s" % fname)
raise
for line in reader.readlines():
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Source.py b/src/lib/Bcfg2/Server/Plugins/Packages/Source.py
index 67ada2399..c9f6ea14a 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Source.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Source.py
@@ -331,10 +331,11 @@ class Source(Debuggable): # pylint: disable=R0902
@track_statistics()
def setup_data(self, force_update=False):
- """ Perform all data fetching and setup tasks. For most
- backends, this involves downloading all metadata from the
- repository, parsing it, and caching the parsed data locally.
- The order of operations is:
+ """Perform all data fetching and setup tasks.
+
+ For most backends, this involves downloading all metadata from
+ the repository, parsing it, and caching the parsed data
+ locally. The order of operations is:
#. Call :func:`load_state` to try to load data from the local
cache.
@@ -352,6 +353,15 @@ class Source(Debuggable): # pylint: disable=R0902
upstream repository.
:type force_update: bool
"""
+ # there are a bunch of wildcard except statements here,
+ # because the various functions called herein (``load_state``,
+ # ``read_files``, ``update``) are defined entirely by the
+ # Packages plugins that implement them.
+ #
+ # TODO: we should define an exception subclass that each of
+ # these functions can raise when an *expected* error condition
+ # is encountered.
+ #
# pylint: disable=W0702
if not force_update:
if os.path.exists(self.cachefile):
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py
index b6e9f13eb..dbe3f9ce5 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py
@@ -631,10 +631,6 @@ class YumCollection(Collection):
err = sys.exc_info()[1]
self.logger.error("Packages: Could not contact Pulp server: %s" %
err)
- except:
- err = sys.exc_info()[1]
- self.logger.error("Packages: Unknown error querying Pulp server: "
- "%s" % err)
return consumer
@track_statistics()
@@ -1034,10 +1030,6 @@ class YumSource(Source):
err = sys.exc_info()[1]
raise SourceInitError("Could not contact Pulp server: %s" %
err)
- except:
- err = sys.exc_info()[1]
- raise SourceInitError("Unknown error querying Pulp server: %s"
- % err)
self.rawurl = "%s/%s" % (PULPCONFIG.cds['baseurl'],
self.repo['relative_path'])
self.arches = [self.repo['arch']]
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/YumHelper.py b/src/lib/Bcfg2/Server/Plugins/Packages/YumHelper.py
index f26d6ba18..b2e43bde7 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/YumHelper.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/YumHelper.py
@@ -285,8 +285,8 @@ class HelperSubcommand(Bcfg2.Options.Subcommand):
def run(self, setup):
try:
data = json.loads(sys.stdin.read())
- except: # pylint: disable=W0702
- self.logger.error("Unexpected error decoding JSON input: %s" %
+ except ValueError:
+ self.logger.error("Error decoding JSON input: %s" %
sys.exc_info()[1])
print(json.dumps(self.fallback))
return 2
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py b/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py
index 87d42fd1c..3aa5c415f 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py
@@ -515,10 +515,6 @@ class Packages(Bcfg2.Server.Plugin.Plugin,
err = sys.exc_info()[1]
self.logger.error("Packages: Error writing %s to %s: "
"%s" % (key, localfile, err))
- except:
- err = sys.exc_info()[1]
- self.logger.error("Packages: Unknown error fetching "
- "%s: %s" % (key, err))
for kfile in glob.glob(os.path.join(self.keypath, "*")):
if kfile not in keyfiles:
diff --git a/src/lib/Bcfg2/Server/Plugins/Pkgmgr.py b/src/lib/Bcfg2/Server/Plugins/Pkgmgr.py
index c7d8986ed..7c6ab0ed7 100644
--- a/src/lib/Bcfg2/Server/Plugins/Pkgmgr.py
+++ b/src/lib/Bcfg2/Server/Plugins/Pkgmgr.py
@@ -35,7 +35,7 @@ class FuzzyDict(dict):
def get(self, key, default=None):
try:
return self.__getitem__(key)
- except:
+ except KeyError:
if default:
return default
raise
@@ -182,11 +182,7 @@ class PNode(object):
"""Return a dictionary of package mappings."""
if self.predicate(metadata, entry):
for key in self.contents:
- try:
- data[key].update(self.contents[key])
- except: # pylint: disable=W0702
- data[key] = FuzzyDict()
- data[key].update(self.contents[key])
+ data.setdefault(key, FuzzyDict).update(self.contents[key])
for child in self.children:
child.Match(metadata, data)
diff --git a/src/lib/Bcfg2/Server/Plugins/Probes.py b/src/lib/Bcfg2/Server/Plugins/Probes.py
index 21d50ace6..76aab69b5 100644
--- a/src/lib/Bcfg2/Server/Plugins/Probes.py
+++ b/src/lib/Bcfg2/Server/Plugins/Probes.py
@@ -405,7 +405,7 @@ class ProbeSet(Bcfg2.Server.Plugin.EntrySet):
else:
try:
probe.text = entry.data
- except: # pylint: disable=W0702
+ except ValueError:
self.logger.error("Client unable to handle unicode "
"probes. Skipping %s" %
probe.get('name'))
@@ -447,12 +447,7 @@ class Probes(Bcfg2.Server.Plugin.Probing,
Bcfg2.Server.Plugin.Connector.__init__(self)
Bcfg2.Server.Plugin.DatabaseBacked.__init__(self, core)
- try:
- self.probes = ProbeSet(self.data, self.name)
- except:
- err = sys.exc_info()[1]
- raise Bcfg2.Server.Plugin.PluginInitError(err)
-
+ self.probes = ProbeSet(self.data, self.name)
if self._use_db:
self.probestore = DBProbeStore(core, self.data)
else:
diff --git a/src/lib/Bcfg2/Server/Plugins/Properties.py b/src/lib/Bcfg2/Server/Plugins/Properties.py
index 28400f6d2..c4dd75e60 100644
--- a/src/lib/Bcfg2/Server/Plugins/Properties.py
+++ b/src/lib/Bcfg2/Server/Plugins/Properties.py
@@ -79,13 +79,12 @@ class PropertyFile(object):
class JSONPropertyFile(Bcfg2.Server.Plugin.FileBacked, PropertyFile):
- """ Handle JSON Properties files. """
+ """Handle JSON Properties files."""
def __init__(self, name):
Bcfg2.Server.Plugin.FileBacked.__init__(self, name)
PropertyFile.__init__(self, name)
self.json = None
- __init__.__doc__ = Bcfg2.Server.Plugin.FileBacked.__init__.__doc__
def Index(self):
try:
@@ -94,21 +93,18 @@ class JSONPropertyFile(Bcfg2.Server.Plugin.FileBacked, PropertyFile):
err = sys.exc_info()[1]
raise PluginExecutionError("Could not load JSON data from %s: %s" %
(self.name, err))
- Index.__doc__ = Bcfg2.Server.Plugin.FileBacked.Index.__doc__
def _write(self):
json.dump(self.json, open(self.name, 'wb'))
return True
- _write.__doc__ = PropertyFile._write.__doc__
def validate_data(self):
try:
json.dumps(self.json)
- except:
+ except TypeError:
err = sys.exc_info()[1]
raise PluginExecutionError("Data for %s cannot be dumped to JSON: "
"%s" % (self.name, err))
- validate_data.__doc__ = PropertyFile.validate_data.__doc__
def __str__(self):
return str(self.json)
diff --git a/src/lib/Bcfg2/Server/Plugins/Reporting.py b/src/lib/Bcfg2/Server/Plugins/Reporting.py
index 282de8247..5c73546b4 100644
--- a/src/lib/Bcfg2/Server/Plugins/Reporting.py
+++ b/src/lib/Bcfg2/Server/Plugins/Reporting.py
@@ -3,7 +3,6 @@
import sys
import time
import platform
-import traceback
import lxml.etree
import Bcfg2.Options
from Bcfg2.Reporting.Transport.base import TransportError
@@ -102,11 +101,11 @@ class Reporting(Statistics, Threaded, PullSource):
except TransportError:
continue
except:
- self.logger.error("%s: Attempt %s: Failed to add statistic %s"
+ self.logger.error("%s: Attempt %s: Failed to add statistic: %s"
% (self.__class__.__name__, i,
- traceback.format_exc().splitlines()[-1]))
- self.logger.error("%s: Retry limit reached for %s" %
- (self.__class__.__name__, client.hostname))
+ sys.exc_info()[1]))
+ raise PluginExecutionError("%s: Retry limit reached for %s" %
+ (self.__class__.__name__, client.hostname))
def shutdown(self):
super(Reporting, self).shutdown()
diff --git a/src/lib/Bcfg2/Server/Plugins/SSHbase.py b/src/lib/Bcfg2/Server/Plugins/SSHbase.py
index 89c7107aa..e4fb9b565 100644
--- a/src/lib/Bcfg2/Server/Plugins/SSHbase.py
+++ b/src/lib/Bcfg2/Server/Plugins/SSHbase.py
@@ -199,20 +199,19 @@ class SSHbase(Bcfg2.Server.Plugin.Plugin,
newnames.add(name.split('.')[0])
try:
newips.update(self.get_ipcache_entry(name)[0])
- except: # pylint: disable=W0702
+ except PluginExecutionError:
continue
names[cmeta.hostname].update(newnames)
names[cmeta.hostname].update(cmeta.addresses)
names[cmeta.hostname].update(newips)
# TODO: Only perform reverse lookups on IPs if an
# option is set.
- if True:
- for ip in newips:
- try:
- names[cmeta.hostname].update(
- self.get_namecache_entry(ip))
- except: # pylint: disable=W0702
- continue
+ for ip in newips:
+ try:
+ names[cmeta.hostname].update(
+ self.get_namecache_entry(ip))
+ except socket.gaierror:
+ continue
names[cmeta.hostname] = sorted(names[cmeta.hostname])
pubkeys = [pubk for pubk in list(self.entries.keys())
@@ -309,7 +308,7 @@ class SSHbase(Bcfg2.Server.Plugin.Plugin,
(event.filename, action))
def get_ipcache_entry(self, client):
- """ Build a cache of dns results. """
+ """Build a cache of dns results."""
if client in self.ipcache:
if self.ipcache[client]:
return self.ipcache[client]
diff --git a/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py b/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py
index 047fc062e..cec2de297 100644
--- a/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py
+++ b/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py
@@ -55,6 +55,10 @@ class HelperModule(Debuggable):
module = imp.load_source(safe_module_name(self._module_name),
self.name)
except: # pylint: disable=W0702
+ # this needs to be a blanket except because the
+ # imp.load_source() call can raise literally any error,
+ # since it imports the module and just passes through any
+ # exceptions raised.
err = sys.exc_info()[1]
self.logger.error("TemplateHelper: Failed to import %s: %s" %
(self.name, err))
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgGenshiGenerator.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgGenshiGenerator.py
index b667d417a..e2636908e 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgGenshiGenerator.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgGenshiGenerator.py
@@ -129,7 +129,7 @@ class TestCfgGenshiGenerator(TestCfgGenerator):
encoding=Bcfg2.Options.setup.encoding)
cgg.loader.reset_mock()
- cgg.loader.load.side_effect = OSError
+ cgg.loader.load.side_effect = TemplateError("test")
self.assertRaises(PluginExecutionError,
cgg.handle_event, event)
cgg.loader.load.assert_called_with(
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPrivateKeyCreator.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPrivateKeyCreator.py
index d64bbaabf..45945911f 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPrivateKeyCreator.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPrivateKeyCreator.py
@@ -2,6 +2,7 @@ import os
import sys
import lxml.etree
from mock import Mock, MagicMock, patch
+from Bcfg2.Compat import StringIO
from Bcfg2.Server.Plugins.Cfg import CfgCreationError
from Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator import *
from Bcfg2.Server.Plugin import PluginExecutionError
@@ -29,24 +30,25 @@ class TestCfgPrivateKeyCreator(TestXMLCfgCreator):
test_obj = CfgPrivateKeyCreator
should_monitor = False
+ def setUp(self):
+ TestXMLCfgCreator.setUp(self)
+ set_setup_default("cfg_category", "category")
+
@patch("Bcfg2.Server.Plugins.Cfg.CfgPublicKeyCreator.get_cfg", Mock())
def get_obj(self, name=None, fam=None):
return TestXMLCfgCreator.get_obj(self, name=name)
@patch("shutil.rmtree")
- @patch("tempfile.mkdtemp")
- def test__gen_keypair(self, mock_mkdtemp, mock_rmtree):
+ def _gen_keypair(self, mock_mkdtemp, mock_rmtree):
pkc = self.get_obj()
pkc.cmd = Mock()
pkc.XMLMatch = Mock()
- mock_mkdtemp.return_value = datastore
metadata = Mock()
exc = Mock()
exc.success = True
pkc.cmd.run.return_value = exc
- spec = lxml.etree.Element("PrivateKey")
pkc.XMLMatch.return_value = spec
def reset():
@@ -82,52 +84,62 @@ class TestCfgPrivateKeyCreator(TestXMLCfgCreator):
mock_rmtree.assert_called_with(datastore)
@patch("shutil.rmtree")
+ @patch("tempfile.mkdtemp")
@patch("%s.open" % builtins)
- def test_create_data(self, mock_open, mock_rmtree):
- pkc = self.get_obj()
- pkc.XMLMatch = Mock()
- pkc.get_specificity = Mock()
- # in order to make ** magic work in older versions of python,
- # get_specificity() must return an actual dict, not just a
- # Mock object that works like a dict. in order to test that
- # the get_specificity() return value is being used
- # appropriately, we put some dummy data in it and test for
- # that data
- pkc.get_specificity.side_effect = lambda m: dict(group="foo")
- pkc._gen_keypair = Mock()
- privkey = os.path.join(datastore, "privkey")
- pkc._gen_keypair.return_value = privkey
- pkc.pubkey_creator = Mock()
- pkc.pubkey_creator.get_filename.return_value = "pubkey.filename"
+ def _create_private_key(self, expected, mock_open, mock_mkdtemp,
+ mock_rmtree, spec=None):
+ pkc = self.get_obj(name="/home/foo/.ssh/id_rsa/privkey.xml")
+ pkc.cmd = MockExecutor()
+ pkc.pubkey_creator.write_data = Mock()
pkc.write_data = Mock()
+ mock_mkdtemp.return_value = datastore
+
+ if spec is None:
+ pkc.xdata = lxml.etree.Element("PrivateKey")
+ else:
+ pkc.xdata = spec
+
+ privkey_filename = os.path.join(datastore, "privkey")
+ pubkey_filename = os.path.join(datastore, "privkey.pub")
entry = lxml.etree.Element("Path", name="/home/foo/.ssh/id_rsa")
metadata = Mock()
+ metadata.group_in_category.return_value = "foo"
- def open_read_rv():
- mock_open.return_value.read.side_effect = lambda: "privatekey"
- return "ssh-rsa publickey foo@bar.com"
+ def open_key(fname):
+ if fname == privkey_filename:
+ return StringIO("privatekey")
+ elif fname == pubkey_filename:
+ return StringIO("ssh-rsa publickey foo@bar.com")
+ else:
+ self.fail("Unexpected open call: %s" % fname)
- def reset():
- mock_open.reset_mock()
- mock_rmtree.reset_mock()
- pkc.XMLMatch.reset_mock()
- pkc.get_specificity.reset_mock()
- pkc._gen_keypair.reset_mock()
- pkc.pubkey_creator.reset_mock()
- pkc.write_data.reset_mock()
- mock_open.return_value.read.side_effect = open_read_rv
+ mock_open.side_effect = open_key
- reset()
self.assertEqual(pkc.create_data(entry, metadata), "privatekey")
- pkc.XMLMatch.assert_called_with(metadata)
- pkc.get_specificity.assert_called_with(metadata)
- pkc._gen_keypair.assert_called_with(metadata,
- pkc.XMLMatch.return_value)
self.assertItemsEqual(mock_open.call_args_list,
- [call(privkey + ".pub"), call(privkey)])
- pkc.pubkey_creator.get_filename.assert_called_with(group="foo")
+ [call(pubkey_filename), call(privkey_filename)])
+ self.assertItemsEqual(
+ pkc.cmd.calls[0]['command'],
+ ['ssh-keygen', '-f', privkey_filename] + expected)
+ metadata.group_in_category.assert_called_with("category")
pkc.pubkey_creator.write_data.assert_called_with(
- "ssh-rsa publickey pubkey.filename\n", group="foo")
- pkc.write_data.assert_called_with("privatekey", group="foo")
+ "ssh-rsa publickey /home/foo/.ssh/id_rsa.pub/id_rsa.pub.G50_foo\n",
+ group="foo", prio=50)
+ pkc.write_data.assert_called_with("privatekey", group="foo", prio=50)
mock_rmtree.assert_called_with(datastore)
+
+ def test_create_data(self):
+ pass
+
+ def test_create_private_key_defaults(self):
+ self._create_private_key(['-t', 'rsa', '-N', ''])
+
+ def test_create_private_key_spec(self):
+ spec = lxml.etree.Element("PrivateKey")
+ lxml.etree.SubElement(spec, "Params", bits="768", type="dsa")
+ passphrase = lxml.etree.SubElement(spec, "Passphrase")
+ passphrase.text = "foo"
+
+ self._create_private_key(['-t', 'dsa', '-b', '768', '-N', 'foo'],
+ spec=spec)
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/Test_init.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/Test_init.py
index 1b55beded..507f0c9c2 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/Test_init.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/Test_init.py
@@ -726,7 +726,7 @@ class TestCfgEntrySet(TestEntrySet):
# test failure to create data
reset()
- creator.create_data.side_effect = OSError
+ creator.create_data.side_effect = CfgCreationError
self.assertRaises(PluginExecutionError,
eset._create_data, entry, metadata)
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestMetadata.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestMetadata.py
index d3fa15236..f2721c9ea 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestMetadata.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestMetadata.py
@@ -519,13 +519,6 @@ class TestMetadata(_TestMetadata, TestClientRunHooks, TestDatabaseBacked):
os.path.join(metadata.data, "clients.xml"),
metadata)
- mock_get_fam.reset_mock()
- fam = Mock()
- fam.AddMonitor = Mock(side_effect=IOError)
- mock_get_fam.return_value = fam
- self.assertRaises(Bcfg2.Server.Plugin.PluginInitError,
- self.get_obj, core=core)
-
@patch('os.makedirs', Mock())
@patch('%s.open' % builtins)
def test_init_repo(self, mock_open):
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestProperties.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestProperties.py
index 159dc6e66..36baee899 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestProperties.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestProperties.py
@@ -124,7 +124,7 @@ class TestJSONPropertyFile(TestFileBacked, TestPropertyFile):
mock_dumps.assert_called_with(pf.json)
mock_dumps.reset_mock()
- mock_dumps.side_effect = ValueError
+ mock_dumps.side_effect = TypeError
self.assertRaises(PluginExecutionError, pf.validate_data)
mock_dumps.assert_called_with(pf.json)
diff --git a/testsuite/Testsrc/test_code_checks.py b/testsuite/Testsrc/test_code_checks.py
index 79eff7959..ba4b19d1c 100644
--- a/testsuite/Testsrc/test_code_checks.py
+++ b/testsuite/Testsrc/test_code_checks.py
@@ -49,7 +49,10 @@ contingent_checks = {
["CfgEncryptedCheetahGenerator.py"]},
("M2Crypto", "jinja2"): {"lib/Bcfg2/Server/Plugins/Cfg":
["CfgEncryptedJinja2Generator.py"]},
- }
+ ("mercurial",): {"lib/Bcfg2/Server/Plugins": ["Hg.py"]},
+ ("guppy",): {"lib/Bcfg2/Server/Plugins": ["Guppy.py"]},
+ ("boto",): {"lib/Bcfg2/Server/Plugins": ["AWSTags.py"]},
+}
# perform only error checking on the listed files
error_checks = {
diff --git a/testsuite/common.py b/testsuite/common.py
index fc2397560..4c7337e0d 100644
--- a/testsuite/common.py
+++ b/testsuite/common.py
@@ -14,6 +14,7 @@ import sys
import codecs
import lxml.etree
import Bcfg2.Options
+import Bcfg2.Utils
from mock import patch, MagicMock, _patch, DEFAULT
try:
from unittest2 import skip, skipIf, skipUnless, TestCase
@@ -119,6 +120,29 @@ else:
return codecs.unicode_escape_decode(s)[0]
+class MockExecutor(object):
+ """mock object for :class:`Bcfg2.Utils.Executor` objects."""
+ def __init__(self, timeout=None):
+ self.timeout = timeout
+
+ # variables that can be set to control the result returned
+ self.stdout = ''
+ self.stderr = ''
+ self.retval = 0
+
+ # variables that record how run() was called
+ self.calls = []
+
+ def run(self, command, inputdata=None, timeout=None, **kwargs):
+ self.calls.append({"command": command,
+ "inputdata": inputdata,
+ "timeout": timeout or self.timeout,
+ "kwargs": kwargs})
+
+ return Bcfg2.Utils.ExecutorResult(self.stdout, self.stderr,
+ self.retval)
+
+
class Bcfg2TestCase(TestCase):
""" Base TestCase class that inherits from
:class:`unittest.TestCase`. This class adds
@@ -138,6 +162,9 @@ class Bcfg2TestCase(TestCase):
if cls.capture_stderr:
sys.stderr = cls._stderr
+ if hasattr(TestCase, "assertCountEqual"):
+ assertItemsEqual = assertCountEqual
+
def assertXMLEqual(self, el1, el2, msg=None):
""" Test that the two XML trees given are equal. """
if msg is None:
diff --git a/testsuite/install.sh b/testsuite/install.sh
index bbbd9ae76..42d5bbadb 100755
--- a/testsuite/install.sh
+++ b/testsuite/install.sh
@@ -17,7 +17,7 @@ if [[ "$WITH_OPTIONAL_DEPS" == "yes" ]]; then
sudo apt-get install -y yum libaugeas0 augeas-lenses libacl1-dev libssl-dev
pip install --use-mirrors PyYAML pyinotify boto pylibacl 'django<1.5' \
- Jinja2
+ Jinja2 mercurial guppy
easy_install https://fedorahosted.org/released/python-augeas/python-augeas-0.4.1.tar.gz
if [[ ${PYVER:0:1} == "2" ]]; then
# django supports py3k, but South doesn't, and the django bits