summaryrefslogtreecommitdiffstats
path: root/src/lib/Bcfg2/Server/Plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/Bcfg2/Server/Plugins')
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Account.py102
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Base.py4
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Bundler.py70
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/CfgCatFilter.py28
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/CfgDiffFilter.py35
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/CfgLegacyInfo.py46
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py31
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Decisions.py3
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Editor.py80
-rw-r--r--src/lib/Bcfg2/Server/Plugins/FileProbes.py4
-rw-r--r--src/lib/Bcfg2/Server/Plugins/GroupPatterns.py6
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Hostbase.py599
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Ldap.py6
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Metadata.py8
-rw-r--r--src/lib/Bcfg2/Server/Plugins/NagiosGen.py7
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Apt.py9
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Collection.py36
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Pac.py9
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py7
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Source.py42
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Yum.py16
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/__init__.py23
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Probes.py7
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Properties.py28
-rw-r--r--src/lib/Bcfg2/Server/Plugins/PuppetENC.py3
-rw-r--r--src/lib/Bcfg2/Server/Plugins/SSHbase.py7
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Snapshots.py129
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Statistics.py160
-rw-r--r--src/lib/Bcfg2/Server/Plugins/TCheetah.py79
-rw-r--r--src/lib/Bcfg2/Server/Plugins/TGenshi.py139
-rw-r--r--src/lib/Bcfg2/Server/Plugins/TemplateHelper.py5
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Trigger.py3
-rw-r--r--src/lib/Bcfg2/Server/Plugins/__init__.py33
33 files changed, 119 insertions, 1645 deletions
diff --git a/src/lib/Bcfg2/Server/Plugins/Account.py b/src/lib/Bcfg2/Server/Plugins/Account.py
deleted file mode 100644
index fd49d3655..000000000
--- a/src/lib/Bcfg2/Server/Plugins/Account.py
+++ /dev/null
@@ -1,102 +0,0 @@
-"""This handles authentication setup."""
-
-import Bcfg2.Server.Plugin
-
-
-class Account(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Generator):
- """This module generates account config files,
- based on an internal data repo:
- static.(passwd|group|limits.conf) -> static entries
- dyn.(passwd|group) -> dynamic entries (usually acquired from yp or somesuch)
- useraccess -> users to be granted login access on some hosts
- superusers -> users to be granted root privs on all hosts
- rootlike -> users to be granted root privs on some hosts
-
- """
- name = 'Account'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- deprecated = True
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Generator.__init__(self)
- self.Entries = {'ConfigFile': {'/etc/passwd': self.from_yp_cb,
- '/etc/group': self.from_yp_cb,
- '/etc/security/limits.conf': self.gen_limits_cb,
- '/root/.ssh/authorized_keys': self.gen_root_keys_cb,
- '/etc/sudoers': self.gen_sudoers}}
- try:
- self.repository = Bcfg2.Server.Plugin.DirectoryBacked(self.data,
- self.core.fam)
- except:
- self.logger.error("Failed to load repos: %s, %s" % \
- (self.data, "%s/ssh" % (self.data)))
- raise Bcfg2.Server.Plugin.PluginInitError
-
- def from_yp_cb(self, entry, metadata):
- """Build password file from cached yp data."""
- fname = entry.attrib['name'].split('/')[-1]
- entry.text = self.repository.entries["static.%s" % (fname)].data
- entry.text += self.repository.entries["dyn.%s" % (fname)].data
- perms = {'owner': 'root',
- 'group': 'root',
- 'mode': '0644'}
- [entry.attrib.__setitem__(key, value) for (key, value) in \
- list(perms.items())]
-
- def gen_limits_cb(self, entry, metadata):
- """Build limits entries based on current ACLs."""
- entry.text = self.repository.entries["static.limits.conf"].data
- superusers = self.repository.entries["superusers"].data.split()
- useraccess = [line.split(':') for line in \
- self.repository.entries["useraccess"].data.split()]
- users = [user for (user, host) in \
- useraccess if host == metadata.hostname.split('.')[0]]
- perms = {'owner': 'root',
- 'group': 'root',
- 'mode': '0600'}
- [entry.attrib.__setitem__(key, value) for (key, value) in \
- list(perms.items())]
- entry.text += "".join(["%s hard maxlogins 1024\n" % uname for uname in superusers + users])
- if "*" not in users:
- entry.text += "* hard maxlogins 0\n"
-
- def gen_root_keys_cb(self, entry, metadata):
- """Build root authorized keys file based on current ACLs."""
- superusers = self.repository.entries['superusers'].data.split()
- try:
- rootlike = [line.split(':', 1) for line in \
- self.repository.entries['rootlike'].data.split()]
- superusers += [user for (user, host) in rootlike \
- if host == metadata.hostname.split('.')[0]]
- except:
- pass
- rdata = self.repository.entries
- entry.text = "".join([rdata["%s.key" % user].data for user \
- in superusers if \
- ("%s.key" % user) in rdata])
- perms = {'owner': 'root',
- 'group': 'root',
- 'mode': '0600'}
- [entry.attrib.__setitem__(key, value) for (key, value) \
- in list(perms.items())]
-
- def gen_sudoers(self, entry, metadata):
- """Build root authorized keys file based on current ACLs."""
- superusers = self.repository.entries['superusers'].data.split()
- try:
- rootlike = [line.split(':', 1) for line in \
- self.repository.entries['rootlike'].data.split()]
- superusers += [user for (user, host) in rootlike \
- if host == metadata.hostname.split('.')[0]]
- except:
- pass
- entry.text = self.repository.entries['static.sudoers'].data
- entry.text += "".join(["%s ALL=(ALL) ALL\n" % uname \
- for uname in superusers])
- perms = {'owner': 'root',
- 'group': 'root',
- 'mode': '0440'}
- [entry.attrib.__setitem__(key, value) for (key, value) \
- in list(perms.items())]
diff --git a/src/lib/Bcfg2/Server/Plugins/Base.py b/src/lib/Bcfg2/Server/Plugins/Base.py
index d662da60a..db003f729 100644
--- a/src/lib/Bcfg2/Server/Plugins/Base.py
+++ b/src/lib/Bcfg2/Server/Plugins/Base.py
@@ -21,9 +21,7 @@ class Base(Bcfg2.Server.Plugin.Plugin,
Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
Bcfg2.Server.Plugin.Structure.__init__(self)
try:
- Bcfg2.Server.Plugin.XMLDirectoryBacked.__init__(self,
- self.data,
- self.core.fam)
+ Bcfg2.Server.Plugin.XMLDirectoryBacked.__init__(self, self.data)
except OSError:
self.logger.error("Failed to load Base repository")
raise Bcfg2.Server.Plugin.PluginInitError
diff --git a/src/lib/Bcfg2/Server/Plugins/Bundler.py b/src/lib/Bcfg2/Server/Plugins/Bundler.py
index 6dc3c2b1d..fa993cd85 100644
--- a/src/lib/Bcfg2/Server/Plugins/Bundler.py
+++ b/src/lib/Bcfg2/Server/Plugins/Bundler.py
@@ -12,13 +12,29 @@ import Bcfg2.Server.Lint
from Bcfg2.Options import get_option_parser
try:
- import genshi.template.base
- import Bcfg2.Server.Plugins.TGenshi
+ import genshi.core
+ import genshi.input
+ from genshi.template import TemplateLoader, MarkupTemplate, TemplateError
HAS_GENSHI = True
except ImportError:
HAS_GENSHI = False
+def removecomment(stream):
+ """ A Genshi filter that removes comments from the stream. This
+ function is a generator.
+
+ :param stream: The Genshi stream to remove comments from
+ :type stream: genshi.core.Stream
+ :returns: tuple of ``(kind, data, pos)``, as when iterating
+ through a Genshi stream
+ """
+ for kind, data, pos in stream:
+ if kind is genshi.core.COMMENT:
+ continue
+ yield kind, data, pos
+
+
class BundleFile(Bcfg2.Server.Plugin.StructFile):
""" Representation of a bundle XML file """
def get_xml_value(self, metadata):
@@ -31,16 +47,35 @@ class BundleFile(Bcfg2.Server.Plugin.StructFile):
if HAS_GENSHI:
- class BundleTemplateFile(Bcfg2.Server.Plugins.TGenshi.TemplateFile,
- Bcfg2.Server.Plugin.StructFile):
+ class BundleTemplateFile(Bcfg2.Server.Plugin.StructFile):
""" Representation of a Genshi-templated bundle XML file """
- def __init__(self, name, specific, encoding):
- Bcfg2.Server.Plugins.TGenshi.TemplateFile.__init__(self, name,
- specific,
- encoding)
+ def __init__(self, name, encoding):
Bcfg2.Server.Plugin.StructFile.__init__(self, name)
+ self.encoding = encoding
self.logger = logging.getLogger(name)
+ self.template = None
+
+ def HandleEvent(self, event=None):
+ """Handle all fs events for this template."""
+ if event and event.code2str() == 'deleted':
+ return
+ try:
+ loader = TemplateLoader()
+ self.template = loader.load(self.name, cls=MarkupTemplate,
+ encoding=self.encoding)
+ except LookupError:
+ err = sys.exc_info()[1]
+ self.logger.error('Genshi lookup error in %s: %s' %
+ (self.name, err))
+ except TemplateError:
+ err = sys.exc_info()[1]
+ self.logger.error('Genshi template error in %s: %s' %
+ (self.name, err))
+ except genshi.input.ParseError:
+ err = sys.exc_info()[1]
+ self.logger.error('Genshi parse error in %s: %s' %
+ (self.name, err))
def get_xml_value(self, metadata):
""" get the rendered XML data that applies to the given
@@ -51,8 +86,7 @@ if HAS_GENSHI:
raise Bcfg2.Server.Plugin.PluginExecutionError(msg)
stream = self.template.generate(
metadata=metadata,
- repo=get_option_parser()['repo']).filter(
- Bcfg2.Server.Plugins.TGenshi.removecomment)
+ repo=get_option_parser()['repo']).filter(removecomment)
data = lxml.etree.XML(stream.render('xml',
strip_whitespace=False),
parser=Bcfg2.Server.XMLParser)
@@ -71,11 +105,6 @@ if HAS_GENSHI:
len(rv)))
return rv
- class SGenshiTemplateFile(BundleTemplateFile):
- """ provided for backwards compat with the deprecated SGenshi
- plugin """
- pass
-
class Bundler(Bcfg2.Server.Plugin.Plugin,
Bcfg2.Server.Plugin.Structure,
@@ -91,9 +120,7 @@ class Bundler(Bcfg2.Server.Plugin.Plugin,
self.encoding = core.setup['encoding']
self.__child__ = self.template_dispatch
try:
- Bcfg2.Server.Plugin.XMLDirectoryBacked.__init__(self,
- self.data,
- self.core.fam)
+ Bcfg2.Server.Plugin.XMLDirectoryBacked.__init__(self, self.data)
except OSError:
err = sys.exc_info()[1]
msg = "Failed to load Bundle repository %s: %s" % (self.data, err)
@@ -111,14 +138,13 @@ class Bundler(Bcfg2.Server.Plugin.Plugin,
('py' in nsmap and
nsmap['py'] == 'http://genshi.edgewall.org/')):
if HAS_GENSHI:
- spec = Bcfg2.Server.Plugin.Specificity()
- return BundleTemplateFile(name, spec, self.encoding)
+ return BundleTemplateFile(name, self.encoding)
else:
raise Bcfg2.Server.Plugin.PluginExecutionError("Genshi not "
"available: %s"
% name)
else:
- return BundleFile(name, self.fam)
+ return BundleFile(name)
def BuildStructures(self, metadata):
"""Build all structures for client (metadata)."""
@@ -139,7 +165,7 @@ class Bundler(Bcfg2.Server.Plugin.Plugin,
continue
try:
bundleset.append(entries[0].get_xml_value(metadata))
- except genshi.template.base.TemplateError:
+ except TemplateError:
err = sys.exc_info()[1]
self.logger.error("Bundler: Failed to render templated bundle "
"%s: %s" % (bundlename, err))
diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgCatFilter.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgCatFilter.py
deleted file mode 100644
index 49a5a85b3..000000000
--- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgCatFilter.py
+++ /dev/null
@@ -1,28 +0,0 @@
-""" Handle .cat files, which append lines to and remove lines from
-plaintext files """
-
-from Bcfg2.Server.Plugins.Cfg import CfgFilter
-
-
-class CfgCatFilter(CfgFilter):
- """ CfgCatFilter appends lines to and remove lines from plaintext
- :ref:`server-plugins-generators-Cfg` files"""
-
- #: Handle .cat files
- __extensions__ = ['cat']
-
- #: .cat files are deprecated
- deprecated = True
-
- def modify_data(self, entry, metadata, data):
- datalines = data.strip().split('\n')
- for line in self.data.split('\n'):
- if not line:
- continue
- if line.startswith('+'):
- datalines.append(line[1:])
- elif line.startswith('-'):
- if line[1:] in datalines:
- datalines.remove(line[1:])
- return "\n".join(datalines) + "\n"
- modify_data.__doc__ = CfgFilter.modify_data.__doc__
diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgDiffFilter.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgDiffFilter.py
deleted file mode 100644
index da506a195..000000000
--- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgDiffFilter.py
+++ /dev/null
@@ -1,35 +0,0 @@
-""" Handle .diff files, which apply diffs to plaintext files """
-
-import os
-import tempfile
-from Bcfg2.Server.Plugin import PluginExecutionError
-from subprocess import Popen, PIPE
-from Bcfg2.Server.Plugins.Cfg import CfgFilter
-
-
-class CfgDiffFilter(CfgFilter):
- """ CfgDiffFilter applies diffs to plaintext
- :ref:`server-plugins-generators-Cfg` files """
-
- #: Handle .diff files
- __extensions__ = ['diff']
-
- #: .diff files are deprecated
- deprecated = True
-
- def modify_data(self, entry, metadata, data):
- basehandle, basename = tempfile.mkstemp()
- open(basename, 'w').write(data)
- os.close(basehandle)
-
- cmd = ["patch", "-u", "-f", basename]
- patch = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
- stderr = patch.communicate(input=self.data)[1]
- ret = patch.wait()
- output = open(basename, 'r').read()
- os.unlink(basename)
- if ret != 0:
- raise PluginExecutionError("Error applying diff %s: %s" %
- (self.name, stderr))
- return output
- modify_data.__doc__ = CfgFilter.modify_data.__doc__
diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgLegacyInfo.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgLegacyInfo.py
deleted file mode 100644
index 5122d9aa1..000000000
--- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgLegacyInfo.py
+++ /dev/null
@@ -1,46 +0,0 @@
-""" Handle info and :info files """
-
-import Bcfg2.Server.Plugin
-from Bcfg2.Server.Plugins.Cfg import CfgInfo
-
-
-class CfgLegacyInfo(CfgInfo):
- """ CfgLegacyInfo handles :file:`info` and :file:`:info` files for
- :ref:`server-plugins-generators-cfg` """
-
- #: Handle :file:`info` and :file:`:info`
- __basenames__ = ['info', ':info']
-
- #: CfgLegacyInfo is deprecated. Use
- #: :class:`Bcfg2.Server.Plugins.Cfg.CfgInfoXML.CfgInfoXML` instead.
- deprecated = True
-
- def __init__(self, path):
- CfgInfo.__init__(self, path)
- self.path = path
-
- #: The set of info metadata stored in the file
- self.metadata = None
- __init__.__doc__ = CfgInfo.__init__.__doc__
-
- def bind_info_to_entry(self, entry, metadata):
- self._set_info(entry, self.metadata)
- bind_info_to_entry.__doc__ = CfgInfo.bind_info_to_entry.__doc__
-
- def handle_event(self, event):
- if event.code2str() == 'deleted':
- return
- self.metadata = dict()
- for line in open(self.path).readlines():
- match = Bcfg2.Server.Plugin.INFO_REGEX.match(line)
- if not match:
- self.logger.warning("Failed to parse line in %s: %s" %
- (event.filename, line))
- continue
- else:
- for key, value in list(match.groupdict().items()):
- if value:
- self.metadata[key] = value
- if ('mode' in self.metadata and len(self.metadata['mode']) == 3):
- self.metadata['mode'] = "0%s" % self.metadata['mode']
- handle_event.__doc__ = CfgInfo.handle_event.__doc__
diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py b/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py
index 53cc90094..0d8116c23 100644
--- a/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py
+++ b/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py
@@ -693,13 +693,6 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet,
# raises an appropriate exception
return self._create_data(entry, metadata)
- if entry.get('mode').lower() == 'inherit':
- # use on-disk permissions
- self.logger.warning("Cfg: %s: Use of mode='inherit' is deprecated"
- % entry.get("name"))
- fname = os.path.join(self.path, generator.name)
- entry.set('mode',
- oct_mode(stat.S_IMODE(os.stat(fname).st_mode)))
try:
return generator.get_data(entry, metadata)
except:
@@ -788,13 +781,6 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet,
badattr = [attr for attr in ['owner', 'group', 'mode']
if attr in new_entry]
if badattr:
- # check for info files and inform user of their removal
- for ifile in ['info', ':info']:
- info = os.path.join(self.path, ifile)
- if os.path.exists(info):
- self.logger.info("Removing %s and replacing with info.xml"
- % info)
- os.remove(info)
metadata_updates = {}
metadata_updates.update(self.metadata)
for attr in badattr:
@@ -874,26 +860,11 @@ class CfgLint(Bcfg2.Server.Lint.ServerPlugin):
def Run(self):
for basename, entry in list(self.core.plugins['Cfg'].entries.items()):
- self.check_delta(basename, entry)
self.check_pubkey(basename, entry)
@classmethod
def Errors(cls):
- return {"cat-file-used": "warning",
- "diff-file-used": "warning",
- "no-pubkey-xml": "warning"}
-
- def check_delta(self, basename, entry):
- """ check that no .cat or .diff files are in use """
- for fname, handler in entry.entries.items():
- path = handler.name
- if self.HandlesFile(path) and isinstance(handler, CfgFilter):
- extension = fname.split(".")[-1]
- if extension in ["cat", "diff"]:
- self.LintError("%s-file-used" % extension,
- "%s file used on %s: %s" % (extension,
- basename,
- fname))
+ return {"no-pubkey-xml": "warning"}
def check_pubkey(self, basename, entry):
""" check that privkey.xml files have corresponding pubkey.xml
diff --git a/src/lib/Bcfg2/Server/Plugins/Decisions.py b/src/lib/Bcfg2/Server/Plugins/Decisions.py
index 5521ea045..a7ef25a84 100644
--- a/src/lib/Bcfg2/Server/Plugins/Decisions.py
+++ b/src/lib/Bcfg2/Server/Plugins/Decisions.py
@@ -5,6 +5,7 @@ import os
import sys
import lxml.etree
import Bcfg2.Server.Plugin
+import Bcfg2.Server.FileMonitor
class DecisionFile(Bcfg2.Server.Plugin.SpecificData):
@@ -46,7 +47,7 @@ class Decisions(Bcfg2.Server.Plugin.EntrySet,
DecisionFile,
core.setup['encoding'])
try:
- core.fam.AddMonitor(self.data, self)
+ Bcfg2.Server.FileMonitor.get_fam().AddMonitor(self.data, self)
except OSError:
err = sys.exc_info()[1]
msg = 'Adding filemonitor for %s failed: %s' % (self.data, err)
diff --git a/src/lib/Bcfg2/Server/Plugins/Editor.py b/src/lib/Bcfg2/Server/Plugins/Editor.py
deleted file mode 100644
index f82e0f1dd..000000000
--- a/src/lib/Bcfg2/Server/Plugins/Editor.py
+++ /dev/null
@@ -1,80 +0,0 @@
-import Bcfg2.Server.Plugin
-import re
-import lxml.etree
-
-
-def linesub(pattern, repl, filestring):
- """Substitutes instances of pattern with repl in filestring."""
- if filestring == None:
- filestring = ''
- output = list()
- fileread = filestring.split('\n')
- for line in fileread:
- output.append(re.sub(pattern, repl, filestring))
- return '\n'.join(output)
-
-
-class EditDirectives(Bcfg2.Server.Plugin.SpecificData):
- """This object handles the editing directives."""
- def ProcessDirectives(self, input):
- """Processes a list of edit directives on input."""
- temp = input
- for directive in self.data.split('\n'):
- directive = directive.split(',')
- temp = linesub(directive[0], directive[1], temp)
- return temp
-
-
-class EditEntrySet(Bcfg2.Server.Plugin.EntrySet):
- def __init__(self, basename, path, entry_type, encoding):
- self.ignore = re.compile("^(\.#.*|.*~|\\..*\\.(tmp|sw[px])|%s\.H_.*)$" % path.split('/')[-1])
- Bcfg2.Server.Plugin.EntrySet.__init__(self,
- basename,
- path,
- entry_type,
- encoding)
- self.inputs = dict()
-
- def bind_entry(self, entry, metadata):
- client = metadata.hostname
- filename = entry.get('name')
- permdata = {'owner': 'root',
- 'group': 'root',
- 'mode': '0644'}
- [entry.attrib.__setitem__(key, permdata[key]) for key in permdata]
- entry.text = self.entries['edits'].ProcessDirectives(self.get_client_data(client))
- if not entry.text:
- entry.set('empty', 'true')
- try:
- f = open('%s/%s.H_%s' % (self.path, filename.split('/')[-1], client), 'w')
- f.write(entry.text)
- f.close()
- except:
- pass
-
- def get_client_data(self, client):
- return self.inputs[client]
-
-
-class Editor(Bcfg2.Server.Plugin.GroupSpool,
- Bcfg2.Server.Plugin.Probing):
- name = 'Editor'
- __author__ = 'bcfg2-dev@mcs.anl.gov'
- filename_pattern = 'edits'
- es_child_cls = EditDirectives
- es_cls = EditEntrySet
-
- def GetProbes(self, _):
- '''Return a set of probes for execution on client'''
- probelist = list()
- for name in list(self.entries.keys()):
- probe = lxml.etree.Element('probe')
- probe.set('name', name)
- probe.set('source', "Editor")
- probe.text = "cat %s" % name
- probelist.append(probe)
- return probelist
-
- def ReceiveData(self, client, datalist):
- for data in datalist:
- self.entries[data.get('name')].inputs[client.hostname] = data.text
diff --git a/src/lib/Bcfg2/Server/Plugins/FileProbes.py b/src/lib/Bcfg2/Server/Plugins/FileProbes.py
index 365549e85..461b718e2 100644
--- a/src/lib/Bcfg2/Server/Plugins/FileProbes.py
+++ b/src/lib/Bcfg2/Server/Plugins/FileProbes.py
@@ -11,6 +11,7 @@ import lxml.etree
import Bcfg2.Options
import Bcfg2.Server
import Bcfg2.Server.Plugin
+import Bcfg2.Server.FileMonitor
from Bcfg2.Compat import b64decode
#: The probe we send to clients to get the file data. Returns an XML
@@ -69,7 +70,6 @@ class FileProbes(Bcfg2.Server.Plugin.Plugin,
Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
Bcfg2.Server.Plugin.Probing.__init__(self)
self.config = FileProbesConfig(os.path.join(self.data, 'config.xml'),
- fam=core.fam,
should_monitor=True)
self.entries = dict()
self.probes = dict()
@@ -196,7 +196,7 @@ class FileProbes(Bcfg2.Server.Plugin.Plugin,
if tries >= 10:
self.logger.error("%s still not registered" % filename)
return
- self.core.fam.handle_events_in_interval(1)
+ Bcfg2.Server.FileMonitor.get_fam().handle_events_in_interval(1)
try:
cfg.entries[filename].bind_entry(entry, metadata)
except Bcfg2.Server.Plugin.PluginExecutionError:
diff --git a/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py b/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py
index 1b12e590a..42d860b89 100644
--- a/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py
+++ b/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py
@@ -90,11 +90,7 @@ class PatternFile(Bcfg2.Server.Plugin.XMLFileBacked):
__identifier__ = None
def __init__(self, filename, core=None):
- try:
- fam = core.fam
- except AttributeError:
- fam = None
- Bcfg2.Server.Plugin.XMLFileBacked.__init__(self, filename, fam=fam,
+ Bcfg2.Server.Plugin.XMLFileBacked.__init__(self, filename,
should_monitor=True)
self.core = core
self.patterns = []
diff --git a/src/lib/Bcfg2/Server/Plugins/Hostbase.py b/src/lib/Bcfg2/Server/Plugins/Hostbase.py
deleted file mode 100644
index 55757e0b4..000000000
--- a/src/lib/Bcfg2/Server/Plugins/Hostbase.py
+++ /dev/null
@@ -1,599 +0,0 @@
-"""
-This file provides the Hostbase plugin.
-It manages dns/dhcp/nis host information
-"""
-
-from lxml.etree import Element, SubElement
-import os
-import re
-from time import strftime
-os.environ['DJANGO_SETTINGS_MODULE'] = 'Bcfg2.Server.Hostbase.settings'
-import Bcfg2.Server.Plugin
-from Bcfg2.Server.Plugin import PluginExecutionError, PluginInitError
-from django.template import Context, loader
-from django.db import connection
-# Compatibility imports
-from Bcfg2.Compat import StringIO
-
-try:
- set
-except NameError:
- # deprecated since python 2.6
- from sets import Set as set
-
-
-class Hostbase(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Structure,
- Bcfg2.Server.Plugin.Generator):
- """The Hostbase plugin handles host/network info."""
- name = 'Hostbase'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- filepath = '/my/adm/hostbase/files/bind'
- deprecated = True
-
- def __init__(self, core, datastore):
-
- self.ready = False
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Structure.__init__(self)
- Bcfg2.Server.Plugin.Generator.__init__(self)
- files = ['zone.tmpl',
- 'reversesoa.tmpl',
- 'named.tmpl',
- 'reverseappend.tmpl',
- 'dhcpd.tmpl',
- 'hosts.tmpl',
- 'hostsappend.tmpl']
- self.filedata = {}
- self.dnsservers = []
- self.dhcpservers = []
- self.templates = {'zone': loader.get_template('zone.tmpl'),
- 'reversesoa': loader.get_template('reversesoa.tmpl'),
- 'named': loader.get_template('named.tmpl'),
- 'namedviews': loader.get_template('namedviews.tmpl'),
- 'reverseapp': loader.get_template('reverseappend.tmpl'),
- 'dhcp': loader.get_template('dhcpd.tmpl'),
- 'hosts': loader.get_template('hosts.tmpl'),
- 'hostsapp': loader.get_template('hostsappend.tmpl'),
- }
- self.Entries['ConfigFile'] = {}
- self.__rmi__ = ['rebuildState']
- try:
- self.rebuildState(None)
- except:
- raise PluginInitError
-
- def FetchFile(self, entry, metadata):
- """Return prebuilt file data."""
- fname = entry.get('name').split('/')[-1]
- if not fname in self.filedata:
- raise PluginExecutionError
- perms = {'owner': 'root',
- 'group': 'root',
- 'mode': '644'}
- [entry.attrib.__setitem__(key, value)
- for (key, value) in list(perms.items())]
- entry.text = self.filedata[fname]
-
- def BuildStructures(self, metadata):
- """Build hostbase bundle."""
- if metadata.hostname not in self.dnsservers or metadata.hostname not in self.dhcpservers:
- return []
- output = Element("Bundle", name='hostbase')
- if metadata.hostname in self.dnsservers:
- for configfile in self.Entries['ConfigFile']:
- if re.search('/etc/bind/', configfile):
- SubElement(output, "ConfigFile", name=configfile)
- if metadata.hostname in self.dhcpservers:
- SubElement(output, "ConfigFile", name="/etc/dhcp3/dhcpd.conf")
- return [output]
-
- def rebuildState(self, _):
- """Pre-cache all state information for hostbase config files
- callable as an XMLRPC function.
-
- """
- self.buildZones()
- self.buildDHCP()
- self.buildHosts()
- self.buildHostsLPD()
- self.buildPrinters()
- self.buildNetgroups()
- return True
-
- def buildZones(self):
- """Pre-build and stash zone files."""
- cursor = connection.cursor()
-
- cursor.execute("SELECT id, serial FROM hostbase_zone")
- zones = cursor.fetchall()
-
- for zone in zones:
- # update the serial number for all zone files
- todaydate = (strftime('%Y%m%d'))
- try:
- if todaydate == str(zone[1])[:8]:
- serial = zone[1] + 1
- else:
- serial = int(todaydate) * 100
- except (KeyError):
- serial = int(todaydate) * 100
- cursor.execute("""UPDATE hostbase_zone SET serial = \'%s\' WHERE id = \'%s\'""" % (str(serial), zone[0]))
-
- cursor.execute("SELECT * FROM hostbase_zone WHERE zone NOT LIKE \'%%.rev\'")
- zones = cursor.fetchall()
-
- iplist = []
- hosts = {}
-
- for zone in zones:
- zonefile = StringIO()
- externalzonefile = StringIO()
- cursor.execute("""SELECT n.name FROM hostbase_zone_nameservers z
- INNER JOIN hostbase_nameserver n ON z.nameserver_id = n.id
- WHERE z.zone_id = \'%s\'""" % zone[0])
- nameservers = cursor.fetchall()
- cursor.execute("""SELECT i.ip_addr FROM hostbase_zone_addresses z
- INNER JOIN hostbase_zoneaddress i ON z.zoneaddress_id = i.id
- WHERE z.zone_id = \'%s\'""" % zone[0])
- addresses = cursor.fetchall()
- cursor.execute("""SELECT m.priority, m.mx FROM hostbase_zone_mxs z
- INNER JOIN hostbase_mx m ON z.mx_id = m.id
- WHERE z.zone_id = \'%s\'""" % zone[0])
- mxs = cursor.fetchall()
- context = Context({
- 'zone': zone,
- 'nameservers': nameservers,
- 'addresses': addresses,
- 'mxs': mxs
- })
- zonefile.write(self.templates['zone'].render(context))
- externalzonefile.write(self.templates['zone'].render(context))
-
- querystring = """SELECT h.hostname, p.ip_addr,
- n.name, c.cname, m.priority, m.mx, n.dns_view
- FROM (((((hostbase_host h INNER JOIN hostbase_interface i ON h.id = i.host_id)
- INNER JOIN hostbase_ip p ON i.id = p.interface_id)
- INNER JOIN hostbase_name n ON p.id = n.ip_id)
- INNER JOIN hostbase_name_mxs x ON n.id = x.name_id)
- INNER JOIN hostbase_mx m ON m.id = x.mx_id)
- LEFT JOIN hostbase_cname c ON n.id = c.name_id
- WHERE n.name LIKE '%%%%%s'
- AND h.status = 'active'
- ORDER BY h.hostname, n.name, p.ip_addr
- """ % zone[1]
- cursor.execute(querystring)
- zonehosts = cursor.fetchall()
- prevhost = (None, None, None, None)
- cnames = StringIO()
- cnamesexternal = StringIO()
- for host in zonehosts:
- if not host[2].split(".", 1)[1] == zone[1]:
- zonefile.write(cnames.getvalue())
- externalzonefile.write(cnamesexternal.getvalue())
- cnames = StringIO()
- cnamesexternal = StringIO()
- continue
- if not prevhost[1] == host[1] or not prevhost[2] == host[2]:
- zonefile.write(cnames.getvalue())
- externalzonefile.write(cnamesexternal.getvalue())
- cnames = StringIO()
- cnamesexternal = StringIO()
- zonefile.write("%-32s%-10s%-32s\n" %
- (host[2].split(".", 1)[0], 'A', host[1]))
- zonefile.write("%-32s%-10s%-3s%s.\n" %
- ('', 'MX', host[4], host[5]))
- if host[6] == 'global':
- externalzonefile.write("%-32s%-10s%-32s\n" %
- (host[2].split(".", 1)[0], 'A', host[1]))
- externalzonefile.write("%-32s%-10s%-3s%s.\n" %
- ('', 'MX', host[4], host[5]))
- elif not prevhost[5] == host[5]:
- zonefile.write("%-32s%-10s%-3s%s.\n" %
- ('', 'MX', host[4], host[5]))
- if host[6] == 'global':
- externalzonefile.write("%-32s%-10s%-3s%s.\n" %
- ('', 'MX', host[4], host[5]))
-
- if host[3]:
- try:
- if host[3].split(".", 1)[1] == zone[1]:
- cnames.write("%-32s%-10s%-32s\n" %
- (host[3].split(".", 1)[0],
- 'CNAME', host[2].split(".", 1)[0]))
- if host[6] == 'global':
- cnamesexternal.write("%-32s%-10s%-32s\n" %
- (host[3].split(".", 1)[0],
- 'CNAME', host[2].split(".", 1)[0]))
- else:
- cnames.write("%-32s%-10s%-32s\n" %
- (host[3] + ".",
- 'CNAME',
- host[2].split(".", 1)[0]))
- if host[6] == 'global':
- cnamesexternal.write("%-32s%-10s%-32s\n" %
- (host[3] + ".",
- 'CNAME',
- host[2].split(".", 1)[0]))
-
- except:
- pass
- prevhost = host
- zonefile.write(cnames.getvalue())
- externalzonefile.write(cnamesexternal.getvalue())
- zonefile.write("\n\n%s" % zone[9])
- externalzonefile.write("\n\n%s" % zone[9])
- self.filedata[zone[1]] = zonefile.getvalue()
- self.filedata[zone[1] + ".external"] = externalzonefile.getvalue()
- zonefile.close()
- externalzonefile.close()
- self.Entries['ConfigFile']["%s/%s" % (self.filepath, zone[1])] = self.FetchFile
- self.Entries['ConfigFile']["%s/%s.external" % (self.filepath, zone[1])] = self.FetchFile
-
- cursor.execute("SELECT * FROM hostbase_zone WHERE zone LIKE \'%%.rev\' AND zone <> \'.rev\'")
- reversezones = cursor.fetchall()
-
- reversenames = []
- for reversezone in reversezones:
- cursor.execute("""SELECT n.name FROM hostbase_zone_nameservers z
- INNER JOIN hostbase_nameserver n ON z.nameserver_id = n.id
- WHERE z.zone_id = \'%s\'""" % reversezone[0])
- reverse_nameservers = cursor.fetchall()
-
- context = Context({
- 'inaddr': reversezone[1].rstrip('.rev'),
- 'zone': reversezone,
- 'nameservers': reverse_nameservers,
- })
-
- self.filedata[reversezone[1]] = self.templates['reversesoa'].render(context)
- self.filedata[reversezone[1] + '.external'] = self.templates['reversesoa'].render(context)
- self.filedata[reversezone[1]] += reversezone[9]
- self.filedata[reversezone[1] + '.external'] += reversezone[9]
-
- subnet = reversezone[1].split(".")
- subnet.reverse()
- reversenames.append((reversezone[1].rstrip('.rev'), ".".join(subnet[1:])))
-
- for filename in reversenames:
- cursor.execute("""
- SELECT DISTINCT h.hostname, p.ip_addr, n.dns_view FROM ((hostbase_host h
- INNER JOIN hostbase_interface i ON h.id = i.host_id)
- INNER JOIN hostbase_ip p ON i.id = p.interface_id)
- INNER JOIN hostbase_name n ON n.ip_id = p.id
- WHERE p.ip_addr LIKE '%s%%%%' AND h.status = 'active' ORDER BY p.ip_addr
- """ % filename[1])
- reversehosts = cursor.fetchall()
- zonefile = StringIO()
- externalzonefile = StringIO()
- if len(filename[0].split(".")) == 2:
- originlist = []
- [originlist.append((".".join([ip[1].split(".")[2], filename[0]]),
- ".".join([filename[1], ip[1].split(".")[2]])))
- for ip in reversehosts
- if (".".join([ip[1].split(".")[2], filename[0]]),
- ".".join([filename[1], ip[1].split(".")[2]])) not in originlist]
- for origin in originlist:
- hosts = [(host[1].split("."), host[0])
- for host in reversehosts
- if host[1].rstrip('0123456789').rstrip('.') == origin[1]]
- hosts_external = [(host[1].split("."), host[0])
- for host in reversehosts
- if (host[1].rstrip('0123456789').rstrip('.') == origin[1]
- and host[2] == 'global')]
- context = Context({
- 'hosts': hosts,
- 'inaddr': origin[0],
- 'fileorigin': filename[0],
- })
- zonefile.write(self.templates['reverseapp'].render(context))
- context = Context({
- 'hosts': hosts_external,
- 'inaddr': origin[0],
- 'fileorigin': filename[0],
- })
- externalzonefile.write(self.templates['reverseapp'].render(context))
- else:
- originlist = [filename[0]]
- hosts = [(host[1].split("."), host[0])
- for host in reversehosts
- if (host[1].split("."), host[0]) not in hosts]
- hosts_external = [(host[1].split("."), host[0])
- for host in reversehosts
- if ((host[1].split("."), host[0]) not in hosts_external
- and host[2] == 'global')]
- context = Context({
- 'hosts': hosts,
- 'inaddr': filename[0],
- 'fileorigin': None,
- })
- zonefile.write(self.templates['reverseapp'].render(context))
- context = Context({
- 'hosts': hosts_external,
- 'inaddr': filename[0],
- 'fileorigin': None,
- })
- externalzonefile.write(self.templates['reverseapp'].render(context))
- self.filedata['%s.rev' % filename[0]] += zonefile.getvalue()
- self.filedata['%s.rev.external' % filename[0]] += externalzonefile.getvalue()
- zonefile.close()
- externalzonefile.close()
- self.Entries['ConfigFile']['%s/%s.rev' % (self.filepath, filename[0])] = self.FetchFile
- self.Entries['ConfigFile']['%s/%s.rev.external' % (self.filepath, filename[0])] = self.FetchFile
-
- ## here's where the named.conf file gets written
- context = Context({
- 'zones': zones,
- 'reverses': reversenames,
- })
- self.filedata['named.conf'] = self.templates['named'].render(context)
- self.Entries['ConfigFile']['/my/adm/hostbase/files/named.conf'] = self.FetchFile
- self.filedata['named.conf.views'] = self.templates['namedviews'].render(context)
- self.Entries['ConfigFile']['/my/adm/hostbase/files/named.conf.views'] = self.FetchFile
-
- def buildDHCP(self):
- """Pre-build dhcpd.conf and stash in the filedata table."""
-
- # fetches all the hosts with DHCP == True
- cursor = connection.cursor()
- cursor.execute("""
- SELECT hostname, mac_addr, ip_addr
- FROM (hostbase_host h INNER JOIN hostbase_interface i ON h.id = i.host_id)
- INNER JOIN hostbase_ip ip ON i.id = ip.interface_id
- WHERE i.dhcp=1 AND h.status='active' AND i.mac_addr <> ''
- AND i.mac_addr <> 'float' AND i.mac_addr <> 'unknown'
- ORDER BY h.hostname, i.mac_addr
- """)
-
- dhcphosts = cursor.fetchall()
- count = 0
- hosts = []
- hostdata = [dhcphosts[0][0], dhcphosts[0][1], dhcphosts[0][2]]
- if len(dhcphosts) > 1:
- for x in range(1, len(dhcphosts)):
- # if an interface has 2 or more ip addresses
- # adds the ip to the current interface
- if hostdata[0].split(".")[0] == dhcphosts[x][0].split(".")[0] and hostdata[1] == dhcphosts[x][1]:
- hostdata[2] = ", ".join([hostdata[2], dhcphosts[x][2]])
- # if a host has 2 or more interfaces
- # writes the current one and grabs the next
- elif hostdata[0].split(".")[0] == dhcphosts[x][0].split(".")[0]:
- hosts.append(hostdata)
- count += 1
- hostdata = ["-".join([dhcphosts[x][0], str(count)]), dhcphosts[x][1], dhcphosts[x][2]]
- # new host found, writes current data to the template
- else:
- hosts.append(hostdata)
- count = 0
- hostdata = [dhcphosts[x][0], dhcphosts[x][1], dhcphosts[x][2]]
- #makes sure the last of the data gets written out
- if hostdata not in hosts:
- hosts.append(hostdata)
-
- context = Context({
- 'hosts': hosts,
- 'numips': len(hosts),
- })
-
- self.filedata['dhcpd.conf'] = self.templates['dhcp'].render(context)
- self.Entries['ConfigFile']['/my/adm/hostbase/files/dhcpd.conf'] = self.FetchFile
-
- def buildHosts(self):
- """Pre-build and stash /etc/hosts file."""
-
- append_data = []
-
- cursor = connection.cursor()
- cursor.execute("""
- SELECT hostname FROM hostbase_host ORDER BY hostname
- """)
- hostbase = cursor.fetchall()
- domains = [host[0].split(".", 1)[1] for host in hostbase]
- domains_set = set(domains)
- domain_data = [(domain, domains.count(domain)) for domain in domains_set]
- domain_data.sort()
-
- cursor.execute("""
- SELECT ip_addr FROM hostbase_ip ORDER BY ip_addr
- """)
- ips = cursor.fetchall()
- three_octets = [ip[0].rstrip('0123456789').rstrip('.') \
- for ip in ips]
- three_octets_set = set(three_octets)
- three_octets_data = [(octet, three_octets.count(octet)) \
- for octet in three_octets_set]
- three_octets_data.sort()
-
- for three_octet in three_octets_data:
- querystring = """SELECT h.hostname, h.primary_user,
- p.ip_addr, n.name, c.cname
- FROM (((hostbase_host h INNER JOIN hostbase_interface i ON h.id = i.host_id)
- INNER JOIN hostbase_ip p ON i.id = p.interface_id)
- INNER JOIN hostbase_name n ON p.id = n.ip_id)
- LEFT JOIN hostbase_cname c ON n.id = c.name_id
- WHERE p.ip_addr LIKE \'%s.%%%%\' AND h.status = 'active'""" % three_octet[0]
- cursor.execute(querystring)
- tosort = list(cursor.fetchall())
- tosort.sort(lambda x, y: cmp(int(x[2].split(".")[-1]), int(y[2].split(".")[-1])))
- append_data.append((three_octet, tuple(tosort)))
-
- two_octets = [ip.rstrip('0123456789').rstrip('.') for ip in three_octets]
- two_octets_set = set(two_octets)
- two_octets_data = [(octet, two_octets.count(octet))
- for octet in two_octets_set]
- two_octets_data.sort()
-
- context = Context({
- 'domain_data': domain_data,
- 'three_octets_data': three_octets_data,
- 'two_octets_data': two_octets_data,
- 'three_octets': three_octets,
- 'num_ips': len(three_octets),
- })
-
- self.filedata['hosts'] = self.templates['hosts'].render(context)
-
- for subnet in append_data:
- ips = []
- simple = True
- namelist = [name.split('.', 1)[0] for name in [subnet[1][0][3]]]
- cnamelist = []
- if subnet[1][0][4]:
- cnamelist.append(subnet[1][0][4].split('.', 1)[0])
- simple = False
- appenddata = subnet[1][0]
- for ip in subnet[1][1:]:
- if appenddata[2] == ip[2]:
- namelist.append(ip[3].split('.', 1)[0])
- if ip[4]:
- cnamelist.append(ip[4].split('.', 1)[0])
- simple = False
- appenddata = ip
- else:
- if appenddata[0] == ip[0]:
- simple = False
- ips.append((appenddata[2], appenddata[0], set(namelist),
- cnamelist, simple, appenddata[1]))
- appenddata = ip
- simple = True
- namelist = [ip[3].split('.', 1)[0]]
- cnamelist = []
- if ip[4]:
- cnamelist.append(ip[4].split('.', 1)[0])
- simple = False
- ips.append((appenddata[2], appenddata[0], set(namelist),
- cnamelist, simple, appenddata[1]))
- context = Context({
- 'subnet': subnet[0],
- 'ips': ips,
- })
- self.filedata['hosts'] += self.templates['hostsapp'].render(context)
- self.Entries['ConfigFile']['/mcs/etc/hosts'] = self.FetchFile
-
- def buildPrinters(self):
- """The /mcs/etc/printers.data file"""
- header = """# This file is automatically generated. DO NOT EDIT IT!
-#
-Name Room User Type Notes
-============== ========== ============================== ======================== ====================
-"""
-
- cursor = connection.cursor()
- # fetches all the printers from the database
- cursor.execute("""
- SELECT printq, location, primary_user, comments
- FROM hostbase_host
- WHERE whatami='printer' AND printq <> '' AND status = 'active'
- ORDER BY printq
- """)
- printers = cursor.fetchall()
-
- printersfile = header
- for printer in printers:
- # splits up the printq line and gets the
- # correct description out of the comments section
- temp = printer[3].split('\n')
- for printq in re.split(',[ ]*', printer[0]):
- if len(temp) > 1:
- printersfile += ("%-16s%-12s%-32s%-26s%s\n" %
- (printq, printer[1], printer[2], temp[1], temp[0]))
- else:
- printersfile += ("%-16s%-12s%-32s%-26s%s\n" %
- (printq, printer[1], printer[2], '', printer[3]))
- self.filedata['printers.data'] = printersfile
- self.Entries['ConfigFile']['/mcs/etc/printers.data'] = self.FetchFile
-
- def buildHostsLPD(self):
- """Creates the /mcs/etc/hosts.lpd file"""
-
- # this header needs to be changed to be more generic
- header = """+@machines
-+@all-machines
-achilles.ctd.anl.gov
-raven.ops.anl.gov
-seagull.hr.anl.gov
-parrot.ops.anl.gov
-condor.ops.anl.gov
-delphi.esh.anl.gov
-anlcv1.ctd.anl.gov
-anlvms.ctd.anl.gov
-olivia.ctd.anl.gov\n\n"""
-
- cursor = connection.cursor()
- cursor.execute("""
- SELECT hostname FROM hostbase_host WHERE netgroup=\"red\" AND status = 'active'
- ORDER BY hostname""")
- redmachines = list(cursor.fetchall())
- cursor.execute("""
- SELECT n.name FROM ((hostbase_host h INNER JOIN hostbase_interface i ON h.id = i.host_id)
- INNER JOIN hostbase_ip p ON i.id = p.interface_id) INNER JOIN hostbase_name n ON p.id = n.ip_id
- WHERE netgroup=\"red\" AND n.only=1 AND h.status = 'active'
- """)
- redmachines.extend(list(cursor.fetchall()))
- cursor.execute("""
- SELECT hostname FROM hostbase_host WHERE netgroup=\"win\" AND status = 'active'
- ORDER BY hostname""")
- winmachines = list(cursor.fetchall())
- cursor.execute("""
- SELECT n.name FROM ((hostbase_host h INNER JOIN hostbase_interface i ON h.id = i.host_id)
- INNER JOIN hostbase_ip p ON i.id = p.interface_id) INNER JOIN hostbase_name n ON p.id = n.ip_id
- WHERE netgroup=\"win\" AND n.only=1 AND h.status = 'active'
- """)
- winmachines.__add__(list(cursor.fetchall()))
- hostslpdfile = header
- for machine in redmachines:
- hostslpdfile += machine[0] + "\n"
- hostslpdfile += "\n"
- for machine in winmachines:
- hostslpdfile += machine[0] + "\n"
- self.filedata['hosts.lpd'] = hostslpdfile
- self.Entries['ConfigFile']['/mcs/etc/hosts.lpd'] = self.FetchFile
-
- def buildNetgroups(self):
- """Makes the *-machine files"""
- header = """###################################################################
-# This file lists hosts in the '%s' machine netgroup, it is
-# automatically generated. DO NOT EDIT THIS FILE!
-#
-# Number of hosts in '%s' machine netgroup: %i
-#\n\n"""
-
- cursor = connection.cursor()
- # fetches all the hosts that with valid netgroup entries
- cursor.execute("""
- SELECT h.hostname, n.name, h.netgroup, n.only FROM ((hostbase_host h
- INNER JOIN hostbase_interface i ON h.id = i.host_id)
- INNER JOIN hostbase_ip p ON i.id = p.interface_id)
- INNER JOIN hostbase_name n ON p.id = n.ip_id
- WHERE h.netgroup <> '' AND h.netgroup <> 'none' AND h.status = 'active'
- ORDER BY h.netgroup, h.hostname
- """)
- nameslist = cursor.fetchall()
- # gets the first host and initializes the hash
- hostdata = nameslist[0]
- netgroups = {hostdata[2]: [hostdata[0]]}
- for row in nameslist:
- # if new netgroup, create it
- if row[2] not in netgroups:
- netgroups.update({row[2]: []})
- # if it belongs in the netgroup and has multiple interfaces, put them in
- if hostdata[0] == row[0] and row[3]:
- netgroups[row[2]].append(row[1])
- hostdata = row
- # if its a new host, write the old one to the hash
- elif hostdata[0] != row[0]:
- netgroups[row[2]].append(row[0])
- hostdata = row
-
- for netgroup in netgroups:
- fileoutput = StringIO()
- fileoutput.write(header % (netgroup, netgroup, len(netgroups[netgroup])))
- for each in netgroups[netgroup]:
- fileoutput.write(each + "\n")
- self.filedata['%s-machines' % netgroup] = fileoutput.getvalue()
- fileoutput.close()
- self.Entries['ConfigFile']['/my/adm/hostbase/makenets/machines/%s-machines' % netgroup] = self.FetchFile
-
- cursor.execute("""
- UPDATE hostbase_host SET dirty=0
- """)
diff --git a/src/lib/Bcfg2/Server/Plugins/Ldap.py b/src/lib/Bcfg2/Server/Plugins/Ldap.py
index f724402d0..8e8b078d9 100644
--- a/src/lib/Bcfg2/Server/Plugins/Ldap.py
+++ b/src/lib/Bcfg2/Server/Plugins/Ldap.py
@@ -44,10 +44,10 @@ class ConfigFile(Bcfg2.Server.Plugin.FileBacked):
The approach implemented here is having the user call a registering
decorator that updates a global variable in this module.
"""
- def __init__(self, filename, fam):
+ def __init__(self, filename):
self.filename = filename
Bcfg2.Server.Plugin.FileBacked.__init__(self, self.filename)
- fam.AddMonitor(self.filename, self)
+ self.fam.AddMonitor(self.filename, self)
def Index(self):
"""
@@ -72,7 +72,7 @@ class Ldap(Bcfg2.Server.Plugin.Plugin, Bcfg2.Server.Plugin.Connector):
def __init__(self, core, datastore):
Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
Bcfg2.Server.Plugin.Connector.__init__(self)
- self.config = ConfigFile(self.data + "/config.py", core.fam)
+ self.config = ConfigFile(self.data + "/config.py")
def debug_log(self, message, flag = None):
if (flag is None) and self.debug_flag or flag:
diff --git a/src/lib/Bcfg2/Server/Plugins/Metadata.py b/src/lib/Bcfg2/Server/Plugins/Metadata.py
index 5519d42b5..b64f91ccf 100644
--- a/src/lib/Bcfg2/Server/Plugins/Metadata.py
+++ b/src/lib/Bcfg2/Server/Plugins/Metadata.py
@@ -103,7 +103,6 @@ class XMLMetadataConfig(Bcfg2.Server.Plugin.XMLFileBacked):
# so that XInclude'd files get properly watched
fpath = os.path.join(metadata.data, basefile)
Bcfg2.Server.Plugin.XMLFileBacked.__init__(self, fpath,
- fam=metadata.core.fam,
should_monitor=False)
self.should_monitor = watch_clients
self.metadata = metadata
@@ -112,7 +111,7 @@ class XMLMetadataConfig(Bcfg2.Server.Plugin.XMLFileBacked):
self.basedata = None
self.basedir = metadata.data
self.logger = metadata.logger
- self.pseudo_monitor = isinstance(metadata.core.fam,
+ self.pseudo_monitor = isinstance(Bcfg2.Server.FileMonitor.get_fam(),
Bcfg2.Server.FileMonitor.Pseudo)
def _get_xdata(self):
@@ -250,7 +249,7 @@ class XMLMetadataConfig(Bcfg2.Server.Plugin.XMLFileBacked):
def add_monitor(self, fpath):
self.extras.append(fpath)
- if self.fam and self.should_monitor:
+ if self.should_monitor:
self.fam.AddMonitor(fpath, self.metadata)
def HandleEvent(self, event=None):
@@ -469,7 +468,8 @@ class Metadata(Bcfg2.Server.Plugin.Metadata,
(clients.xml or groups.xml, e.g.) """
if self.watch_clients:
try:
- self.core.fam.AddMonitor(os.path.join(self.data, fname), self)
+ 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)
diff --git a/src/lib/Bcfg2/Server/Plugins/NagiosGen.py b/src/lib/Bcfg2/Server/Plugins/NagiosGen.py
index baea5fe23..fc06be455 100644
--- a/src/lib/Bcfg2/Server/Plugins/NagiosGen.py
+++ b/src/lib/Bcfg2/Server/Plugins/NagiosGen.py
@@ -17,14 +17,14 @@ class NagiosGenConfig(Bcfg2.Server.Plugin.StructFile):
encryption = False
- def __init__(self, filename, fam):
+ def __init__(self, filename):
# create config.xml if missing
if not os.path.exists(filename):
LOGGER.warning("NagiosGen: %s missing. "
"Creating empty one for you." % filename)
open(filename, "w").write("<NagiosGen/>")
- Bcfg2.Server.Plugin.StructFile.__init__(self, filename, fam=fam,
+ Bcfg2.Server.Plugin.StructFile.__init__(self, filename,
should_monitor=True)
@@ -38,8 +38,7 @@ class NagiosGen(Bcfg2.Server.Plugin.Plugin,
def __init__(self, core, datastore):
Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
Bcfg2.Server.Plugin.Generator.__init__(self)
- self.config = NagiosGenConfig(os.path.join(self.data, 'config.xml'),
- core.fam)
+ self.config = NagiosGenConfig(os.path.join(self.data, 'config.xml'))
self.Entries = {'Path':
{'/etc/nagiosgen.status': self.createhostconfig,
'/etc/nagios/nagiosgen.cfg': self.createserverconfig}}
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py b/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py
index 27f493677..57f802bb5 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py
@@ -13,8 +13,7 @@ class AptCollection(Collection):
overrides nothing, and defers all operations to :class:`PacSource`
"""
- def __init__(self, metadata, sources, cachepath, basepath, fam,
- debug=False):
+ def __init__(self, metadata, sources, cachepath, basepath, debug=False):
# we define an __init__ that just calls the parent __init__,
# so that we can set the docstring on __init__ to something
# different from the parent __init__ -- namely, the parent
@@ -22,7 +21,7 @@ class AptCollection(Collection):
# which we use to delineate the actual docs from the
# .. autoattribute hacks we have to do to get private
# attributes included in sphinx 1.0 """
- Collection.__init__(self, metadata, sources, cachepath, basepath, fam,
+ Collection.__init__(self, metadata, sources, cachepath, basepath,
debug=debug)
__init__.__doc__ = Collection.__init__.__doc__.split(".. -----")[0]
@@ -48,10 +47,6 @@ class AptCollection(Collection):
class AptSource(Source):
""" Handle APT sources """
- #: :ref:`server-plugins-generators-packages-magic-groups` for
- #: ``AptSource`` are "apt", "debian", "ubuntu", and "nexenta"
- basegroups = ['apt', 'debian', 'ubuntu', 'nexenta']
-
#: AptSource sets the ``type`` on Package entries to "deb"
ptype = 'deb'
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Collection.py b/src/lib/Bcfg2/Server/Plugins/Packages/Collection.py
index 2c59b9a5a..cf4234ed0 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Collection.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Collection.py
@@ -78,6 +78,7 @@ import copy
import logging
import lxml.etree
import Bcfg2.Server.Plugin
+from Bcfg2.Server.FileMonitor import get_fam
from Bcfg2.Options import get_option_parser
from Bcfg2.Compat import any, md5 # pylint: disable=W0622
@@ -94,8 +95,7 @@ class Collection(list, Bcfg2.Server.Plugin.Debuggable):
#: Whether or not this Packages backend supports package groups
__package_groups__ = False
- def __init__(self, metadata, sources, cachepath, basepath, fam,
- debug=False):
+ def __init__(self, metadata, sources, cachepath, basepath, debug=False):
"""
:param metadata: The client metadata for this collection
:type metadata: Bcfg2.Server.Plugins.Metadata.ClientMetadata
@@ -112,9 +112,6 @@ class Collection(list, Bcfg2.Server.Plugin.Debuggable):
directory, where more permanent data can be
stored
:type basepath: string
- :param fam: A file monitor object to use if this Collection
- needs to monitor for file activity
- :type fam: Bcfg2.Server.FileMonitor.FileMonitor
:param debug: Enable debugging output
:type debug: bool
@@ -128,7 +125,7 @@ class Collection(list, Bcfg2.Server.Plugin.Debuggable):
self.basepath = basepath
self.cachepath = cachepath
self.virt_pkgs = dict()
- self.fam = fam
+ self.fam = get_fam()
self.setup = get_option_parser()
try:
@@ -204,19 +201,6 @@ class Collection(list, Bcfg2.Server.Plugin.Debuggable):
return sorted(list(set(groups)))
@property
- def basegroups(self):
- """ Get a list of group names used by this Collection type in
- resolution of
- :ref:`server-plugins-generators-packages-magic-groups`.
-
- The base implementation simply aggregates the results of
- :attr:`Bcfg2.Server.Plugins.Packages.Source.Source.basegroups`."""
- groups = set()
- for source in self:
- groups.update(source.basegroups)
- return list(groups)
-
- @property
def cachefiles(self):
""" A list of the full path to all cachefiles used by this
collection.
@@ -386,20 +370,6 @@ class Collection(list, Bcfg2.Server.Plugin.Debuggable):
for source in self:
source.filter_unknown(unknown)
- def magic_groups_match(self):
- """ Returns True if the client's
- :ref:`server-plugins-generators-packages-magic-groups` match
- the magic groups for any of the sources contained in this
- Collection.
-
- The base implementation returns True if any source
- :func:`Bcfg2.Server.Plugins.Packages.Source.Source.magic_groups_match`
- returns True.
-
- :returns: bool
- """
- return any(s.magic_groups_match(self.metadata) for s in self)
-
def build_extra_structures(self, independent):
""" Add additional entries to the ``<Independent/>`` section
of the final configuration. This can be used to handle, e.g.,
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Pac.py b/src/lib/Bcfg2/Server/Plugins/Packages/Pac.py
index 99aed5ce5..5f4d2ea41 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Pac.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Pac.py
@@ -12,8 +12,7 @@ class PacCollection(Collection):
overrides nothing, and defers all operations to :class:`PacSource`
"""
- def __init__(self, metadata, sources, cachepath, basepath, fam,
- debug=False):
+ def __init__(self, metadata, sources, cachepath, basepath, debug=False):
# we define an __init__ that just calls the parent __init__,
# so that we can set the docstring on __init__ to something
# different from the parent __init__ -- namely, the parent
@@ -21,7 +20,7 @@ class PacCollection(Collection):
# which we use to delineate the actual docs from the
# .. autoattribute hacks we have to do to get private
# attributes included in sphinx 1.0 """
- Collection.__init__(self, metadata, sources, cachepath, basepath, fam,
+ Collection.__init__(self, metadata, sources, cachepath, basepath,
debug=debug)
__init__.__doc__ = Collection.__init__.__doc__.split(".. -----")[0]
@@ -29,10 +28,6 @@ class PacCollection(Collection):
class PacSource(Source):
""" Handle Pacman sources """
- #: :ref:`server-plugins-generators-packages-magic-groups` for
- #: ``PacSource`` are "arch" and "parabola"
- basegroups = ['arch', 'parabola']
-
#: PacSource sets the ``type`` on Package entries to "pacman"
ptype = 'pacman'
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py b/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py
index f528076c4..876ee6090 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py
@@ -20,7 +20,7 @@ class PackagesSources(Bcfg2.Server.Plugin.StructFile,
encryption = False
- def __init__(self, filename, cachepath, fam, packages):
+ def __init__(self, filename, cachepath, packages):
"""
:param filename: The full path to ``sources.xml``
:type filename: string
@@ -28,9 +28,6 @@ class PackagesSources(Bcfg2.Server.Plugin.StructFile,
:class:`Bcfg2.Server.Plugins.Packages.Source.Source`
data will be cached
:type cachepath: string
- :param fam: The file access monitor to use to create watches
- on ``sources.xml`` and any XIncluded files.
- :type fam: Bcfg2.Server.FileMonitor.FileMonitor
:param packages: The Packages plugin object ``sources.xml`` is
being parsed on behalf of (i.e., the calling
object)
@@ -41,7 +38,7 @@ class PackagesSources(Bcfg2.Server.Plugin.StructFile,
"""
Bcfg2.Server.Plugin.Debuggable.__init__(self)
try:
- Bcfg2.Server.Plugin.StructFile.__init__(self, filename, fam=fam,
+ Bcfg2.Server.Plugin.StructFile.__init__(self, filename,
should_monitor=True)
except OSError:
err = sys.exc_info()[1]
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Source.py b/src/lib/Bcfg2/Server/Plugins/Packages/Source.py
index 33eff60c8..7a8b2827a 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Source.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Source.py
@@ -27,7 +27,6 @@ in your ``Source`` subclass:
* :func:`Source.urls`
* :func:`Source.read_files`
-* :attr:`Source.basegroups`
Additionally, you may want to consider overriding the following
methods and attributes:
@@ -107,11 +106,6 @@ class Source(Bcfg2.Server.Plugin.Debuggable): # pylint: disable=R0902
those features.
"""
- #: The list of
- #: :ref:`server-plugins-generators-packages-magic-groups` that
- #: make sources of this type available to clients.
- basegroups = []
-
#: The Package type handled by this Source class. The ``type``
#: attribute of Package entries will be set to the value ``ptype``
#: when they are handled by :mod:`Bcfg2.Server.Plugins.Packages`.
@@ -303,8 +297,7 @@ class Source(Bcfg2.Server.Plugin.Debuggable): # pylint: disable=R0902
:return: list of strings - group names
"""
return sorted(list(set([g for g in metadata.groups
- if (g in self.basegroups or
- g in self.groups or
+ if (g in self.groups or
g in self.arches)])))
def load_state(self):
@@ -631,16 +624,15 @@ class Source(Bcfg2.Server.Plugin.Debuggable): # pylint: disable=R0902
def applies(self, metadata):
""" Return true if this source applies to the given client,
- i.e., the client is in all necessary groups and
- :ref:`server-plugins-generators-packages-magic-groups`.
+ i.e., the client is in all necessary groups.
:param metadata: The client metadata to check to see if this
source applies
:type metadata: Bcfg2.Server.Plugins.Metadata.ClientMetadata
:returns: bool
"""
- # check base groups
- if not self.magic_groups_match(metadata):
+ # check arch groups
+ if not self.arch_groups_match(metadata):
return False
# check Group/Client tags from sources.xml
@@ -711,29 +703,13 @@ class Source(Bcfg2.Server.Plugin.Debuggable): # pylint: disable=R0902
"""
return []
- def magic_groups_match(self, metadata):
- """ Returns True if the client's
- :ref:`server-plugins-generators-packages-magic-groups` match
- the magic groups this source. Also returns True if magic
- groups are off in the configuration and the client's
- architecture matches (i.e., architecture groups are *always*
- checked).
+ def arch_groups_match(self, metadata):
+ """ Returns True if the client is in an arch group that
+ matches the arch of this source.
:returns: bool
"""
- found_arch = False
for arch in self.arches:
if arch in metadata.groups:
- found_arch = True
- break
- if not found_arch:
- return False
-
- if not self.setup.cfp.getboolean("packages", "magic_groups",
- default=False):
- return True
- else:
- for group in self.basegroups:
- if group in metadata.groups:
- return True
- return False
+ return True
+ return False
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py
index 1ad699208..c5d59eb24 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py
@@ -59,6 +59,7 @@ import socket
import logging
import lxml.etree
from subprocess import Popen, PIPE
+import Bcfg2.Server.FileMonitor
import Bcfg2.Server.Plugin
from Bcfg2.Options import get_option_parser
# pylint: disable=W0622
@@ -174,7 +175,7 @@ class PulpCertificateSet(Bcfg2.Server.Plugin.EntrySet):
#: The path to certificates on consumer machines
certpath = "/etc/pki/consumer/cert.pem"
- def __init__(self, path, fam):
+ def __init__(self, path):
"""
:param path: The path to the directory where Pulp consumer
certificates will be stored
@@ -192,7 +193,7 @@ class PulpCertificateSet(Bcfg2.Server.Plugin.EntrySet):
important='true',
sensitive='true',
paranoid=self.metadata['paranoid'])
- self.fam = fam
+ self.fam = Bcfg2.Server.FileMonitor.get_fam()
self.fam.AddMonitor(path, self)
def HandleEvent(self, event):
@@ -271,9 +272,8 @@ class YumCollection(Collection):
#: :class:`PulpCertificateSet` object used to handle Pulp certs
pulp_cert_set = None
- def __init__(self, metadata, sources, cachepath, basepath, fam,
- debug=False):
- Collection.__init__(self, metadata, sources, cachepath, basepath, fam,
+ def __init__(self, metadata, sources, cachepath, basepath, debug=False):
+ Collection.__init__(self, metadata, sources, cachepath, basepath,
debug=debug)
self.keypath = os.path.join(self.cachepath, "keys")
@@ -309,7 +309,7 @@ class YumCollection(Collection):
self.logger.error("Could not create Pulp consumer "
"cert directory at %s: %s" %
(certdir, err))
- self.pulp_cert_set = PulpCertificateSet(certdir, self.fam)
+ self.pulp_cert_set = PulpCertificateSet(certdir)
@property
def __package_groups__(self):
@@ -933,10 +933,6 @@ class YumCollection(Collection):
class YumSource(Source):
""" Handle yum sources """
- #: :ref:`server-plugins-generators-packages-magic-groups` for
- #: ``YumSource`` are "yum", "redhat", "centos", and "fedora"
- basegroups = ['yum', 'redhat', 'centos', 'fedora']
-
#: YumSource sets the ``type`` on Package entries to "yum"
ptype = 'yum'
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py b/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py
index db64cf309..169dcd588 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py
@@ -64,14 +64,6 @@ class Packages(Bcfg2.Server.Plugin.Plugin,
# create key directory if needed
os.makedirs(self.keypath)
- # warn about deprecated magic groups
- if self.core.setup.cfp.getboolean("packages", "magic_groups",
- default=False):
- self.logger.warning("Packages: Magic groups are deprecated and "
- "will be removed in a future release")
- self.logger.warning("You can disable magic groups by setting "
- "magic_groups=0 in [packages] in bcfg2.conf")
-
# pylint: disable=C0301
#: The
#: :class:`Bcfg2.Server.Plugins.Packages.PackagesSources.PackagesSources`
@@ -79,7 +71,7 @@ class Packages(Bcfg2.Server.Plugin.Plugin,
#: :class:`Bcfg2.Server.Plugins.Packages.Source.Source` objects for
#: this plugin.
self.sources = PackagesSources(os.path.join(self.data, "sources.xml"),
- self.cachepath, core.fam, self)
+ self.cachepath, self)
#: We cache
#: :class:`Bcfg2.Server.Plugins.Packages.Collection.Collection`
@@ -229,13 +221,7 @@ class Packages(Bcfg2.Server.Plugin.Plugin,
:raises: :class:`Bcfg2.Server.Plugin.exceptions.PluginExecutionError`
"""
if entry.tag == 'Package':
- if self.core.setup.cfp.getboolean("packages", "magic_groups",
- default=False):
- collection = self.get_collection(metadata)
- if collection.magic_groups_match():
- return True
- else:
- return True
+ return True
elif entry.tag == 'Path':
# managed entries for yum/apt configs
if (entry.get("name") == \
@@ -476,8 +462,7 @@ class Packages(Bcfg2.Server.Plugin.Plugin,
if not self.sources.loaded:
# if sources.xml has not received a FAM event yet, defer;
# instantiate a dummy Collection object
- return Collection(metadata, [], self.cachepath, self.data,
- self.core.fam)
+ return Collection(metadata, [], self.cachepath, self.data)
if metadata.hostname in self.clients:
return self.collections[self.clients[metadata.hostname]]
@@ -508,7 +493,7 @@ class Packages(Bcfg2.Server.Plugin.Plugin,
"for %s" % (cclass.__name__, metadata.hostname))
collection = cclass(metadata, relevant, self.cachepath, self.data,
- self.core.fam, debug=self.debug_flag)
+ debug=self.debug_flag)
ckey = collection.cachekey
self.clients[metadata.hostname] = ckey
self.collections[ckey] = collection
diff --git a/src/lib/Bcfg2/Server/Plugins/Probes.py b/src/lib/Bcfg2/Server/Plugins/Probes.py
index f106b75a4..7b8ef2209 100644
--- a/src/lib/Bcfg2/Server/Plugins/Probes.py
+++ b/src/lib/Bcfg2/Server/Plugins/Probes.py
@@ -9,6 +9,7 @@ import operator
import lxml.etree
import Bcfg2.Server
import Bcfg2.Server.Plugin
+import Bcfg2.Server.FileMonitor
try:
from django.db import models
@@ -117,12 +118,12 @@ class ProbeSet(Bcfg2.Server.Plugin.EntrySet):
bangline = re.compile('^#!\s*(?P<interpreter>.*)$')
basename_is_regex = True
- def __init__(self, path, fam, encoding, plugin_name):
+ def __init__(self, path, encoding, plugin_name):
self.plugin_name = plugin_name
Bcfg2.Server.Plugin.EntrySet.__init__(self, '[0-9A-Za-z_\-]+', path,
Bcfg2.Server.Plugin.SpecificData,
encoding)
- fam.AddMonitor(path, self)
+ Bcfg2.Server.FileMonitor.get_fam().AddMonitor(path, self)
def HandleEvent(self, event):
""" handle events on everything but probed.xml """
@@ -178,7 +179,7 @@ class Probes(Bcfg2.Server.Plugin.Probing,
Bcfg2.Server.Plugin.DatabaseBacked.__init__(self, core, datastore)
try:
- self.probes = ProbeSet(self.data, core.fam, core.setup['encoding'],
+ self.probes = ProbeSet(self.data, core.setup['encoding'],
self.name)
except:
err = sys.exc_info()[1]
diff --git a/src/lib/Bcfg2/Server/Plugins/Properties.py b/src/lib/Bcfg2/Server/Plugins/Properties.py
index 24daa2107..b7ede594c 100644
--- a/src/lib/Bcfg2/Server/Plugins/Properties.py
+++ b/src/lib/Bcfg2/Server/Plugins/Properties.py
@@ -88,8 +88,8 @@ class PropertyFile(object):
class JSONPropertyFile(Bcfg2.Server.Plugin.FileBacked, PropertyFile):
""" Handle JSON Properties files. """
- def __init__(self, name, fam=None):
- Bcfg2.Server.Plugin.FileBacked.__init__(self, name, fam=fam)
+ 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__
@@ -127,8 +127,8 @@ class JSONPropertyFile(Bcfg2.Server.Plugin.FileBacked, PropertyFile):
class YAMLPropertyFile(Bcfg2.Server.Plugin.FileBacked, PropertyFile):
""" Handle YAML Properties files. """
- def __init__(self, name, fam=None):
- Bcfg2.Server.Plugin.FileBacked.__init__(self, name, fam=fam)
+ def __init__(self, name):
+ Bcfg2.Server.Plugin.FileBacked.__init__(self, name)
PropertyFile.__init__(self, name)
self.yaml = None
__init__.__doc__ = Bcfg2.Server.Plugin.FileBacked.__init__.__doc__
@@ -166,8 +166,8 @@ class YAMLPropertyFile(Bcfg2.Server.Plugin.FileBacked, PropertyFile):
class XMLPropertyFile(Bcfg2.Server.Plugin.StructFile, PropertyFile):
""" Handle XML Properties files. """
- def __init__(self, name, fam=None, should_monitor=False):
- Bcfg2.Server.Plugin.StructFile.__init__(self, name, fam=fam,
+ def __init__(self, name, should_monitor=False):
+ Bcfg2.Server.Plugin.StructFile.__init__(self, name,
should_monitor=should_monitor)
PropertyFile.__init__(self, name)
__init__.__doc__ = Bcfg2.Server.Plugin.StructFile.__init__.__doc__
@@ -239,8 +239,8 @@ class PropDirectoryBacked(Bcfg2.Server.Plugin.DirectoryBacked):
#: Ignore XML schema (``.xsd``) files
ignore = re.compile(r'.*\.xsd$')
- def __init__(self, data, fam):
- Bcfg2.Server.Plugin.DirectoryBacked.__init__(self, data, fam)
+ def __init__(self, data):
+ Bcfg2.Server.Plugin.DirectoryBacked.__init__(self, data)
#: Instead of creating children of this object with a static
#: object, we use :func:`property_dispatcher` to create a
@@ -248,23 +248,21 @@ class PropDirectoryBacked(Bcfg2.Server.Plugin.DirectoryBacked):
self.__child__ = self.property_dispatcher
__init__.__doc__ = Bcfg2.Server.Plugin.DirectoryBacked.__init__.__doc__
- def property_dispatcher(self, fname, fam):
+ def property_dispatcher(self, fname):
""" Dispatch an event on a Properties file to the
appropriate object.
:param fname: The name of the file that received the event
:type fname: string
- :param fam: The file monitor the event was received by
- :type fam: Bcfg2.Server.FileMonitor.FileMonitor
:returns: An object of the appropriate subclass of
:class:`PropertyFile`
"""
if fname.endswith(".xml"):
- return XMLPropertyFile(fname, fam)
+ return XMLPropertyFile(fname)
elif HAS_JSON and fname.endswith(".json"):
- return JSONPropertyFile(fname, fam)
+ return JSONPropertyFile(fname)
elif HAS_YAML and (fname.endswith(".yaml") or fname.endswith(".yml")):
- return YAMLPropertyFile(fname, fam)
+ return YAMLPropertyFile(fname)
else:
raise Bcfg2.Server.Plugin.PluginExecutionError(
"Properties: Unknown extension %s" % fname)
@@ -279,7 +277,7 @@ class Properties(Bcfg2.Server.Plugin.Plugin,
Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
Bcfg2.Server.Plugin.Connector.__init__(self)
try:
- self.store = PropDirectoryBacked(self.data, core.fam)
+ self.store = PropDirectoryBacked(self.data)
except OSError:
err = sys.exc_info()[1]
self.logger.error("Error while creating Properties store: %s" %
diff --git a/src/lib/Bcfg2/Server/Plugins/PuppetENC.py b/src/lib/Bcfg2/Server/Plugins/PuppetENC.py
index 801e7006d..221f49e3c 100644
--- a/src/lib/Bcfg2/Server/Plugins/PuppetENC.py
+++ b/src/lib/Bcfg2/Server/Plugins/PuppetENC.py
@@ -35,8 +35,7 @@ class PuppetENC(Bcfg2.Server.Plugin.Plugin,
Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
Bcfg2.Server.Plugin.Connector.__init__(self)
Bcfg2.Server.Plugin.ClientRunHooks.__init__(self)
- Bcfg2.Server.Plugin.DirectoryBacked.__init__(self, self.data,
- self.core.fam)
+ Bcfg2.Server.Plugin.DirectoryBacked.__init__(self, self.data)
self.cache = dict()
def _run_encs(self, metadata):
diff --git a/src/lib/Bcfg2/Server/Plugins/SSHbase.py b/src/lib/Bcfg2/Server/Plugins/SSHbase.py
index c7db67301..7b6c9c418 100644
--- a/src/lib/Bcfg2/Server/Plugins/SSHbase.py
+++ b/src/lib/Bcfg2/Server/Plugins/SSHbase.py
@@ -135,7 +135,8 @@ class SSHbase(Bcfg2.Server.Plugin.Plugin,
# do so once
self.badnames = dict()
- core.fam.AddMonitor(self.data, self)
+ self.fam = Bcfg2.Server.FileMonitor.get_fam()
+ self.fam.AddMonitor(self.data, self)
self.static = dict()
self.entries = dict()
@@ -256,7 +257,7 @@ class SSHbase(Bcfg2.Server.Plugin.Plugin,
self.skn = False
return
- if event.filename in ['info', 'info.xml', ':info']:
+ if event.filename == 'info.xml':
for entry in list(self.entries.values()):
entry.handle_event(event)
return
@@ -368,7 +369,7 @@ class SSHbase(Bcfg2.Server.Plugin.Plugin,
msg = "%s still not registered" % filename
self.logger.error(msg)
raise Bcfg2.Server.Plugin.PluginExecutionError(msg)
- self.core.fam.handle_events_in_interval(1)
+ self.fam.handle_events_in_interval(1)
tries += 1
try:
self.entries[entry.get('name')].bind_entry(entry, metadata)
diff --git a/src/lib/Bcfg2/Server/Plugins/Snapshots.py b/src/lib/Bcfg2/Server/Plugins/Snapshots.py
deleted file mode 100644
index cc5946bb2..000000000
--- a/src/lib/Bcfg2/Server/Plugins/Snapshots.py
+++ /dev/null
@@ -1,129 +0,0 @@
-import logging
-import difflib
-import Bcfg2.Server.Plugin
-import Bcfg2.Server.Snapshots
-import Bcfg2.Logger
-from Bcfg2.Server.Snapshots.model import Snapshot
-import sys
-import time
-import threading
-
-# Compatibility import
-from Bcfg2.Compat import Queue, u_str, b64decode
-
-logger = logging.getLogger('Snapshots')
-
-ftypes = ['ConfigFile', 'SymLink', 'Directory']
-datafields = {
- 'Package': ['version'],
- 'Path': ['type'],
- 'Service': ['status'],
- 'ConfigFile': ['owner', 'group', 'mode'],
- 'Directory': ['owner', 'group', 'mode'],
- 'SymLink': ['to'],
- }
-
-
-def build_snap_ent(entry):
- basefields = []
- if entry.tag in ['Package', 'Service']:
- basefields += ['type']
- desired = dict([(key, u_str(entry.get(key))) for key in basefields])
- state = dict([(key, u_str(entry.get(key))) for key in basefields])
- desired.update([(key, u_str(entry.get(key))) for key in \
- datafields[entry.tag]])
- if entry.tag == 'ConfigFile' or \
- ((entry.tag == 'Path') and (entry.get('type') == 'file')):
- if entry.text == None:
- desired['contents'] = None
- else:
- if entry.get('encoding', 'ascii') == 'ascii':
- desired['contents'] = u_str(entry.text)
- else:
- desired['contents'] = u_str(b64decode(entry.text))
-
- if 'current_bfile' in entry.attrib:
- state['contents'] = u_str(b64decode(entry.get('current_bfile')))
- elif 'current_bdiff' in entry.attrib:
- diff = b64decode(entry.get('current_bdiff'))
- state['contents'] = u_str( \
- '\n'.join(difflib.restore(diff.split('\n'), 1)))
-
- state.update([(key, u_str(entry.get('current_' + key, entry.get(key)))) \
- for key in datafields[entry.tag]])
- if entry.tag in ['ConfigFile', 'Path'] and entry.get('exists', 'true') == 'false':
- state = None
- return [desired, state]
-
-
-class Snapshots(Bcfg2.Server.Plugin.Statistics):
- name = 'Snapshots'
- deprecated = True
-
- def __init__(self, core, datastore):
- 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)
-
- def start_threads(self):
- self.loader.start()
-
- def load_snapshot(self):
- while self.running:
- try:
- (metadata, data) = self.work_queue.get(block=True, timeout=5)
- except:
- continue
- self.statistics_from_old_stats(metadata, data)
-
- def process_statistics(self, metadata, data):
- return self.work_queue.put((metadata, data))
-
- def statistics_from_old_stats(self, metadata, xdata):
- # entries are name -> (modified, correct, start, desired, end)
- # not sure we can get all of this from old format stats
- t1 = time.time()
- entries = dict([('Package', dict()),
- ('Service', dict()), ('Path', dict())])
- extra = dict([('Package', dict()), ('Service', dict()),
- ('Path', dict())])
- bad = []
- state = xdata.find('.//Statistics')
- correct = state.get('state') == 'clean'
- revision = u_str(state.get('revision', '-1'))
- for entry in state.find('.//Bad'):
- data = [False, False, u_str(entry.get('name'))] \
- + build_snap_ent(entry)
- if entry.tag in ftypes:
- etag = 'Path'
- else:
- etag = entry.tag
- entries[etag][entry.get('name')] = data
- for entry in state.find('.//Modified'):
- if entry.tag in ftypes:
- etag = 'Path'
- else:
- etag = entry.tag
- if entry.get('name') in entries[etag]:
- data = [True, False, u_str(entry.get('name'))] + \
- build_snap_ent(entry)
- else:
- data = [True, False, u_str(entry.get('name'))] + \
- build_snap_ent(entry)
- for entry in state.find('.//Extra'):
- if entry.tag in datafields:
- data = build_snap_ent(entry)[1]
- ename = u_str(entry.get('name'))
- data['name'] = ename
- extra[entry.tag][ename] = data
- else:
- print("extra", entry.tag, entry.get('name'))
- t2 = time.time()
- snap = Snapshot.from_data(self.session, correct, revision,
- metadata, entries, extra)
- self.session.add(snap)
- self.session.commit()
- t3 = time.time()
- logger.info("Snapshot storage took %fs" % (t3 - t2))
- return True
diff --git a/src/lib/Bcfg2/Server/Plugins/Statistics.py b/src/lib/Bcfg2/Server/Plugins/Statistics.py
deleted file mode 100644
index 7fae445d0..000000000
--- a/src/lib/Bcfg2/Server/Plugins/Statistics.py
+++ /dev/null
@@ -1,160 +0,0 @@
-'''This file manages the statistics collected by the BCFG2 Server'''
-
-import copy
-import difflib
-import logging
-import lxml.etree
-import os
-import sys
-from time import asctime, localtime, time, strptime, mktime
-import threading
-from Bcfg2.Compat import b64decode
-import Bcfg2.Server.Plugin
-
-
-class StatisticsStore(object):
- """Manages the memory and file copy of statistics collected about client runs."""
- __min_write_delay__ = 0
-
- def __init__(self, filename):
- self.filename = filename
- self.element = lxml.etree.Element('Dummy')
- self.dirty = 0
- self.lastwrite = 0
- self.logger = logging.getLogger('Bcfg2.Server.Statistics')
- self.ReadFromFile()
-
- def WriteBack(self, force=0):
- """Write statistics changes back to persistent store."""
- if (self.dirty and (self.lastwrite + self.__min_write_delay__ <= time())) \
- or force:
- try:
- fout = open(self.filename + '.new', 'w')
- except IOError:
- ioerr = sys.exc_info()[1]
- self.logger.error("Failed to open %s for writing: %s" % (self.filename + '.new', ioerr))
- else:
- fout.write(lxml.etree.tostring(self.element,
- xml_declaration=False).decode('UTF-8'))
- fout.close()
- os.rename(self.filename + '.new', self.filename)
- self.dirty = 0
- self.lastwrite = time()
-
- def ReadFromFile(self):
- """Reads current state regarding statistics."""
- try:
- fin = open(self.filename, 'r')
- data = fin.read()
- fin.close()
- self.element = lxml.etree.XML(data)
- self.dirty = 0
- except (IOError, lxml.etree.XMLSyntaxError):
- self.logger.error("Creating new statistics file %s"%(self.filename))
- self.element = lxml.etree.Element('ConfigStatistics')
- self.WriteBack()
- self.dirty = 0
-
- def updateStats(self, xml, client):
- """Updates the statistics of a current node with new data."""
-
- # Current policy:
- # - Keep anything less than 24 hours old
- # - Keep latest clean run for clean nodes
- # - Keep latest clean and dirty run for dirty nodes
- newstat = xml.find('Statistics')
-
- if newstat.get('state') == 'clean':
- node_dirty = 0
- else:
- node_dirty = 1
-
- # Find correct node entry in stats data
- # The following list comprehension should be guarenteed to return at
- # most one result
- nodes = [elem for elem in self.element.findall('Node') \
- if elem.get('name') == client]
- nummatch = len(nodes)
- if nummatch == 0:
- # Create an entry for this node
- node = lxml.etree.SubElement(self.element, 'Node', name=client)
- elif nummatch == 1 and not node_dirty:
- # Delete old instance
- node = nodes[0]
- [node.remove(elem) for elem in node.findall('Statistics') \
- if self.isOlderThan24h(elem.get('time'))]
- elif nummatch == 1 and node_dirty:
- # Delete old dirty statistics entry
- node = nodes[0]
- [node.remove(elem) for elem in node.findall('Statistics') \
- if (elem.get('state') == 'dirty' \
- and self.isOlderThan24h(elem.get('time')))]
- else:
- # Shouldn't be reached
- self.logger.error("Duplicate node entry for %s"%(client))
-
- # Set current time for stats
- newstat.set('time', asctime(localtime()))
-
- # Add statistic
- node.append(copy.copy(newstat))
-
- # Set dirty
- self.dirty = 1
- self.WriteBack(force=1)
-
- def isOlderThan24h(self, testTime):
- """Helper function to determine if <time> string is older than 24 hours."""
- now = time()
- utime = mktime(strptime(testTime))
- secondsPerDay = 60*60*24
-
- return (now-utime) > secondsPerDay
-
-
-class Statistics(Bcfg2.Server.Plugin.ThreadedStatistics,
- Bcfg2.Server.Plugin.PullSource):
- name = 'Statistics'
- deprecated = True
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.ThreadedStatistics.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.PullSource.__init__(self)
- fpath = "%s/etc/statistics.xml" % datastore
- self.data_file = StatisticsStore(fpath)
-
- def handle_statistic(self, metadata, data):
- self.data_file.updateStats(data, metadata.hostname)
-
- def FindCurrent(self, client):
- rt = self.data_file.element.xpath('//Node[@name="%s"]' % client)[0]
- maxtime = max([strptime(stat.get('time')) for stat \
- in rt.findall('Statistics')])
- return [stat for stat in rt.findall('Statistics') \
- if strptime(stat.get('time')) == maxtime][0]
-
- def GetExtra(self, client):
- return [(entry.tag, entry.get('name')) for entry \
- in self.FindCurrent(client).xpath('.//Extra/*')]
-
- def GetCurrentEntry(self, client, e_type, e_name):
- curr = self.FindCurrent(client)
- entry = curr.xpath('.//Bad/%s[@name="%s"]' % (e_type, e_name))
- if not entry:
- raise Bcfg2.Server.Plugin.PluginExecutionError
- cfentry = entry[-1]
-
- owner = cfentry.get('current_owner', cfentry.get('owner'))
- group = cfentry.get('current_group', cfentry.get('group'))
- mode = cfentry.get('current_mode', cfentry.get('mode'))
- if cfentry.get('sensitive') in ['true', 'True']:
- raise Bcfg2.Server.Plugin.PluginExecutionError
- elif 'current_bfile' in cfentry.attrib:
- contents = b64decode(cfentry.get('current_bfile'))
- elif 'current_bdiff' in cfentry.attrib:
- diff = b64decode(cfentry.get('current_bdiff'))
- contents = '\n'.join(difflib.restore(diff.split('\n'), 1))
- else:
- contents = None
-
- return (owner, group, mode, contents)
diff --git a/src/lib/Bcfg2/Server/Plugins/TCheetah.py b/src/lib/Bcfg2/Server/Plugins/TCheetah.py
deleted file mode 100644
index f2c59ce29..000000000
--- a/src/lib/Bcfg2/Server/Plugins/TCheetah.py
+++ /dev/null
@@ -1,79 +0,0 @@
-'''This module implements a templating generator based on Cheetah'''
-
-import logging
-import sys
-import traceback
-import Bcfg2.Server.Plugin
-
-from Bcfg2.Compat import unicode, b64encode
-
-logger = logging.getLogger('Bcfg2.Plugins.TCheetah')
-
-try:
- import Cheetah.Template
- import Cheetah.Parser
-except:
- logger.error("TCheetah: Failed to import Cheetah. Is it installed?")
- raise
-
-
-class TemplateFile:
- """Template file creates Cheetah template structures for the loaded file."""
-
- def __init__(self, name, specific, encoding):
- self.name = name
- self.specific = specific
- self.encoding = encoding
- self.template = None
- self.searchlist = dict()
-
- def handle_event(self, event):
- """Handle all fs events for this template."""
- if event.code2str() == 'deleted':
- return
- try:
- s = {'useStackFrames': False}
- self.template = Cheetah.Template.Template(open(self.name).read(),
- compilerSettings=s,
- searchList=self.searchlist)
- except Cheetah.Parser.ParseError:
- perror = sys.exc_info()[1]
- logger.error("Cheetah parse error for file %s" % (self.name))
- logger.error(perror.report())
-
- def bind_entry(self, entry, metadata):
- """Build literal file information."""
- self.template.metadata = metadata
- self.searchlist['metadata'] = metadata
- self.template.path = entry.get('realname', entry.get('name'))
- self.searchlist['path'] = entry.get('realname', entry.get('name'))
- self.template.source_path = self.name
- self.searchlist['source_path'] = self.name
-
- if entry.tag == 'Path':
- entry.set('type', 'file')
- try:
- if type(self.template) == unicode:
- entry.text = self.template
- else:
- if entry.get('encoding') == 'base64':
- # take care of case where file needs base64 encoding
- entry.text = b64encode(self.template)
- else:
- entry.text = unicode(str(self.template), self.encoding)
- except:
- (a, b, c) = sys.exc_info()
- msg = traceback.format_exception(a, b, c, limit=2)[-1][:-1]
- logger.error(msg)
- logger.error("TCheetah template error for %s" % self.searchlist['path'])
- del a, b, c
- raise Bcfg2.Server.Plugin.PluginExecutionError
-
-
-class TCheetah(Bcfg2.Server.Plugin.GroupSpool):
- """The TCheetah generator implements a templating mechanism for configuration files."""
- name = 'TCheetah'
- __author__ = 'bcfg-dev@mcs.anl.gov'
- filename_pattern = 'template'
- es_child_cls = TemplateFile
- deprecated = True
diff --git a/src/lib/Bcfg2/Server/Plugins/TGenshi.py b/src/lib/Bcfg2/Server/Plugins/TGenshi.py
deleted file mode 100644
index 809587d91..000000000
--- a/src/lib/Bcfg2/Server/Plugins/TGenshi.py
+++ /dev/null
@@ -1,139 +0,0 @@
-"""This module implements a templating generator based on Genshi."""
-
-import logging
-import sys
-import Bcfg2.Server.Plugin
-
-from Bcfg2.Compat import unicode, b64encode
-
-logger = logging.getLogger('Bcfg2.Plugins.TGenshi')
-
-# try to import genshi stuff
-try:
- import genshi.core
- import genshi.input
- from genshi.template import TemplateLoader, \
- TextTemplate, MarkupTemplate, TemplateError
-except ImportError:
- logger.error("TGenshi: Failed to import Genshi. Is it installed?")
- raise
-try:
- from genshi.template import NewTextTemplate
- have_ntt = True
-except:
- have_ntt = False
-
-def removecomment(stream):
- """A genshi filter that removes comments from the stream."""
- for kind, data, pos in stream:
- if kind is genshi.core.COMMENT:
- continue
- yield kind, data, pos
-
-
-class TemplateFile(object):
- """Template file creates Genshi template structures for the loaded file."""
-
- def __init__(self, name, specific, encoding):
- self.name = name
- self.specific = specific
- self.encoding = encoding
- if self.specific.all:
- matchname = self.name
- elif self.specific.group:
- matchname = self.name[:self.name.find('.G')]
- else:
- matchname = self.name[:self.name.find('.H')]
- if matchname.endswith('.txt'):
- self.template_cls = TextTemplate
- elif matchname.endswith('.newtxt'):
- if not have_ntt:
- logger.error("Genshi NewTextTemplates not supported by this version of Genshi")
- else:
- self.template_cls = NewTextTemplate
- else:
- self.template_cls = MarkupTemplate
- self.HandleEvent = self.handle_event
-
- def handle_event(self, event=None):
- """Handle all fs events for this template."""
- if event and event.code2str() == 'deleted':
- return
- try:
- loader = TemplateLoader()
- try:
- self.template = loader.load(self.name, cls=self.template_cls,
- encoding=self.encoding)
- except LookupError:
- lerror = sys.exc_info()[1]
- logger.error('Genshi lookup error: %s' % lerror)
- except TemplateError:
- terror = sys.exc_info()[1]
- logger.error('Genshi template error: %s' % terror)
- except genshi.input.ParseError:
- perror = sys.exc_info()[1]
- logger.error('Genshi parse error: %s' % perror)
-
- def bind_entry(self, entry, metadata):
- """Build literal file information."""
- fname = entry.get('realname', entry.get('name'))
- if entry.tag == 'Path':
- entry.set('type', 'file')
- try:
- stream = self.template.generate( \
- name=fname, metadata=metadata,
- path=self.name).filter(removecomment)
- if have_ntt:
- ttypes = [TextTemplate, NewTextTemplate]
- else:
- ttypes = [TextTemplate]
- if True in [isinstance(self.template, t) for t in ttypes]:
- try:
- textdata = stream.render('text', strip_whitespace=False)
- except TypeError:
- textdata = stream.render('text')
- if type(textdata) == unicode:
- entry.text = textdata
- else:
- if entry.get('encoding') == 'base64':
- # take care of case where file needs base64 encoding
- entry.text = b64encode(textdata)
- else:
- entry.text = unicode(textdata, self.encoding)
- else:
- try:
- xmldata = stream.render('xml', strip_whitespace=False)
- except TypeError:
- xmldata = stream.render('xml')
- if type(xmldata) == unicode:
- entry.text = xmldata
- else:
- entry.text = unicode(xmldata, self.encoding)
- if entry.text == '':
- entry.set('empty', 'true')
- except TemplateError:
- err = sys.exc_info()[1]
- logger.exception('Genshi template error')
- raise Bcfg2.Server.Plugin.PluginExecutionError('Genshi template error: %s' % err)
- except AttributeError:
- err = sys.exc_info()[1]
- logger.exception('Genshi template loading error')
- raise Bcfg2.Server.Plugin.PluginExecutionError('Genshi template loading error: %s' % err)
-
-
-class TemplateEntrySet(Bcfg2.Server.Plugin.EntrySet):
- basename_is_regex = True
-
-
-class TGenshi(Bcfg2.Server.Plugin.GroupSpool):
- """
- The TGenshi generator implements a templating
- mechanism for configuration files.
-
- """
- name = 'TGenshi'
- __author__ = 'jeff@ocjtech.us'
- filename_pattern = 'template\.(txt|newtxt|xml)'
- es_cls = TemplateEntrySet
- es_child_cls = TemplateFile
- deprecated = True
diff --git a/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py b/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py
index 9c8314f50..e3f8ed749 100644
--- a/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py
+++ b/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py
@@ -15,9 +15,8 @@ MODULE_RE = re.compile(r'(?P<filename>(?P<module>[^\/]+)\.py)$')
class HelperModule(object):
""" Representation of a TemplateHelper module """
- def __init__(self, name, fam=None):
+ def __init__(self, name):
self.name = name
- self.fam = fam
self._module_name = MODULE_RE.search(self.name).group('module')
self._attrs = []
@@ -75,7 +74,7 @@ class TemplateHelper(Bcfg2.Server.Plugin.Plugin,
def __init__(self, core, datastore):
Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
Bcfg2.Server.Plugin.Connector.__init__(self)
- Bcfg2.Server.Plugin.DirectoryBacked.__init__(self, self.data, core.fam)
+ Bcfg2.Server.Plugin.DirectoryBacked.__init__(self, self.data)
def get_additional_data(self, _):
return dict([(h._module_name, h) # pylint: disable=W0212
diff --git a/src/lib/Bcfg2/Server/Plugins/Trigger.py b/src/lib/Bcfg2/Server/Plugins/Trigger.py
index f7c82fdb3..878bf9cea 100644
--- a/src/lib/Bcfg2/Server/Plugins/Trigger.py
+++ b/src/lib/Bcfg2/Server/Plugins/Trigger.py
@@ -25,8 +25,7 @@ class Trigger(Bcfg2.Server.Plugin.Plugin,
def __init__(self, core, datastore):
Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
Bcfg2.Server.Plugin.ClientRunHooks.__init__(self)
- Bcfg2.Server.Plugin.DirectoryBacked.__init__(self, self.data,
- self.core.fam)
+ Bcfg2.Server.Plugin.DirectoryBacked.__init__(self, self.data)
def async_run(self, args):
""" Run the trigger script asynchronously in a forked process
diff --git a/src/lib/Bcfg2/Server/Plugins/__init__.py b/src/lib/Bcfg2/Server/Plugins/__init__.py
index b33eeba28..1f85702f0 100644
--- a/src/lib/Bcfg2/Server/Plugins/__init__.py
+++ b/src/lib/Bcfg2/Server/Plugins/__init__.py
@@ -1,32 +1 @@
-"""Imports for Bcfg2.Server.Plugins."""
-
-__all__ = [
- 'Account',
- 'Base',
- 'Bundler',
- 'Bzr',
- 'Cfg',
- 'Cvs',
- 'Darcs',
- 'Decisions',
- 'Fossil',
- 'Git',
- 'GroupPatterns',
- 'Hg',
- 'Hostbase',
- 'Metadata',
- 'NagiosGen',
- 'Ohai',
- 'Packages',
- 'Properties',
- 'Probes',
- 'Pkgmgr',
- 'Rules',
- 'SSHbase',
- 'Snapshots',
- 'Statistics',
- 'Svn',
- 'TCheetah',
- 'Trigger',
- 'TGenshi',
- ]
+""" Bcfg2 Plugins """