summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNarayan Desai <desai@mcs.anl.gov>2008-03-21 15:54:04 +0000
committerNarayan Desai <desai@mcs.anl.gov>2008-03-21 15:54:04 +0000
commitcc7f6afe536fd425dd1fbcad49565453624506d4 (patch)
treeb1b651ad15e8698088242c0dbb07654946820583
parentd1040d8565d4cdea17663c797ed14d095e9cac9d (diff)
downloadbcfg2-cc7f6afe536fd425dd1fbcad49565453624506d4.tar.gz
bcfg2-cc7f6afe536fd425dd1fbcad49565453624506d4.tar.bz2
bcfg2-cc7f6afe536fd425dd1fbcad49565453624506d4.zip
Merge in GroupSpool plugin as common code and switch TGenshi to use it
git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@4430 ce84e21b-d406-0410-9b95-82705330c041
-rw-r--r--src/lib/Server/Plugin.py91
-rw-r--r--src/lib/Server/Plugins/TGenshi.py153
2 files changed, 116 insertions, 128 deletions
diff --git a/src/lib/Server/Plugin.py b/src/lib/Server/Plugin.py
index ba63995f8..73f8a6988 100644
--- a/src/lib/Server/Plugin.py
+++ b/src/lib/Server/Plugin.py
@@ -1,7 +1,7 @@
'''This module provides the baseclass for Bcfg2 Server Plugins'''
__revision__ = '$Revision$'
-import logging, lxml.etree, re, copy
+import logging, lxml.etree, re, copy, posixpath
from lxml.etree import XML, XMLSyntaxError
@@ -522,3 +522,92 @@ class EntrySet:
raise PluginExecutionError
+# GroupSpool plugin common code (for TGenshi, TCheetah, and Cfg)
+
+class TemplateProperties(SingleXMLFileBacked):
+ '''Class for Genshi properties'''
+ def Index(self):
+ '''Build data into an elementtree object for templating usage'''
+ try:
+ self.properties = lxml.etree.XML(self.data)
+ del self.data
+ except lxml.etree.XMLSyntaxError:
+ logger.error("Failed to parse properties.xml; disabling")
+
+class FakeProperties:
+ '''Dummy class used when properties dont exist'''
+ def __init__(self):
+ self.properties = lxml.etree.Element("Properties")
+
+class GroupSpool(Plugin):
+ '''The TGenshi generator implements a templating mechanism for configuration files'''
+ __name__ = 'GroupSpool'
+ __version__ = '$Id$'
+ __author__ = 'bcfg-dev@mcs.anl.gov'
+ use_props = False
+ filename_pattern = ""
+ es_child_cls = object
+
+ def __init__(self, core, datastore):
+ Plugin.__init__(self, core, datastore)
+ if self.data[-1] == '/':
+ self.data = self.data[:-1]
+ self.Entries['ConfigFile'] = {}
+ self.entries = {}
+ self.handles = {}
+ self.AddDirectoryMonitor('')
+ if self.use_props:
+ try:
+ self.properties = TemplateProperties( \
+ '%s/../etc/properties.xml' % (self.data), self.core.fam)
+ except:
+ self.properties = FakeProperties()
+ self.logger.info("%s properties disabled" % self.__name__)
+ else:
+ self.properties = FakeProperties()
+
+ def HandleEvent(self, event):
+ '''Unified FAM event handler for DirShadow'''
+ action = event.code2str()
+ if event.filename[0] == '/':
+ return
+ epath = "".join([self.data, self.handles[event.requestID],
+ event.filename])
+ if posixpath.isdir(epath):
+ ident = self.handles[event.requestID] + event.filename
+ else:
+ ident = self.handles[event.requestID][:-1]
+
+ if action in ['exists', 'created']:
+ if posixpath.isdir(epath):
+ self.AddDirectoryMonitor(epath[len(self.data):])
+ if ident not in self.entries:
+ self.entries[ident] = EntrySet(self.filename_pattern,
+ epath,
+ self.properties,
+ self.es_child_cls)
+ self.Entries['ConfigFile'][ident] = self.entries[ident].bind_entry
+ if not posixpath.isdir(epath):
+ # do not pass through directory events
+ self.entries[ident].handle_event(event)
+ if action == 'changed':
+ self.entries[ident].handle_event(event)
+ elif action == 'deleted' and ident in self.entries:
+ self.entries[ident].handle_event(event)
+ if not len(self.entries[ident].entries):
+ del self.entries[ident]
+ del self.Entries['ConfigFile'][ident]
+
+ def AddDirectoryMonitor(self, relative):
+ '''Add new directory to FAM structures'''
+ if not relative:
+ relative = '/'
+ if relative[-1] != '/':
+ relative += '/'
+ name = self.data + relative
+ if relative not in self.handles.values():
+ if not posixpath.isdir(name):
+ print "Genshi: Failed to open directory %s" % (name)
+ return
+ reqid = self.core.fam.AddMonitor(name, self)
+ self.handles[reqid] = relative
diff --git a/src/lib/Server/Plugins/TGenshi.py b/src/lib/Server/Plugins/TGenshi.py
index 5867797e1..d7199d78c 100644
--- a/src/lib/Server/Plugins/TGenshi.py
+++ b/src/lib/Server/Plugins/TGenshi.py
@@ -2,57 +2,39 @@
__revision__ = '$Revision$'
from genshi.template import TemplateLoader, TextTemplate, MarkupTemplate, TemplateError
-import logging, lxml.etree, posixpath, re, os
+import logging
import Bcfg2.Server.Plugin
logger = logging.getLogger('Bcfg2.Plugins.TGenshi')
-info = re.compile('^owner:(\s)*(?P<owner>\w+)$|group:(\s)*(?P<group>\w+)$|' +
- 'perms:(\s)*(?P<perms>\w+)$')
class TemplateFile:
'''Template file creates Genshi template structures for the loaded file'''
- def __init__(self, name, loader, properties):
+ def __init__(self, name, properties, specific):
self.name = name
- self.states = {'template': False, 'info': False}
- self.metadata = {'owner': 'root', 'group': 'root', 'perms': '0644'}
self.properties = properties
- self.loader = loader
+ self.specific = specific
+ 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
+ else:
+ self.template_cls = MarkupTemplate
- def HandleEvent(self, event):
+ def handle_event(self, event):
'''Handle all fs events for this template'''
- if event.filename in ['template.xml', 'template.txt']:
- try:
- if event.filename.endswith('.txt'):
- self.template = self.loader.load(os.path.join(self.name[1:], event.filename), cls=TextTemplate)
- else:
- self.template = self.loader.load(os.path.join(self.name[1:], event.filename), cls=MarkupTemplate)
- except TemplateError, terror:
- logger.error('Genshi template error: %s' % terror)
- elif event.filename == 'info.xml':
- if not hasattr(self, 'infoxml'):
- fpath = self.name + '/info.xml'
- self.infoxml = Bcfg2.Server.Plugin.XMLSrc(fpath, True)
- self.infoxml.HandleEvent(event)
- elif event.filename == 'info':
- for line in open(self.name + '/info').readlines():
- match = info.match(line)
- if not match:
- logger.warning("Failed to match line: %s"%line)
- continue
- else:
- mgd = match.groupdict()
- if mgd['owner']:
- self.metadata['owner'] = mgd['owner']
- elif mgd['group']:
- self.metadata['group'] = mgd['group']
- elif mgd['perms']:
- self.metadata['perms'] = mgd['perms']
- if len(self.metadata['perms']) == 3:
- self.metadata['perms'] = "0%s" % (self.metadata['perms'])
- else:
- logger.info('Ignoring event for %s' % event.filename)
+ if event.code2str() == 'deleted':
+ return
+ try:
+ loader = TemplateLoader()
+ self.template = loader.load(self.name, cls=self.template_cls)
+ except TemplateError, terror:
+ logger.error('Genshi template error: %s' % terror)
- def BuildFile(self, entry, metadata):
+ def bind_entry(self, entry, metadata):
'''Build literal file information'''
fname = entry.get('realname', entry.get('name'))
try:
@@ -66,95 +48,12 @@ class TemplateFile:
except TemplateError, terror:
logger.error('Genshi template error: %s' % terror)
raise Bcfg2.Server.Plugin.PluginExecutionError
- if hasattr(self, 'infoxml'):
- mdata = {}
- self.infoxml.pnode.Match(metadata, mdata)
- [entry.attrib.__setitem__(key, value) \
- for (key, value) in mdata['Info'][None].iteritems()]
- else:
- [entry.attrib.__setitem__(key, value) \
- for (key, value) in self.metadata.iteritems()]
-
-class GenshiProperties(Bcfg2.Server.Plugin.SingleXMLFileBacked):
- '''Class for Genshi properties'''
- def Index(self):
- '''Build data into an elementtree object for templating usage'''
- try:
- self.properties = lxml.etree.XML(self.data)
- del self.data
- except lxml.etree.XMLSyntaxError:
- logger.error("Failed to parse properties")
-
-class FakeProperties:
- '''Dummy class used when properties dont exist'''
- def __init__(self):
- self.properties = lxml.etree.Element("Properties")
-class TGenshi(Bcfg2.Server.Plugin.Plugin):
+class TGenshi(Bcfg2.Server.Plugin.GroupSpool):
'''The TGenshi generator implements a templating mechanism for configuration files'''
__name__ = 'TGenshi'
__version__ = '$Id$'
__author__ = 'jeff@ocjtech.us'
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- if self.data[-1] == '/':
- self.data = self.data[:-1]
- self.Entries['ConfigFile'] = {}
- self.entries = {}
- self.handles = {}
- self.loader = TemplateLoader(self.data, auto_reload=True)
- self.AddDirectoryMonitor('')
- try:
- self.properties = GenshiProperties('%s/../etc/properties.xml' \
- % (self.data), self.core.fam)
- except:
- self.properties = FakeProperties()
- self.logger.info("Failed to read properties file; TGenshi properties disabled")
-
- def BuildEntry(self, entry, metadata):
- '''Dispatch fetch calls to the correct object'''
- self.entries[entry.get('name')].BuildFile(entry, metadata)
-
- def HandleEvent(self, event):
- '''Unified FAM event handler for DirShadow'''
- action = event.code2str()
- if event.filename[0] == '/':
- return
- epath = "".join([self.data, self.handles[event.requestID], event.filename])
- if event.filename in ['info', 'info.xml', 'template.xml',
- 'template.txt']:
- identifier = self.handles[event.requestID][:-1]
- else:
- identifier = self.handles[event.requestID] + event.filename
- if action in ['exists', 'created']:
- if posixpath.isdir(epath):
- self.AddDirectoryMonitor(epath[len(self.data):])
- elif event.filename in ['info', 'template.xml', 'template.txt']:
- if not self.entries.has_key(identifier):
- self.entries[identifier] = TemplateFile(identifier, self.loader, self.properties)
- self.Entries['ConfigFile'][identifier] = self.BuildEntry
- self.entries[identifier].HandleEvent(event)
- else:
- logger.info('Not creating template for %s' % identifier)
- elif action == 'changed':
- if self.entries.has_key(identifier):
- self.entries[identifier].HandleEvent(event)
- elif action == 'deleted':
- if event.filename in ['template.xml', 'template.txt'] and self.entries.has_key(identifier):
- del self.entries[identifier]
- del self.Entries['ConfigFile'][identifier]
-
- def AddDirectoryMonitor(self, relative):
- '''Add new directory to FAM structures'''
- if not relative:
- relative = '/'
- if relative[-1] != '/':
- relative += '/'
- name = self.data + relative
- if relative not in self.handles.values():
- if not posixpath.isdir(name):
- print "Genshi: Failed to open directory %s" % (name)
- return
- reqid = self.core.fam.AddMonitor(name, self)
- self.handles[reqid] = relative
+ use_props = True
+ filename_pattern = 'template\.(txt|xml)'
+ es_child_cls = TemplateFile