summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorChris St. Pierre <chris.a.st.pierre@gmail.com>2012-08-15 08:21:45 -0400
committerChris St. Pierre <chris.a.st.pierre@gmail.com>2012-08-15 08:21:45 -0400
commitb455dafd90b9710020f798cd73d63cd049685695 (patch)
tree0456007832aa19bc5d8bea84cbb647492926c7e2 /src
parent06a2efea2f666b94eaf7e74bda798ed261fc47de (diff)
parente911b57eb38dfa0fc06d19e70e02e121ae721e57 (diff)
downloadbcfg2-b455dafd90b9710020f798cd73d63cd049685695.tar.gz
bcfg2-b455dafd90b9710020f798cd73d63cd049685695.tar.bz2
bcfg2-b455dafd90b9710020f798cd73d63cd049685695.zip
Merge branch 'tests'
Diffstat (limited to 'src')
-rw-r--r--src/lib/Bcfg2/Bcfg2Py3k.py5
-rw-r--r--src/lib/Bcfg2/Server/Admin/Reports.py4
-rw-r--r--src/lib/Bcfg2/Server/Admin/Syncdb.py2
-rw-r--r--src/lib/Bcfg2/Server/Core.py25
-rw-r--r--src/lib/Bcfg2/Server/Plugin.py395
-rw-r--r--src/lib/Bcfg2/Server/Plugins/DBStats.py4
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Decisions.py6
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Deps.py21
-rw-r--r--src/lib/Bcfg2/Server/Plugins/FileProbes.py4
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Metadata.py81
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Apt.py7
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Pac.py7
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py11
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Probes.py11
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Snapshots.py6
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Statistics.py4
-rw-r--r--src/lib/Bcfg2/Server/Plugins/TemplateHelper.py7
-rwxr-xr-xsrc/sbin/bcfg2-info2
-rwxr-xr-xsrc/sbin/bcfg2-yum-helper16
19 files changed, 297 insertions, 321 deletions
diff --git a/src/lib/Bcfg2/Bcfg2Py3k.py b/src/lib/Bcfg2/Bcfg2Py3k.py
index 7b0c6a2b5..7fce94789 100644
--- a/src/lib/Bcfg2/Bcfg2Py3k.py
+++ b/src/lib/Bcfg2/Bcfg2Py3k.py
@@ -88,11 +88,6 @@ except NameError:
import functools
reduce = functools.reduce
-if sys.hexversion >= 0x03000000:
- from io import FileIO as file
-else:
- file = file
-
try:
from collections import MutableMapping
except ImportError:
diff --git a/src/lib/Bcfg2/Server/Admin/Reports.py b/src/lib/Bcfg2/Server/Admin/Reports.py
index 175b99d1d..335d6a1e7 100644
--- a/src/lib/Bcfg2/Server/Admin/Reports.py
+++ b/src/lib/Bcfg2/Server/Admin/Reports.py
@@ -109,7 +109,7 @@ class Reports(Bcfg2.Server.Admin.Mode):
try:
update_database()
except UpdaterError:
- print "Update failed"
+ print("Update failed")
raise SystemExit(-1)
elif args[0] == 'load_stats':
quick = '-O3' in args
@@ -121,7 +121,7 @@ class Reports(Bcfg2.Server.Admin.Mode):
if stats_file[0] == '-':
self.errExit("Invalid statistics file: %s" % stats_file)
elif args[i] == '-c' or args[i] == '--clients-file':
- print "DeprecationWarning: %s is no longer used" % args[i]
+ print("DeprecationWarning: %s is no longer used" % args[i])
i = i + 1
self.load_stats(stats_file, self.log.getEffectiveLevel() > logging.WARNING, quick)
elif args[0] == 'purge':
diff --git a/src/lib/Bcfg2/Server/Admin/Syncdb.py b/src/lib/Bcfg2/Server/Admin/Syncdb.py
index c9bba0810..72d3d469e 100644
--- a/src/lib/Bcfg2/Server/Admin/Syncdb.py
+++ b/src/lib/Bcfg2/Server/Admin/Syncdb.py
@@ -35,5 +35,5 @@ class Syncdb(Bcfg2.Server.Admin.Mode):
try:
update_database()
except UpdaterError:
- print "Update failed"
+ print("Update failed")
raise SystemExit(-1)
diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py
index 0676b1d8f..660d2c3ef 100644
--- a/src/lib/Bcfg2/Server/Core.py
+++ b/src/lib/Bcfg2/Server/Core.py
@@ -10,15 +10,10 @@ import time
import inspect
import lxml.etree
from traceback import format_exc
-
-# this must be set before we import the Metadata plugin
-os.environ['DJANGO_SETTINGS_MODULE'] = 'Bcfg2.settings'
-
import Bcfg2.settings
import Bcfg2.Server
import Bcfg2.Logger
import Bcfg2.Server.FileMonitor
-import Bcfg2.Server.Plugins.Metadata
from Bcfg2.Bcfg2Py3k import xmlrpclib
from Bcfg2.Server.Plugin import PluginInitError, PluginExecutionError
@@ -31,6 +26,8 @@ try:
except:
pass
+os.environ['DJANGO_SETTINGS_MODULE'] = 'Bcfg2.settings'
+
def exposed(func):
func.exposed = True
return func
@@ -357,7 +354,7 @@ class BaseCore(object):
revision=self.revision)
try:
meta = self.build_metadata(client)
- except Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError:
+ except Bcfg2.Server.Plugin.MetadataConsistencyError:
self.logger.error("Metadata consistency error for client %s" %
client)
return lxml.etree.Element("error", type='metadata error')
@@ -448,7 +445,7 @@ class BaseCore(object):
"""Build the metadata structure."""
if not hasattr(self, 'metadata'):
# some threads start before metadata is even loaded
- raise Bcfg2.Server.Plugins.Metadata.MetadataRuntimeError
+ raise Bcfg2.Server.Plugin.MetadataRuntimeError
imd = self.metadata.get_initial_metadata(client_name)
for conn in self.connectors:
grps = conn.get_additional_groups(imd)
@@ -484,11 +481,11 @@ class BaseCore(object):
meta = self.build_metadata(client)
else:
meta = None
- except Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError:
+ except Bcfg2.Server.Plugin.MetadataConsistencyError:
err = sys.exc_info()[1]
self.critical_error("Client metadata resolution error for %s: %s" %
(address[0], err))
- except Bcfg2.Server.Plugins.Metadata.MetadataRuntimeError:
+ except Bcfg2.Server.Plugin.MetadataRuntimeError:
err = sys.exc_info()[1]
self.critical_error('Metadata system runtime failure for %s: %s' %
(address[0], err))
@@ -527,8 +524,8 @@ class BaseCore(object):
client, metadata = self.resolve_client(address)
try:
self.metadata.set_version(client, version)
- except (Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError,
- Bcfg2.Server.Plugins.Metadata.MetadataRuntimeError):
+ except (Bcfg2.Server.Plugin.MetadataConsistencyError,
+ Bcfg2.Server.Plugin.MetadataRuntimeError):
err = sys.exc_info()[1]
self.critical_error("Unable to set version for %s: %s" %
(client, err))
@@ -585,8 +582,8 @@ class BaseCore(object):
client = self.resolve_client(address, metadata=False)[0]
try:
self.metadata.set_profile(client, profile, address)
- except (Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError,
- Bcfg2.Server.Plugins.Metadata.MetadataRuntimeError):
+ except (Bcfg2.Server.Plugin.MetadataConsistencyError,
+ Bcfg2.Server.Plugin.MetadataRuntimeError):
err = sys.exc_info()[1]
self.critical_error("Unable to assert profile for %s: %s" %
(client, err))
@@ -600,7 +597,7 @@ class BaseCore(object):
config = self.BuildConfiguration(client)
return lxml.etree.tostring(config, encoding='UTF-8',
xml_declaration=True)
- except Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError:
+ except Bcfg2.Server.Plugin.MetadataConsistencyError:
self.critical_error("Metadata consistency failure for %s" % client)
@exposed
diff --git a/src/lib/Bcfg2/Server/Plugin.py b/src/lib/Bcfg2/Server/Plugin.py
index 7fe98ea92..7e7f7db18 100644
--- a/src/lib/Bcfg2/Server/Plugin.py
+++ b/src/lib/Bcfg2/Server/Plugin.py
@@ -4,8 +4,6 @@ import copy
import logging
import lxml.etree
import os
-import pickle
-import posixpath
import re
import sys
import threading
@@ -22,12 +20,7 @@ except ImportError:
# py3k compatibility
if sys.hexversion >= 0x03000000:
from functools import reduce
- from io import FileIO as BUILTIN_FILE_TYPE
-else:
- BUILTIN_FILE_TYPE = file
-from Bcfg2.Bcfg2Py3k import Queue
-from Bcfg2.Bcfg2Py3k import Empty
-from Bcfg2.Bcfg2Py3k import Full
+from Bcfg2.Bcfg2Py3k import Queue, Empty, Full, cPickle
# grab default metadata info from bcfg2.conf
opts = {'owner': Bcfg2.Options.MDATA_OWNER,
@@ -37,24 +30,21 @@ opts = {'owner': Bcfg2.Options.MDATA_OWNER,
'important': Bcfg2.Options.MDATA_IMPORTANT,
'paranoid': Bcfg2.Options.MDATA_PARANOID,
'sensitive': Bcfg2.Options.MDATA_SENSITIVE}
-mdata_setup = Bcfg2.Options.OptionParser(opts)
-mdata_setup.parse([])
-del mdata_setup['args']
+default_file_metadata = Bcfg2.Options.OptionParser(opts)
+default_file_metadata.parse([])
+del default_file_metadata['args']
logger = logging.getLogger('Bcfg2.Server.Plugin')
-default_file_metadata = mdata_setup
-
-info_regex = re.compile( \
- 'encoding:(\s)*(?P<encoding>\w+)|' +
- 'group:(\s)*(?P<group>\S+)|' +
- 'important:(\s)*(?P<important>\S+)|' +
- 'mtime:(\s)*(?P<mtime>\w+)|' +
- 'owner:(\s)*(?P<owner>\S+)|' +
- 'paranoid:(\s)*(?P<paranoid>\S+)|' +
- 'perms:(\s)*(?P<perms>\w+)|' +
- 'secontext:(\s)*(?P<secontext>\S+)|' +
- 'sensitive:(\s)*(?P<sensitive>\S+)|')
+info_regex = re.compile('owner:(\s)*(?P<owner>\S+)|' +
+ 'group:(\s)*(?P<group>\S+)|' +
+ 'perms:(\s)*(?P<perms>\w+)|' +
+ 'secontext:(\s)*(?P<secontext>\S+)|' +
+ 'paranoid:(\s)*(?P<paranoid>\S+)|' +
+ 'sensitive:(\s)*(?P<sensitive>\S+)|' +
+ 'encoding:(\s)*(?P<encoding>\w+)|' +
+ 'important:(\s)*(?P<important>\S+)|' +
+ 'mtime:(\s)*(?P<mtime>\w+)|')
def bind_info(entry, metadata, infoxml=None, default=default_file_metadata):
for attr, val in list(default.items()):
@@ -80,6 +70,18 @@ class PluginExecutionError(Exception):
pass
+class MetadataConsistencyError(Exception):
+ """This error gets raised when metadata is internally inconsistent."""
+ pass
+
+
+class MetadataRuntimeError(Exception):
+ """This error is raised when the metadata engine
+ is called prior to reading enough data.
+ """
+ pass
+
+
class Debuggable(object):
__rmi__ = ['toggle_debug']
@@ -102,30 +104,6 @@ class Debuggable(object):
self.logger.error(message)
-class DatabaseBacked(object):
- def __init__(self):
- pass
-
- @property
- def _use_db(self):
- use_db = self.core.setup.cfp.getboolean(self.name.lower(),
- "use_database",
- default=False)
- if use_db and has_django:
- return True
- elif not use_db:
- return False
- else:
- self.logger.error("use_database is true but django not found")
- return False
-
-
-
-class PluginDatabaseModel(object):
- class Meta:
- app_label = "Server"
-
-
class Plugin(Debuggable):
"""This is the base class for all Bcfg2 Server plugins.
Several attributes must be defined in the subclass:
@@ -172,6 +150,26 @@ class Plugin(Debuggable):
return "%s Plugin" % self.__class__.__name__
+class DatabaseBacked(Plugin):
+ @property
+ def _use_db(self):
+ use_db = self.core.setup.cfp.getboolean(self.name.lower(),
+ "use_database",
+ default=False)
+ if use_db and has_django:
+ return True
+ elif not use_db:
+ return False
+ else:
+ self.logger.error("use_database is true but django not found")
+ return False
+
+
+class PluginDatabaseModel(object):
+ class Meta:
+ app_label = "Server"
+
+
class Generator(object):
"""Generator plugins contribute to literal client configurations."""
def HandlesEntry(self, entry, metadata):
@@ -180,14 +178,14 @@ class Generator(object):
def HandleEntry(self, entry, metadata):
"""This is the slow-path handler for configuration entry binding."""
- raise PluginExecutionError
+ return entry
class Structure(object):
"""Structure Plugins contribute to abstract client configurations."""
def BuildStructures(self, metadata):
"""Return a list of abstract goal structures for client."""
- raise PluginExecutionError
+ raise NotImplementedError
class Metadata(object):
@@ -208,10 +206,13 @@ class Metadata(object):
pass
def get_initial_metadata(self, client_name):
- raise PluginExecutionError
+ raise NotImplementedError
+
+ def merge_additional_data(self, imd, source, data):
+ raise NotImplementedError
- def merge_additional_data(self, imd, source, groups, data):
- raise PluginExecutionError
+ def merge_additional_groups(self, imd, groups):
+ raise NotImplementedError
class Connector(object):
@@ -236,22 +237,22 @@ class Probing(object):
pass
-class Statistics(object):
+class Statistics(Plugin):
"""Signal statistics handling capability."""
def process_statistics(self, client, xdata):
pass
-class ThreadedStatistics(Statistics,
- threading.Thread):
+class ThreadedStatistics(Statistics, threading.Thread):
"""Threaded statistics handling capability."""
def __init__(self, core, datastore):
- Statistics.__init__(self)
+ Statistics.__init__(self, core, datastore)
threading.Thread.__init__(self)
# Event from the core signaling an exit
self.terminate = core.terminate
self.work_queue = Queue(100000)
- self.pending_file = "%s/etc/%s.pending" % (datastore, self.__class__.__name__)
+ self.pending_file = os.path.join(datastore, "etc",
+ "%s.pending" % self.name)
self.daemon = False
self.start()
@@ -262,32 +263,37 @@ class ThreadedStatistics(Statistics,
while not self.work_queue.empty():
(metadata, data) = self.work_queue.get_nowait()
try:
- pending_data.append((metadata.hostname, lxml.etree.tostring(data)))
+ pending_data.append((metadata.hostname,
+ lxml.etree.tostring(data)))
except:
- self.logger.warning("Dropping interaction for %s" % metadata.hostname)
+ err = sys.exc_info()[1]
+ self.logger.warning("Dropping interaction for %s: %s" %
+ (metadata.hostname, err))
except Empty:
pass
try:
savefile = open(self.pending_file, 'w')
- pickle.dump(pending_data, savefile)
+ cPickle.dump(pending_data, savefile)
savefile.close()
- self.logger.info("Saved pending %s data" % self.__class__.__name__)
+ self.logger.info("Saved pending %s data" % self.name)
except:
- self.logger.warning("Failed to save pending data")
+ err = sys.exc_info()[1]
+ self.logger.warning("Failed to save pending data: %s" % err)
def load(self):
- """Load any pending data to a file."""
+ """Load any pending data from a file."""
if not os.path.exists(self.pending_file):
return True
pending_data = []
try:
savefile = open(self.pending_file, 'r')
- pending_data = pickle.load(savefile)
+ pending_data = cPickle.load(savefile)
savefile.close()
except Exception:
e = sys.exc_info()[1]
self.logger.warning("Failed to load pending data: %s" % e)
+ return False
for (pmetadata, pdata) in pending_data:
# check that shutdown wasnt called early
if self.terminate.isSet():
@@ -298,7 +304,7 @@ class ThreadedStatistics(Statistics,
try:
metadata = self.core.build_metadata(pmetadata)
break
- except Bcfg2.Server.Plugins.Metadata.MetadataRuntimeError:
+ except MetadataRuntimeError:
pass
self.terminate.wait(5)
@@ -313,14 +319,17 @@ class ThreadedStatistics(Statistics,
break
except lxml.etree.LxmlError:
lxml_error = sys.exc_info()[1]
- self.logger.error("Unable to load save interaction: %s" % lxml_error)
- except Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError:
- self.logger.error("Unable to load metadata for save interaction: %s" % pmetadata)
+ self.logger.error("Unable to load saved interaction: %s" %
+ lxml_error)
+ except MetadataConsistencyError:
+ self.logger.error("Unable to load metadata for save "
+ "interaction: %s" % pmetadata)
try:
os.unlink(self.pending_file)
except:
- self.logger.error("Failed to unlink save file: %s" % self.pending_file)
- self.logger.info("Loaded pending %s data" % self.__class__.__name__)
+ self.logger.error("Failed to unlink save file: %s" %
+ self.pending_file)
+ self.logger.info("Loaded pending %s data" % self.name)
return True
def run(self):
@@ -328,28 +337,25 @@ class ThreadedStatistics(Statistics,
return
while not self.terminate.isSet() and self.work_queue != None:
try:
- (xdata, client) = self.work_queue.get(block=True, timeout=2)
+ (client, xdata) = self.work_queue.get(block=True, timeout=2)
except Empty:
continue
except Exception:
e = sys.exc_info()[1]
self.logger.error("ThreadedStatistics: %s" % e)
continue
- self.handle_statistic(xdata, client)
+ self.handle_statistic(client, xdata)
if self.work_queue != None and not self.work_queue.empty():
self.save()
def process_statistics(self, metadata, data):
- warned = False
try:
self.work_queue.put_nowait((metadata, copy.copy(data)))
- warned = False
except Full:
- if not warned:
- self.logger.warning("%s: Queue is full. Dropping interactions." % self.__class__.__name__)
- warned = True
+ self.logger.warning("%s: Queue is full. Dropping interactions." %
+ self.name)
- def handle_statistics(self, metadata, data):
+ def handle_statistic(self, metadata, data):
"""Handle stats here."""
pass
@@ -359,17 +365,17 @@ class PullSource(object):
return []
def GetCurrentEntry(self, client, e_type, e_name):
- raise PluginExecutionError
+ raise NotImplementedError
class PullTarget(object):
def AcceptChoices(self, entry, metadata):
- raise PluginExecutionError
+ raise NotImplementedError
def AcceptPullData(self, specific, new_entry, verbose):
"""This is the null per-plugin implementation
of bcfg2-admin pull."""
- raise PluginExecutionError
+ raise NotImplementedError
class Decision(object):
@@ -385,13 +391,13 @@ class ValidationError(Exception):
class StructureValidator(object):
"""Validate/modify goal structures."""
def validate_structures(self, metadata, structures):
- raise ValidationError("not implemented")
+ raise NotImplementedError
class GoalValidator(object):
"""Validate/modify configuration goals."""
def validate_goals(self, metadata, goals):
- raise ValidationError("not implemented")
+ raise NotImplementedError
class Version(object):
@@ -434,7 +440,7 @@ class FileBacked(object):
if event and event.code2str() not in ['exists', 'changed', 'created']:
return
try:
- self.data = BUILTIN_FILE_TYPE(self.name).read()
+ self.data = open(self.name).read()
self.Index()
except IOError:
err = sys.exc_info()[1]
@@ -498,8 +504,8 @@ class DirectoryBacked(object):
"""
dirpathname = os.path.join(self.data, relative)
if relative not in self.handles.values():
- if not posixpath.isdir(dirpathname):
- logger.error("Failed to open directory %s" % (dirpathname))
+ if not os.path.isdir(dirpathname):
+ logger.error("%s is not a directory" % dirpathname)
return
reqid = self.fam.AddMonitor(dirpathname, self)
self.handles[reqid] = relative
@@ -531,11 +537,6 @@ class DirectoryBacked(object):
"""
action = event.code2str()
- # Clean up the absolute path names passed in
- event.filename = os.path.normpath(event.filename)
- if event.filename.startswith(self.data):
- event.filename = event.filename[len(self.data)+1:]
-
# Exclude events for actions we don't care about
if action == 'endExist':
return
@@ -545,10 +546,14 @@ class DirectoryBacked(object):
(action, event.requestID, event.filename))
return
+ # Clean up path names
+ event.filename = os.path.normpath(event.filename.lstrip('/'))
+
# Calculate the absolute and relative paths this event refers to
abspath = os.path.join(self.data, self.handles[event.requestID],
event.filename)
- relpath = os.path.join(self.handles[event.requestID], event.filename)
+ relpath = os.path.join(self.handles[event.requestID],
+ event.filename).lstrip('/')
if action == 'deleted':
for key in self.entries.keys():
@@ -559,7 +564,7 @@ class DirectoryBacked(object):
# watching a directory just because it gets deleted. If it
# is recreated, we will start getting notifications for it
# again without having to add a new monitor.
- elif posixpath.isdir(abspath):
+ elif os.path.isdir(abspath):
# Deal with events for directories
if action in ['exists', 'created']:
self.add_directory_monitor(relpath)
@@ -637,14 +642,18 @@ class XMLFileBacked(FileBacked):
Bcfg2.Server.XI_NAMESPACE)]
for el in included:
name = el.get("href")
- if name not in self.extras:
- if name.startswith("/"):
- fpath = name
+ if name.startswith("/"):
+ fpath = name
+ else:
+ if fname:
+ rel = fname
else:
- fpath = os.path.join(os.path.dirname(self.name), name)
+ rel = self.name
+ fpath = os.path.join(os.path.dirname(rel), name)
+ if fpath not in self.extras:
if os.path.exists(fpath):
self._follow_xincludes(fname=fpath)
- self.add_monitor(fpath, name)
+ self.add_monitor(fpath)
else:
msg = "%s: %s does not exist, skipping" % (self.name, name)
if el.findall('./%sfallback' % Bcfg2.Server.XI_NAMESPACE):
@@ -658,9 +667,9 @@ class XMLFileBacked(FileBacked):
self.xdata = lxml.etree.XML(self.data, base_url=self.name,
parser=Bcfg2.Server.XMLParser)
except lxml.etree.XMLSyntaxError:
- err = sys.exc_info()[1]
- logger.error("Failed to parse %s: %s" % (self.name, err))
- raise Bcfg2.Server.Plugin.PluginInitError
+ msg = "Failed to parse %s: %s" % (self.name, sys.exc_info()[1])
+ logger.error(msg)
+ raise PluginInitError(msg)
self._follow_xincludes()
if self.extras:
@@ -674,8 +683,8 @@ class XMLFileBacked(FileBacked):
if self.__identifier__ is not None:
self.label = self.xdata.attrib[self.__identifier__]
- def add_monitor(self, fpath, fname):
- self.extras.append(fname)
+ def add_monitor(self, fpath):
+ self.extras.append(fpath)
if self.fam and self.should_monitor:
self.fam.AddMonitor(fpath, self)
@@ -696,11 +705,9 @@ class StructFile(XMLFileBacked):
return False
negate = item.get('negate', 'false').lower() == 'true'
if item.tag == 'Group':
- return ((negate and item.get('name') not in metadata.groups) or
- (not negate and item.get('name') in metadata.groups))
+ return negate == (item.get('name') not in metadata.groups)
elif item.tag == 'Client':
- return ((negate and item.get('name') != metadata.hostname) or
- (not negate and item.get('name') == metadata.hostname))
+ return negate == (item.get('name') != metadata.hostname)
else:
return True
@@ -714,7 +721,7 @@ class StructFile(XMLFileBacked):
rv.extend(self._match(child, metadata))
return rv
else:
- rv = copy.copy(item)
+ rv = copy.deepcopy(item)
for child in rv.iterchildren():
rv.remove(child)
for child in item.iterchildren():
@@ -754,26 +761,28 @@ class StructFile(XMLFileBacked):
return rv
-class INode:
+class INode(object):
"""
LNodes provide lists of things available at a particular
group intersection.
"""
- raw = {'Client': "lambda m, e:'%(name)s' == m.hostname and predicate(m, e)",
- 'Group': "lambda m, e:'%(name)s' in m.groups and predicate(m, e)"}
- nraw = {'Client': "lambda m, e:'%(name)s' != m.hostname and predicate(m, e)",
- 'Group': "lambda m, e:'%(name)s' not in m.groups and predicate(m, e)"}
+ raw = dict(
+ Client="lambda m, e:'%(name)s' == m.hostname and predicate(m, e)",
+ Group="lambda m, e:'%(name)s' in m.groups and predicate(m, e)")
+ nraw = dict(
+ Client="lambda m, e:'%(name)s' != m.hostname and predicate(m, e)",
+ Group="lambda m, e:'%(name)s' not in m.groups and predicate(m, e)")
containers = ['Group', 'Client']
ignore = []
def __init__(self, data, idict, parent=None):
self.data = data
self.contents = {}
- if parent == None:
- self.predicate = lambda m, d: True
+ if parent is None:
+ self.predicate = lambda m, e: True
else:
predicate = parent.predicate
- if data.get('negate', 'false') in ['true', 'True']:
+ if data.get('negate', 'false').lower() == 'true':
psrc = self.nraw
else:
psrc = self.raw
@@ -782,20 +791,23 @@ class INode:
{'name': data.get('name')},
{'predicate': predicate})
else:
- raise Exception
- mytype = self.__class__
+ raise PluginExecutionError("Unknown tag: %s" % data.tag)
self.children = []
+ self._load_children(data, idict)
+
+ def _load_children(self, data, idict):
for item in data.getchildren():
if item.tag in self.ignore:
continue
elif item.tag in self.containers:
- self.children.append(mytype(item, idict, self))
+ self.children.append(self.__class__(item, idict, self))
else:
try:
self.contents[item.tag][item.get('name')] = \
dict(item.attrib)
except KeyError:
- self.contents[item.tag] = {item.get('name'): dict(item.attrib)}
+ self.contents[item.tag] = \
+ {item.get('name'): dict(item.attrib)}
if item.text:
self.contents[item.tag][item.get('name')]['__text__'] = \
item.text
@@ -847,31 +859,36 @@ class XMLSrc(XMLFileBacked):
def HandleEvent(self, _=None):
"""Read file upon update."""
try:
- data = BUILTIN_FILE_TYPE(self.name).read()
+ data = open(self.name).read()
except IOError:
- logger.error("Failed to read file %s" % (self.name))
- return
+ msg = "Failed to read file %s: %s" % (self.name, sys.exc_info()[1])
+ logger.error(msg)
+ raise PluginExecutionError(msg)
self.items = {}
try:
xdata = lxml.etree.XML(data, parser=Bcfg2.Server.XMLParser)
except lxml.etree.XMLSyntaxError:
- logger.error("Failed to parse file %s" % (self.name))
- return
+ msg = "Failed to parse file %s" % (self.name, sys.exc_info()[1])
+ logger.error(msg)
+ raise PluginExecutionError(msg)
self.pnode = self.__node__(xdata, self.items)
self.cache = None
try:
self.priority = int(xdata.get('priority'))
except (ValueError, TypeError):
if not self.noprio:
- logger.error("Got bogus priority %s for file %s" %
- (xdata.get('priority'), self.name))
+ msg = "Got bogus priority %s for file %s" % \
+ (xdata.get('priority'), self.name)
+ logger.error(msg)
+ raise PluginExecutionError(msg)
+
del xdata, data
def Cache(self, metadata):
"""Build a package dict for a given host."""
- if self.cache == None or self.cache[0] != metadata:
+ if self.cache is None or self.cache[0] != metadata:
cache = (metadata, self.__cacheobj__())
- if self.pnode == None:
+ if self.pnode is None:
logger.error("Cache method called early for %s; forcing data load" % (self.name))
self.HandleEvent()
return
@@ -900,11 +917,7 @@ class PrioDir(Plugin, Generator, XMLDirectoryBacked):
def __init__(self, core, datastore):
Plugin.__init__(self, core, datastore)
Generator.__init__(self)
- try:
- XMLDirectoryBacked.__init__(self, self.data, self.core.fam)
- except OSError:
- self.logger.error("Failed to load %s indices" % (self.name))
- raise PluginInitError
+ XMLDirectoryBacked.__init__(self, self.data, self.core.fam)
def HandleEvent(self, event):
"""Handle events and update dispatch table."""
@@ -943,13 +956,13 @@ class PrioDir(Plugin, Generator, XMLDirectoryBacked):
else:
prio = [int(src.priority) for src in matching]
if prio.count(max(prio)) > 1:
- self.logger.error("Found conflicting sources with "
- "same priority for %s, %s %s" %
- (metadata.hostname,
- entry.tag.lower(), entry.get('name')))
+ msg = "Found conflicting sources with same priority for " + \
+ "%s:%s for %s" % (entry.tag, entry.get("name"),
+ metadata.hostname)
+ self.logger.error(msg)
self.logger.error([item.name for item in matching])
self.logger.error("Priority was %s" % max(prio))
- raise PluginExecutionError
+ raise PluginExecutionError(msg)
index = prio.index(max(prio))
for rname in list(matching[index].cache[1][entry.tag].keys()):
@@ -975,9 +988,9 @@ class SpecificityError(Exception):
pass
-class Specificity:
-
- def __init__(self, all=False, group=False, hostname=False, prio=0, delta=False):
+class Specificity(object):
+ def __init__(self, all=False, group=False, hostname=False, prio=0,
+ delta=False):
self.hostname = hostname
self.all = all
self.group = group
@@ -987,6 +1000,12 @@ class Specificity:
def __lt__(self, other):
return self.__cmp__(other) < 0
+ def __gt__(self, other):
+ return self.__cmp__(other) > 0
+
+ def __eq__(self, other):
+ return self.__cmp__(other) == 0
+
def matches(self, metadata):
return self.all or \
self.hostname == metadata.hostname or \
@@ -995,26 +1014,36 @@ class Specificity:
def __cmp__(self, other):
"""Sort most to least specific."""
if self.all:
- return 1
- if self.group:
+ if other.all:
+ return 0
+ else:
+ return 1
+ elif other.all:
+ return -1
+ elif self.group:
if other.hostname:
return 1
if other.group and other.prio > self.prio:
return 1
if other.group and other.prio == self.prio:
return 0
+ elif other.group:
+ return -1
+ elif self.hostname and other.hostname:
+ return 0
return -1
- def more_specific(self, other):
- """Test if self is more specific than other."""
+ def __str__(self):
+ rv = [self.__class__.__name__, ': ']
if self.all:
- True
+ rv.append("all")
elif self.group:
- if other.hostname:
- return True
- elif other.group and other.prio > self.prio:
- return True
- return False
+ rv.append("Group %s, priority %s" % (self.group, self.prio))
+ elif self.hostname:
+ rv.append("Host %s" % self.hostname)
+ if self.delta:
+ rv.append(", delta=%s" % self.delta)
+ return "".join(rv)
class SpecificData(object):
@@ -1037,7 +1066,7 @@ class EntrySet(Debuggable):
"""Entry sets deal with the host- and group-specific entries."""
ignore = re.compile("^(\.#.*|.*~|\\..*\\.(sw[px])|.*\\.genshi_include)$")
- def __init__(self, basename, path, entry_type, encoding):
+ def __init__(self, basename, path, entry_type, encoding, is_regex=False):
Debuggable.__init__(self, name=basename)
self.path = path
self.entry_type = entry_type
@@ -1045,7 +1074,12 @@ class EntrySet(Debuggable):
self.metadata = default_file_metadata.copy()
self.infoxml = None
self.encoding = encoding
- pattern = '(.*/)?%s(\.((H_(?P<hostname>\S+))|' % basename
+
+ if is_regex:
+ base_pat = basename
+ else:
+ base_pat = re.escape(basename)
+ pattern = '(.*/)?%s(\.((H_(?P<hostname>\S+))|' % base_pat
pattern += '(G(?P<prio>\d+)_(?P<group>\S+))))?$'
self.specific = re.compile(pattern)
@@ -1062,20 +1096,13 @@ class EntrySet(Debuggable):
if matching is None:
matching = self.get_matching(metadata)
- hspec = [ent for ent in matching if ent.specific.hostname]
- if hspec:
- return hspec[0]
-
- gspec = [ent for ent in matching if ent.specific.group]
- if gspec:
- gspec.sort()
- return gspec[-1]
-
- aspec = [ent for ent in matching if ent.specific.all]
- if aspec:
- return aspec[0]
-
- raise PluginExecutionError
+ if matching:
+ matching.sort()
+ return matching[0]
+ else:
+ raise PluginExecutionError("No matching entries available for %s "
+ "for %s" % (self.path,
+ metadata.hostname))
def handle_event(self, event):
"""Handle FAM events for the TemplateSet."""
@@ -1164,8 +1191,7 @@ class EntrySet(Debuggable):
if value:
self.metadata[key] = value
if len(self.metadata['perms']) == 3:
- self.metadata['perms'] = "0%s" % \
- (self.metadata['perms'])
+ self.metadata['perms'] = "0%s" % self.metadata['perms']
def reset_metadata(self, event):
"""Reset metadata to defaults if info or info.xml removed."""
@@ -1178,7 +1204,8 @@ class EntrySet(Debuggable):
bind_info(entry, metadata, infoxml=self.infoxml, default=self.metadata)
def bind_entry(self, entry, metadata):
- """Return the appropriate interpreted template from the set of available templates."""
+ """Return the appropriate interpreted template from the set of
+ available templates."""
self.bind_info_to_entry(entry, metadata)
return self.best_matching(metadata).bind_entry(entry, metadata)
@@ -1206,36 +1233,38 @@ class GroupSpool(Plugin, Generator):
def add_entry(self, event):
epath = self.event_path(event)
ident = self.event_id(event)
- if posixpath.isdir(epath):
+ if os.path.isdir(epath):
self.AddDirectoryMonitor(epath[len(self.data):])
- if ident not in self.entries and posixpath.isfile(epath):
- dirpath = "".join([self.data, ident])
+ if ident not in self.entries and os.path.isfile(epath):
+ dirpath = self.data + ident
self.entries[ident] = self.es_cls(self.filename_pattern,
dirpath,
self.es_child_cls,
self.encoding)
self.Entries[self.entry_type][ident] = \
self.entries[ident].bind_entry
- if not posixpath.isdir(epath):
+ if not os.path.isdir(epath):
# do not pass through directory events
self.entries[ident].handle_event(event)
def event_path(self, event):
- return "".join([self.data, self.handles[event.requestID],
- event.filename])
+ return os.path.join(self.data,
+ self.handles[event.requestID].lstrip("/"),
+ event.filename)
def event_id(self, event):
epath = self.event_path(event)
- if posixpath.isdir(epath):
- return self.handles[event.requestID] + event.filename
+ if os.path.isdir(epath):
+ return os.path.join(self.handles[event.requestID].lstrip("/"),
+ event.filename)
else:
- return self.handles[event.requestID][:-1]
+ return self.handles[event.requestID].rstrip("/")
def toggle_debug(self):
for entry in self.entries.values():
if hasattr(entry, "toggle_debug"):
entry.toggle_debug()
- return Plugin.toggle_debug()
+ return Plugin.toggle_debug(self)
def HandleEvent(self, event):
"""Unified FAM event handler for GroupSpool."""
@@ -1246,7 +1275,7 @@ class GroupSpool(Plugin, Generator):
if action in ['exists', 'created']:
self.add_entry(event)
- if action == 'changed':
+ elif action == 'changed':
if ident in self.entries:
self.entries[ident].handle_event(event)
else:
@@ -1274,7 +1303,7 @@ class GroupSpool(Plugin, Generator):
relative += '/'
name = self.data + relative
if relative not in list(self.handles.values()):
- if not posixpath.isdir(name):
+ if not os.path.isdir(name):
self.logger.error("Failed to open directory %s" % name)
return
reqid = self.core.fam.AddMonitor(name, self)
diff --git a/src/lib/Bcfg2/Server/Plugins/DBStats.py b/src/lib/Bcfg2/Server/Plugins/DBStats.py
index 40ab11208..fa1f45a39 100644
--- a/src/lib/Bcfg2/Server/Plugins/DBStats.py
+++ b/src/lib/Bcfg2/Server/Plugins/DBStats.py
@@ -18,13 +18,11 @@ from Bcfg2.Server.Reports.reports.models import Client
logger = logging.getLogger('Bcfg2.Plugins.DBStats')
-class DBStats(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.ThreadedStatistics,
+class DBStats(Bcfg2.Server.Plugin.ThreadedStatistics,
Bcfg2.Server.Plugin.PullSource):
name = 'DBStats'
def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
Bcfg2.Server.Plugin.ThreadedStatistics.__init__(self, core, datastore)
Bcfg2.Server.Plugin.PullSource.__init__(self)
self.cpath = "%s/Metadata/clients.xml" % datastore
diff --git a/src/lib/Bcfg2/Server/Plugins/Decisions.py b/src/lib/Bcfg2/Server/Plugins/Decisions.py
index b432474f2..78b549c2c 100644
--- a/src/lib/Bcfg2/Server/Plugins/Decisions.py
+++ b/src/lib/Bcfg2/Server/Plugins/Decisions.py
@@ -23,9 +23,9 @@ class DecisionSet(Bcfg2.Server.Plugin.EntrySet):
- `encoding`: XML character encoding
"""
- pattern = '(white|black)list'
- Bcfg2.Server.Plugin.EntrySet.__init__(self, pattern, path, \
- DecisionFile, encoding)
+ Bcfg2.Server.Plugin.EntrySet.__init__(self, '(white|black)list', path,
+ DecisionFile, encoding,
+ is_regex=True)
try:
fam.AddMonitor(path, self)
except OSError:
diff --git a/src/lib/Bcfg2/Server/Plugins/Deps.py b/src/lib/Bcfg2/Server/Plugins/Deps.py
index 9b848baae..d3a1ee871 100644
--- a/src/lib/Bcfg2/Server/Plugins/Deps.py
+++ b/src/lib/Bcfg2/Server/Plugins/Deps.py
@@ -7,27 +7,10 @@ import Bcfg2.Server.Plugin
class DNode(Bcfg2.Server.Plugin.INode):
"""DNode provides supports for single predicate types for dependencies."""
- raw = {'Group': "lambda m, e:'%(name)s' in m.groups and predicate(m, e)"}
- containers = ['Group']
-
- def __init__(self, data, idict, parent=None):
- self.data = data
- self.contents = {}
- if parent == None:
- self.predicate = lambda x, d: True
- else:
- predicate = parent.predicate
- if data.tag in list(self.raw.keys()):
- self.predicate = eval(self.raw[data.tag] %
- {'name': data.get('name')},
- {'predicate': predicate})
- else:
- raise Exception
- mytype = self.__class__
- self.children = []
+ def _load_children(self, data, idict):
for item in data.getchildren():
if item.tag in self.containers:
- self.children.append(mytype(item, idict, self))
+ self.children.append(self.__class__(item, idict, self))
else:
data = [(child.tag, child.get('name'))
for child in item.getchildren()]
diff --git a/src/lib/Bcfg2/Server/Plugins/FileProbes.py b/src/lib/Bcfg2/Server/Plugins/FileProbes.py
index f95c05d42..a403c78d7 100644
--- a/src/lib/Bcfg2/Server/Plugins/FileProbes.py
+++ b/src/lib/Bcfg2/Server/Plugins/FileProbes.py
@@ -24,7 +24,7 @@ import lxml.etree
path = "%s"
if not os.path.exists(path):
- print "%%s does not exist" %% path
+ print("%%s does not exist" %% path)
raise SystemExit(1)
stat = os.stat(path)
@@ -34,7 +34,7 @@ data = lxml.etree.Element("ProbedFileData",
group=grp.getgrgid(stat[5])[0],
perms=oct(stat[0] & 07777))
data.text = binascii.b2a_base64(open(path).read())
-print lxml.etree.tostring(data)
+print(lxml.etree.tostring(data))
"""
class FileProbes(Bcfg2.Server.Plugin.Plugin,
diff --git a/src/lib/Bcfg2/Server/Plugins/Metadata.py b/src/lib/Bcfg2/Server/Plugins/Metadata.py
index e7be7c227..3c2c3701a 100644
--- a/src/lib/Bcfg2/Server/Plugins/Metadata.py
+++ b/src/lib/Bcfg2/Server/Plugins/Metadata.py
@@ -81,18 +81,6 @@ if has_django:
return False
-class MetadataConsistencyError(Exception):
- """This error gets raised when metadata is internally inconsistent."""
- pass
-
-
-class MetadataRuntimeError(Exception):
- """This error is raised when the metadata engine
- is called prior to reading enough data.
- """
- pass
-
-
class XMLMetadataConfig(Bcfg2.Server.Plugin.XMLFileBacked):
"""Handles xml config files and all XInclude statements"""
def __init__(self, metadata, watch_clients, basefile):
@@ -117,13 +105,15 @@ class XMLMetadataConfig(Bcfg2.Server.Plugin.XMLFileBacked):
@property
def xdata(self):
if not self.data:
- raise MetadataRuntimeError("%s has no data" % self.basefile)
+ raise Bcfg2.Server.Plugin.MetadataRuntimeError("%s has no data" %
+ self.basefile)
return self.data
@property
def base_xdata(self):
if not self.basedata:
- raise MetadataRuntimeError("%s has no data" % self.basefile)
+ raise Bcfg2.Server.Plugin.MetadataRuntimeError("%s has no data" %
+ self.basefile)
return self.basedata
def load_xml(self):
@@ -158,7 +148,7 @@ class XMLMetadataConfig(Bcfg2.Server.Plugin.XMLFileBacked):
except IOError:
msg = "Failed to write %s: %s" % (tmpfile, sys.exc_info()[1])
self.logger.error(msg)
- raise MetadataRuntimeError(msg)
+ raise Bcfg2.Server.Plugin.MetadataRuntimeError(msg)
# prep data
dataroot = xmltree.getroot()
newcontents = lxml.etree.tostring(dataroot, pretty_print=True)
@@ -174,7 +164,7 @@ class XMLMetadataConfig(Bcfg2.Server.Plugin.XMLFileBacked):
(tmpfile, sys.exc_info()[1])
self.logger.error(msg, exc_info=1)
os.unlink(tmpfile)
- raise MetadataRuntimeError(msg)
+ raise Bcfg2.Server.Plugin.MetadataRuntimeError(msg)
datafile.close()
# check if clients.xml is a symlink
if os.path.islink(fname):
@@ -187,7 +177,7 @@ class XMLMetadataConfig(Bcfg2.Server.Plugin.XMLFileBacked):
msg = "Metadata: Failed to rename %s: %s" % (tmpfile,
sys.exc_info()[1])
self.logger.error(msg)
- raise MetadataRuntimeError(msg)
+ raise Bcfg2.Server.Plugin.MetadataRuntimeError(msg)
def find_xml_for_xpath(self, xpath):
"""Find and load xml file containing the xpath query"""
@@ -203,28 +193,26 @@ class XMLMetadataConfig(Bcfg2.Server.Plugin.XMLFileBacked):
"""Try to find the data in included files"""
for included in self.extras:
try:
- xdata = lxml.etree.parse(os.path.join(self.basedir,
- included),
+ xdata = lxml.etree.parse(included,
parser=Bcfg2.Server.XMLParser)
cli = xdata.xpath(xpath)
if len(cli) > 0:
- return {'filename': os.path.join(self.basedir,
- included),
+ return {'filename': included,
'xmltree': xdata,
'xquery': cli}
except lxml.etree.XMLSyntaxError:
- self.logger.error('Failed to parse %s' % (included))
+ self.logger.error('Failed to parse %s' % included)
return {}
- def add_monitor(self, fpath, fname):
- self.extras.append(fname)
+ def add_monitor(self, fpath):
+ self.extras.append(fpath)
if self.fam and self.should_monitor:
self.fam.AddMonitor(fpath, self.metadata)
def HandleEvent(self, event):
"""Handle fam events"""
filename = os.path.basename(event.filename)
- if filename in self.extras:
+ if event.filename in self.extras:
if event.code2str() == 'exists':
return False
elif filename != self.basefile:
@@ -318,8 +306,7 @@ class MetadataGroup(tuple):
def __hash__(self):
return hash(self.name)
-class Metadata(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Metadata,
+class Metadata(Bcfg2.Server.Plugin.Metadata,
Bcfg2.Server.Plugin.Statistics,
Bcfg2.Server.Plugin.DatabaseBacked):
"""This class contains data for bcfg2 server metadata."""
@@ -328,10 +315,9 @@ class Metadata(Bcfg2.Server.Plugin.Plugin,
sort_order = 500
def __init__(self, core, datastore, watch_clients=True):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
Bcfg2.Server.Plugin.Metadata.__init__(self)
- Bcfg2.Server.Plugin.Statistics.__init__(self)
- Bcfg2.Server.Plugin.DatabaseBacked.__init__(self)
+ Bcfg2.Server.Plugin.Statistics.__init__(self, core, datastore)
+ Bcfg2.Server.Plugin.DatabaseBacked.__init__(self, core, datastore)
self.watch_clients = watch_clients
self.states = dict()
self.extra = dict()
@@ -436,7 +422,7 @@ class Metadata(Bcfg2.Server.Plugin.Plugin,
node = self._search_xdata(tag, name, config.xdata, alias=alias)
if node != None:
self.logger.error("%s \"%s\" already exists" % (tag, name))
- raise MetadataConsistencyError
+ raise Bcfg2.Server.Plugin.MetadataConsistencyError
element = lxml.etree.SubElement(config.base_xdata.getroot(),
tag, name=name)
if attribs:
@@ -480,13 +466,13 @@ class Metadata(Bcfg2.Server.Plugin.Plugin,
node = self._search_xdata(tag, name, config.xdata, alias=alias)
if node == None:
self.logger.error("%s \"%s\" does not exist" % (tag, name))
- raise MetadataConsistencyError
+ raise Bcfg2.Server.Plugin.MetadataConsistencyError
xdict = config.find_xml_for_xpath('.//%s[@name="%s"]' %
(tag, node.get('name')))
if not xdict:
self.logger.error("Unexpected error finding %s \"%s\"" %
(tag, name))
- raise MetadataConsistencyError
+ raise Bcfg2.Server.Plugin.MetadataConsistencyError
for key, val in list(attribs.items()):
xdict['xquery'][0].set(key, val)
config.write_xml(xdict['filename'], xdict['xmltree'])
@@ -522,13 +508,13 @@ class Metadata(Bcfg2.Server.Plugin.Plugin,
node = self._search_xdata(tag, name, config.xdata)
if node == None:
self.logger.error("%s \"%s\" does not exist" % (tag, name))
- raise MetadataConsistencyError
+ raise Bcfg2.Server.Plugin.MetadataConsistencyError
xdict = config.find_xml_for_xpath('.//%s[@name="%s"]' %
(tag, node.get('name')))
if not xdict:
self.logger.error("Unexpected error finding %s \"%s\"" %
(tag, name))
- raise MetadataConsistencyError
+ raise Bcfg2.Server.Plugin.MetadataConsistencyError
xdict['xquery'][0].getparent().remove(xdict['xquery'][0])
config.write_xml(xdict['filename'], xdict['xmltree'])
@@ -558,7 +544,7 @@ class Metadata(Bcfg2.Server.Plugin.Plugin,
except MetadataClientModel.DoesNotExist:
msg = "Client %s does not exist" % client_name
self.logger.warning(msg)
- raise MetadataConsistencyError(msg)
+ raise Bcfg2.Server.Plugin.MetadataConsistencyError(msg)
client.delete()
self.clients = self.list_clients()
else:
@@ -741,16 +727,16 @@ class Metadata(Bcfg2.Server.Plugin.Plugin,
self.logger.info("Asserting client %s profile to %s" %
(client, profile))
if False in list(self.states.values()):
- raise MetadataRuntimeError
+ raise Bcfg2.Server.Plugin.MetadataRuntimeError("Metadata has not been read yet")
if not force and profile not in self.groups:
msg = "Profile group %s does not exist" % profile
self.logger.error(msg)
- raise MetadataConsistencyError(msg)
+ raise Bcfg2.Server.Plugin.MetadataConsistencyError(msg)
group = self.groups[profile]
if not force and not group.is_public:
msg = "Cannot set client %s to private group %s" % (client, profile)
self.logger.error(msg)
- raise MetadataConsistencyError(msg)
+ raise Bcfg2.Server.Plugin.MetadataConsistencyError(msg)
if client in self.clients:
if self._use_db:
@@ -797,7 +783,7 @@ class Metadata(Bcfg2.Server.Plugin.Plugin,
else:
msg = "Cannot set version on non-existent client %s" % client
self.logger.error(msg)
- raise MetadataConsistencyError(msg)
+ raise Bcfg2.Server.Plugin.MetadataConsistencyError(msg)
self.versions[client] = version
self.clients_xml.write()
@@ -831,7 +817,7 @@ class Metadata(Bcfg2.Server.Plugin.Plugin,
if len(self.addresses[address]) != 1:
err = "Address %s has multiple reverse assignments; a uuid must be used" % address
self.logger.error(err)
- raise MetadataConsistencyError(err)
+ raise Bcfg2.Server.Plugin.MetadataConsistencyError(err)
return self.addresses[address][0]
try:
cname = socket.gethostbyaddr(address)[0].lower()
@@ -841,7 +827,7 @@ class Metadata(Bcfg2.Server.Plugin.Plugin,
except socket.herror:
warning = "address resolution error for %s" % address
self.logger.warning(warning)
- raise MetadataConsistencyError(warning)
+ raise Bcfg2.Server.Plugin.MetadataConsistencyError(warning)
def _merge_groups(self, client, groups, categories=None):
""" set group membership based on the contents of groups.xml
@@ -871,7 +857,7 @@ class Metadata(Bcfg2.Server.Plugin.Plugin,
def get_initial_metadata(self, client):
"""Return the metadata for a given client."""
if False in list(self.states.values()):
- raise MetadataRuntimeError("Metadata has not been read yet")
+ raise Bcfg2.Server.Plugin.MetadataRuntimeError("Metadata has not been read yet")
client = client.lower()
if client in self.aliases:
client = self.aliases[client]
@@ -898,7 +884,7 @@ class Metadata(Bcfg2.Server.Plugin.Plugin,
else:
msg = "Cannot add new client %s; no default group set" % client
self.logger.error(msg)
- raise MetadataConsistencyError(msg)
+ raise Bcfg2.Server.Plugin.MetadataConsistencyError(msg)
if client in self.clientgroups:
for cgroup in self.clientgroups[client]:
@@ -1052,9 +1038,10 @@ class Metadata(Bcfg2.Server.Plugin.Plugin,
id_method = 'address'
try:
client = self.resolve_client(address)
- except MetadataConsistencyError:
- self.logger.error("Client %s failed to resolve; metadata problem"
- % address[0])
+ except Bcfg2.Server.Plugin.MetadataConsistencyError:
+ err = sys.exc_info()[1]
+ self.logger.error("Client %s failed to resolve: %s" %
+ (address[0], err))
return False
else:
id_method = 'uuid'
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py b/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py
index 83f7bbd10..685cd5c1d 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py
@@ -2,8 +2,7 @@ import re
import gzip
from Bcfg2.Server.Plugins.Packages.Collection import Collection
from Bcfg2.Server.Plugins.Packages.Source import Source
-from Bcfg2.Bcfg2Py3k import cPickle, file
-
+from Bcfg2.Bcfg2Py3k import cPickle
class AptCollection(Collection):
def get_group(self, group):
@@ -25,13 +24,13 @@ class AptSource(Source):
'components': self.components, 'arches': self.arches}]
def save_state(self):
- cache = file(self.cachefile, 'wb')
+ cache = open(self.cachefile, 'wb')
cPickle.dump((self.pkgnames, self.deps, self.provides,
self.essentialpkgs), cache, 2)
cache.close()
def load_state(self):
- data = file(self.cachefile)
+ data = open(self.cachefile)
(self.pkgnames, self.deps, self.provides,
self.essentialpkgs) = cPickle.load(data)
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Pac.py b/src/lib/Bcfg2/Server/Plugins/Packages/Pac.py
index 99a090739..34c7b42c1 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Pac.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Pac.py
@@ -1,6 +1,6 @@
import gzip
import tarfile
-from Bcfg2.Bcfg2Py3k import cPickle, file
+from Bcfg2.Bcfg2Py3k import cPickle
from Bcfg2.Server.Plugins.Packages.Collection import Collection
from Bcfg2.Server.Plugins.Packages.Source import Source
@@ -9,6 +9,7 @@ class PacCollection(Collection):
self.logger.warning("Packages: Package groups are not supported by Pacman")
return []
+
class PacSource(Source):
basegroups = ['arch', 'parabola']
ptype = 'pacman'
@@ -22,13 +23,13 @@ class PacSource(Source):
'components': self.components, 'arches': self.arches}]
def save_state(self):
- cache = file(self.cachefile, 'wb')
+ cache = open(self.cachefile, 'wb')
cPickle.dump((self.pkgnames, self.deps, self.provides),
cache, 2)
cache.close()
def load_state(self):
- data = file(self.cachefile)
+ data = open(self.cachefile)
self.pkgnames, self.deps, self.provides = cPickle.load(data)
def filter_unknown(self, unknown):
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py b/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py
index 3ca96c0a4..0d565be31 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py
@@ -41,16 +41,9 @@ class PackagesSources(Bcfg2.Server.Plugin.StructFile,
def HandleEvent(self, event=None):
Bcfg2.Server.Plugin.XMLFileBacked.HandleEvent(self, event=event)
if event and event.filename != self.name:
- for fname in self.extras:
- fpath = None
- if fname.startswith("/"):
- fpath = os.path.abspath(fname)
- else:
- fpath = \
- os.path.abspath(os.path.join(os.path.dirname(self.name),
- fname))
+ for fpath in self.extras:
if fpath == os.path.abspath(event.filename):
- self.parsed.add(fname)
+ self.parsed.add(fpath)
break
if self.loaded:
diff --git a/src/lib/Bcfg2/Server/Plugins/Probes.py b/src/lib/Bcfg2/Server/Plugins/Probes.py
index 114a9bbd8..e08f52a28 100644
--- a/src/lib/Bcfg2/Server/Plugins/Probes.py
+++ b/src/lib/Bcfg2/Server/Plugins/Probes.py
@@ -115,11 +115,10 @@ class ProbeSet(Bcfg2.Server.Plugin.EntrySet):
bangline = re.compile('^#!\s*(?P<interpreter>.*)$')
def __init__(self, path, fam, encoding, plugin_name):
- fpattern = '[0-9A-Za-z_\-]+'
self.plugin_name = plugin_name
- Bcfg2.Server.Plugin.EntrySet.__init__(self, fpattern, path,
+ Bcfg2.Server.Plugin.EntrySet.__init__(self, '[0-9A-Za-z_\-]+', path,
Bcfg2.Server.Plugin.SpecificData,
- encoding)
+ encoding, is_regex=True)
fam.AddMonitor(path, self)
def HandleEvent(self, event):
@@ -152,8 +151,7 @@ class ProbeSet(Bcfg2.Server.Plugin.EntrySet):
return ret
-class Probes(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Probing,
+class Probes(Bcfg2.Server.Plugin.Probing,
Bcfg2.Server.Plugin.Connector,
Bcfg2.Server.Plugin.DatabaseBacked):
"""A plugin to gather information from a client machine."""
@@ -161,10 +159,9 @@ class Probes(Bcfg2.Server.Plugin.Plugin,
__author__ = 'bcfg-dev@mcs.anl.gov'
def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
Bcfg2.Server.Plugin.Connector.__init__(self)
Bcfg2.Server.Plugin.Probing.__init__(self)
- Bcfg2.Server.Plugin.DatabaseBacked.__init__(self)
+ Bcfg2.Server.Plugin.DatabaseBacked.__init__(self, core, datastore)
try:
self.probes = ProbeSet(self.data, core.fam, core.encoding,
diff --git a/src/lib/Bcfg2/Server/Plugins/Snapshots.py b/src/lib/Bcfg2/Server/Plugins/Snapshots.py
index 232dbb0c3..666beef21 100644
--- a/src/lib/Bcfg2/Server/Plugins/Snapshots.py
+++ b/src/lib/Bcfg2/Server/Plugins/Snapshots.py
@@ -62,14 +62,12 @@ def build_snap_ent(entry):
return [desired, state]
-class Snapshots(Bcfg2.Server.Plugin.Statistics,
- Bcfg2.Server.Plugin.Plugin):
+class Snapshots(Bcfg2.Server.Plugin.Statistics):
name = 'Snapshots'
experimental = True
def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Statistics.__init__(self)
+ Bcfg2.Server.Plugin.Statistics.__init__(self, core, datastore)
self.session = Bcfg2.Server.Snapshots.setup_session(core.cfile)
self.work_queue = Queue()
self.loader = threading.Thread(target=self.load_snapshot)
diff --git a/src/lib/Bcfg2/Server/Plugins/Statistics.py b/src/lib/Bcfg2/Server/Plugins/Statistics.py
index 9af7549ff..ce8d085cc 100644
--- a/src/lib/Bcfg2/Server/Plugins/Statistics.py
+++ b/src/lib/Bcfg2/Server/Plugins/Statistics.py
@@ -113,13 +113,11 @@ class StatisticsStore(object):
return (now-utime) > secondsPerDay
-class Statistics(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.ThreadedStatistics,
+class Statistics(Bcfg2.Server.Plugin.ThreadedStatistics,
Bcfg2.Server.Plugin.PullSource):
name = 'Statistics'
def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
Bcfg2.Server.Plugin.ThreadedStatistics.__init__(self, core, datastore)
Bcfg2.Server.Plugin.PullSource.__init__(self)
fpath = "%s/etc/statistics.xml" % datastore
diff --git a/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py b/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py
index 3712506d6..2b3aa6bc5 100644
--- a/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py
+++ b/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py
@@ -50,12 +50,13 @@ class HelperModule(Bcfg2.Server.Plugin.SpecificData):
class HelperSet(Bcfg2.Server.Plugin.EntrySet):
ignore = re.compile("^(\.#.*|.*~|\\..*\\.(sw[px])|.*\.py[co])$")
+ fpattern = '[0-9A-Za-z_\-]+\.py'
def __init__(self, path, fam, encoding, plugin_name):
- fpattern = '[0-9A-Za-z_\-]+\.py'
self.plugin_name = plugin_name
- Bcfg2.Server.Plugin.EntrySet.__init__(self, fpattern, path,
- HelperModule, encoding)
+ Bcfg2.Server.Plugin.EntrySet.__init__(self, self.fpattern, path,
+ HelperModule, encoding,
+ is_regex=True)
fam.AddMonitor(path, self)
def HandleEvent(self, event):
diff --git a/src/sbin/bcfg2-info b/src/sbin/bcfg2-info
index a8cc17a7b..bba8eca7c 100755
--- a/src/sbin/bcfg2-info
+++ b/src/sbin/bcfg2-info
@@ -643,7 +643,7 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.BaseCore):
print("Unable to build metadata for host %s" % args)
return
collection = self.plugins['Packages']._get_collection(metadata)
- print collection.sourcelist()
+ print(collection.sourcelist())
def do_profile(self, arg):
"""."""
diff --git a/src/sbin/bcfg2-yum-helper b/src/sbin/bcfg2-yum-helper
index 53784518b..a0698cc90 100755
--- a/src/sbin/bcfg2-yum-helper
+++ b/src/sbin/bcfg2-yum-helper
@@ -286,27 +286,27 @@ def main():
depsolver = DepSolver(options.config, options.verbose)
if cmd == "clean":
depsolver.clean_cache()
- print json.dumps(True)
+ print(json.dumps(True))
elif cmd == "complete":
data = json.loads(sys.stdin.read())
depsolver.groups = data['groups']
(packages, unknown) = depsolver.complete([pkg_to_tuple(p)
for p in data['packages']])
- print json.dumps(dict(packages=list(packages),
- unknown=list(unknown)))
+ print(json.dumps(dict(packages=list(packages),
+ unknown=list(unknown))))
elif cmd == "is_virtual_package":
package = pkg_to_tuple(json.loads(sys.stdin.read()))
- print json.dumps(bool(depsolver.get_provides(package, silent=True)))
+ print(json.dumps(bool(depsolver.get_provides(package, silent=True))))
elif cmd == "get_deps" or cmd == "get_provides":
package = pkg_to_tuple(json.loads(sys.stdin.read()))
- print json.dumps([p.name for p in getattr(depsolver, cmd)(package)])
+ print(json.dumps([p.name for p in getattr(depsolver, cmd)(package)]))
elif cmd == "get_group":
data = json.loads(sys.stdin.read())
if "type" in data:
packages = depsolver.get_group(data['group'], ptype=data['type'])
else:
packages = depsolver.get_group(data['group'])
- print json.dumps(list(packages))
+ print(json.dumps(list(packages)))
elif cmd == "get_groups":
data = json.loads(sys.stdin.read())
rv = dict()
@@ -317,10 +317,10 @@ def main():
else:
packages = depsolver.get_group(gdata['group'])
rv[gdata['group']] = list(packages)
- print json.dumps(rv)
+ print(json.dumps(rv))
elif cmd == "is_package":
package = pkg_to_tuple(json.loads(sys.stdin.read()))
- print json.dumps(getattr(depsolver, cmd)(package))
+ print(json.dumps(getattr(depsolver, cmd)(package)))
if __name__ == '__main__':