From 34b24211eb8baddec7daf6fa7ecb151fd9aa82e3 Mon Sep 17 00:00:00 2001 From: Narayan Desai Date: Mon, 9 Jun 2008 15:56:41 +0000 Subject: Change to typed plugin system git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@4680 ce84e21b-d406-0410-9b95-82705330c041 --- src/lib/Server/Core.py | 47 ++++++++++----- src/lib/Server/Plugin.py | 39 ++++++++----- src/lib/Server/Plugins/Account.py | 2 +- src/lib/Server/Plugins/Base.py | 3 +- src/lib/Server/Plugins/Bundler.py | 3 +- src/lib/Server/Plugins/Hostbase.py | 4 +- src/lib/Server/Plugins/Metadata.py | 3 +- src/lib/Server/Plugins/SGenshi.py | 2 +- src/lib/Server/Plugins/SSHbase.py | 2 +- src/lib/Server/Plugins/Vhost.py | 116 ------------------------------------- 10 files changed, 67 insertions(+), 154 deletions(-) delete mode 100644 src/lib/Server/Plugins/Vhost.py (limited to 'src/lib') diff --git a/src/lib/Server/Core.py b/src/lib/Server/Core.py index 6a6264e9a..a5a484de9 100644 --- a/src/lib/Server/Core.py +++ b/src/lib/Server/Core.py @@ -233,28 +233,43 @@ class Core(object): except ImportError, e: logger.error("Failed to load plugin %s: %s" % (plugin, e)) continue - struct = getattr(mod, plugin) + plug = getattr(mod, plugin) + if plug.experimental: + logger.info("Loading experimental plugin %s" % (plugin)) + logger.info("NOTE: Interface subject to change") try: - self.plugins[plugin] = struct(self, self.datastore) + self.plugins[plugin] = plug(self, self.datastore) except PluginInitError: logger.error("Failed to instantiate plugin %s" % (plugin)) except: logger.error("Unexpected instantiation failure for plugin %s" % (plugin), exc_info=1) - if 'Metadata' in self.plugins: - self.metadata = self.plugins['Metadata'] - else: - raise CoreInitError, "No Metadata plugin loaded" - for plugin in structures: - if self.plugins.has_key(plugin): - self.structures.append(self.plugins[plugin]) - else: - logger.error("Plugin %s not loaded. Not enabled as a Structure" % (plugin)) - for plugin in generators: - if self.plugins.has_key(plugin): - self.generators.append(self.plugins[plugin]) - else: - logger.error("Plugin %s not loaded. Not enabled as a Generator" % (plugin)) + plugins = self.plugins.values() + while True: + plugin = plugins.pop() + if isinstance(plugin, Bcfg2.Server.Plugin.MetadataPlugin): + self.metadata = plugin + break + if not plugins: + raise CoreInitError, "No Metadata plugin loaded" + for plug_names, plug_tname, plug_type, collection in \ + [(structures, 'structure', Bcfg2.Server.Plugin.StructurePlugin, + self.structures), + (generators, 'generator', Bcfg2.Server.Plugin.GeneratorPlugin, + self.generators)]: + for plugin in plug_names: + print plugin, self.plugins.keys(), plugin in self.plugins + raw_input() + if plugin in self.plugins: + if not isinstance(self.plugins[plugin], plug_type): + logger.error("Plugin %s is not a %s plugin; unloading" \ + % (plugin, plug_tname)) + del self.plugins[plugin] + else: + collection.append(self.plugins[plugin]) + else: + logger.error("Plugin %s not loaded. Not enabled as a %s" \ + % (plugin, plug_tname)) def GetStructures(self, metadata): '''Get all structures for client specified by metadata''' diff --git a/src/lib/Server/Plugin.py b/src/lib/Server/Plugin.py index 8c81e5839..6b308d1f7 100644 --- a/src/lib/Server/Plugin.py +++ b/src/lib/Server/Plugin.py @@ -39,6 +39,7 @@ class Plugin(object): __version__ = '$Id$' __author__ = 'bcfg-dev@mcs.anl.gov' __rmi__ = [] + experimental = False def __init__(self, core, datastore): object.__init__(self) @@ -47,18 +48,8 @@ class Plugin(object): self.data = "%s/%s" % (datastore, self.__name__) self.logger = logging.getLogger('Bcfg2.Plugins.%s' % (self.__name__)) - def BuildStructures(self, _): - '''Build a set of structures tailored to the client metadata''' - return [] - - def GetProbes(self, _): - '''Return a set of probes for execution on client''' - return [] - - def ReceiveData(self, _, dummy): - '''Receive probe results pertaining to client''' - pass - +class GeneratorPlugin(Plugin): + '''Generator plugins contribute to literal client configurations''' def HandlesEntry(self, entry): '''This is the slow path method for routing configuration binding requests''' return False @@ -80,6 +71,26 @@ class Plugin(object): # not implemented yet pass +class StructurePlugin(Plugin): + '''Structure Plugins contribute to abstract client configurations''' + def BuildStructures(self, metadata): + '''return a list of abstract goal structures for client''' + raise PluginExecutionError + +class MetadataPlugin(Plugin): + '''Signal metadata capabilities for this plugin''' + pass + +class ProbingPlugin(Plugin): + '''Signal probe capability for this plugin''' + def GetProbes(self, _): + '''Return a set of probes for execution on client''' + return [] + + def ReceiveData(self, _, dummy): + '''Receive probe results pertaining to client''' + pass + # the rest of the file contains classes for coherent file caching class FileBacked(object): @@ -331,7 +342,7 @@ class XMLDirectoryBacked(DirectoryBacked): '''Directorybacked for *.xml''' patterns = re.compile('.*\.xml') -class PrioDir(Plugin, XMLDirectoryBacked): +class PrioDir(GeneratorPlugin, XMLDirectoryBacked): '''This is a generator that handles package assignments''' __name__ = 'PrioDir' __child__ = XMLSrc @@ -602,7 +613,7 @@ class FakeProperties: def __init__(self): self.properties = lxml.etree.Element("Properties") -class GroupSpool(Plugin): +class GroupSpool(GeneratorPlugin): '''The TGenshi generator implements a templating mechanism for configuration files''' __name__ = 'GroupSpool' __version__ = '$Id$' diff --git a/src/lib/Server/Plugins/Account.py b/src/lib/Server/Plugins/Account.py index 8599c028a..8cab47b01 100644 --- a/src/lib/Server/Plugins/Account.py +++ b/src/lib/Server/Plugins/Account.py @@ -3,7 +3,7 @@ __revision__ = '$Revision$' import Bcfg2.Server.Plugin -class Account(Bcfg2.Server.Plugin.Plugin): +class Account(Bcfg2.Server.Plugin.GeneratorPlugin): '''This module generates account config files, based on an internal data repo: static.(passwd|group|limits.conf) -> static entries diff --git a/src/lib/Server/Plugins/Base.py b/src/lib/Server/Plugins/Base.py index 2a849236f..3a06ba641 100644 --- a/src/lib/Server/Plugins/Base.py +++ b/src/lib/Server/Plugins/Base.py @@ -5,7 +5,8 @@ import Bcfg2.Server.Plugin import copy import lxml.etree -class Base(Bcfg2.Server.Plugin.Plugin, Bcfg2.Server.Plugin.XMLDirectoryBacked): +class Base(Bcfg2.Server.Plugin.StructurePlugin, + Bcfg2.Server.Plugin.XMLDirectoryBacked): '''This Structure is good for the pile of independent configs needed for most actual systems''' __name__ = 'Base' __version__ = '$Id$' diff --git a/src/lib/Server/Plugins/Bundler.py b/src/lib/Server/Plugins/Bundler.py index 597421699..f771d4016 100644 --- a/src/lib/Server/Plugins/Bundler.py +++ b/src/lib/Server/Plugins/Bundler.py @@ -3,7 +3,8 @@ __revision__ = '$Revision$' import copy, lxml.etree, Bcfg2.Server.Plugin -class Bundler(Bcfg2.Server.Plugin.Plugin, Bcfg2.Server.Plugin.XMLDirectoryBacked): +class Bundler(Bcfg2.Server.Plugin.StructurePlugin, + Bcfg2.Server.Plugin.XMLDirectoryBacked): '''The bundler creates dependent clauses based on the bundle/translation scheme from bcfg1''' __name__ = 'Bundler' __version__ = '$Id$' diff --git a/src/lib/Server/Plugins/Hostbase.py b/src/lib/Server/Plugins/Hostbase.py index dcd77f16a..05840f218 100644 --- a/src/lib/Server/Plugins/Hostbase.py +++ b/src/lib/Server/Plugins/Hostbase.py @@ -5,7 +5,7 @@ import sys, os os.environ['DJANGO_SETTINGS_MODULE'] = 'Bcfg2.Server.Hostbase.settings' from lxml.etree import Element, SubElement from syslog import syslog, LOG_INFO -from Bcfg2.Server.Plugin import Plugin, PluginExecutionError, PluginInitError, DirectoryBacked +from Bcfg2.Server.Plugin import StructurePlugin, PluginExecutionError, PluginInitError, DirectoryBacked from time import strftime from sets import Set from django.template import Context, loader @@ -37,7 +37,7 @@ import cStringIO ## '''This function is called when underlying data has changed''' ## pass -class Hostbase(Plugin): +class Hostbase(StructurePlugin): '''The Hostbase plugin handles host/network info''' __name__ = 'Hostbase' __version__ = '$Id$' diff --git a/src/lib/Server/Plugins/Metadata.py b/src/lib/Server/Plugins/Metadata.py index b24dd0c66..f79aa4d03 100644 --- a/src/lib/Server/Plugins/Metadata.py +++ b/src/lib/Server/Plugins/Metadata.py @@ -74,7 +74,8 @@ class ProbeSet(Bcfg2.Server.Plugin.EntrySet): return ret -class Metadata(Bcfg2.Server.Plugin.Plugin): +class Metadata(Bcfg2.Server.Plugin.MetadataPlugin, + Bcfg2.Server.Plugin.ProbingPlugin): '''This class contains data for bcfg2 server metadata''' __version__ = '$Id$' __author__ = 'bcfg-dev@mcs.anl.gov' diff --git a/src/lib/Server/Plugins/SGenshi.py b/src/lib/Server/Plugins/SGenshi.py index 10559733c..bf063b884 100644 --- a/src/lib/Server/Plugins/SGenshi.py +++ b/src/lib/Server/Plugins/SGenshi.py @@ -44,7 +44,7 @@ class SGenshiEntrySet(Bcfg2.Server.Plugin.EntrySet): logger.error("SGenshi: Failed to template file %s" % entry.name) return ret -class SGenshi(SGenshiEntrySet, Bcfg2.Server.Plugin.Plugin): +class SGenshi(SGenshiEntrySet, Bcfg2.Server.Plugin.StructurePlugin): '''The SGenshi plugin provides templated structures''' __name__ = 'SGenshi' __version__ = '$Id$' diff --git a/src/lib/Server/Plugins/SSHbase.py b/src/lib/Server/Plugins/SSHbase.py index 005b52988..cdd95181b 100644 --- a/src/lib/Server/Plugins/SSHbase.py +++ b/src/lib/Server/Plugins/SSHbase.py @@ -4,7 +4,7 @@ __revision__ = '$Revision$' import binascii, os, socket import Bcfg2.Server.Plugin -class SSHbase(Bcfg2.Server.Plugin.Plugin, Bcfg2.Server.Plugin.DirectoryBacked): +class SSHbase(Bcfg2.Server.Plugin.GeneratorPlugin, Bcfg2.Server.Plugin.DirectoryBacked): '''The sshbase generator manages ssh host keys (both v1 and v2) for hosts. It also manages the ssh_known_hosts file. It can integrate host keys from other management domains and similarly diff --git a/src/lib/Server/Plugins/Vhost.py b/src/lib/Server/Plugins/Vhost.py deleted file mode 100644 index 5c38cd19e..000000000 --- a/src/lib/Server/Plugins/Vhost.py +++ /dev/null @@ -1,116 +0,0 @@ -''' -#------------------------------------------- -# Script Name: vhost.py -# Script Version: 1.0 -# Date: 20 July 2005 -# Author: Scott R Behrens -# Description: opens a request file, genereates a vhost httpd.conf file, and establishes symlinks -# Revision History: -# 1.0/<20-7-2005>: orignal version -# 1.1/<20-7-2005>: now genreates multiple files based on XML document -# 1.2/<20-8-2005>: generates one file encoded in base64 -# 1.3/<06-9-2005>: cleanup some pylint and style problems -#------------------------------------------- -''' -__revision__ = '$Revision$' - -import base64 -from copy import deepcopy -from lxml.etree import XML, Element, SubElement -from socket import gethostbyname -from Bcfg2.Server.Plugin import Plugin, PluginExecutionError, SingleXMLFileBacked - -class VhostFile(SingleXMLFileBacked): - '''The Vhost file contains webserver vhost configuration elements''' - sitesen = "/etc/apache2/sites-enabled/" - sitesav = "/etc/apache2/sites-available/" - - def __init__(self, name, fam): - self.meta = Element('dummy') - self.dispatch = {'ConfigFile':{'/etc/default/apache2':self.generateApacheDefault}, - 'Service':{'apache2':self.generateApacheSvc}} - SingleXMLFileBacked.__init__(self, name, fam) - self.http = open('/disks/bcfg2/Vhost/default.httpd', 'r').readlines() - self.servers = [] - self.vhosts = {} - - - def Index(self): - '''Build vhost data structures''' - self.meta = XML(self.data) - self.servers = [serv.get('name') for serv in self.meta.findall('server')] - self.vhosts = {} - for server in self.meta.findall("server"): - for vhost in server.findall("vhost"): - name = vhost.get('name') - self.dispatch[self.sitesav + name] = self.generateSiteFile - self.vhosts[name] = vhost - - def BuildStructures(self, metadata): - '''Build apache+vhost bundle''' - if metadata.hostname not in self.servers: - return [] - output = Element("Bundle", name='apache-vhost', version='2.0') - for server in self.meta.findall("server"): - if server.attrib['name'] in metadata.hostname: - for vhost in server.findall("vhost"): - name = vhost.get('name') - SubElement(output, "SymLink", name=self.sitesen+name, to=self.sitesav+name) - SubElement(output, "ConfigFile", name="/etc/apache2/sites-available/" + name) - SubElement(output, "ConfigFile", name='/etc/default/apache2') - for software in self.meta.findall("Software"): - for child in software.getchildren(): - output.append(deepcopy(child)) - return [output] - - def generateApacheDefault(self, entry, metadata): - '''Build /etc/default/apache2''' - if metadata.hostname in self.servers: - entry.text = 'NO_START=0\n' - else: - entry.text = 'NO_START=1\n' - perms = {'owner':'root', 'group':'root', 'perms':'0644'} - [entry.attrib.__setitem__(key, value) for (key, value) in perms.iteritems()] - - def generateApacheSvc(self, entry, metadata): - '''Enable apache service on webservices, disable on others''' - if metadata.hostname in self.servers: - entry.set('status', 'on') - else: - entry.set('status', 'off') - - def generateSiteFile(self, entry, metadata): - '''Build site-specific config file for vhost''' - if metadata.hostname not in self.servers: - raise PluginExecutionError - vhostname = entry.get('name')[len(self.sitesav):] - if not self.vhosts.has_key(vhostname): - raise PluginExecutionError - - if self.vhosts[vhostname].get('root') == "Hostname": - choice = vhostname - else: - choice = gethostbyname(vhostname) - - config = "" - for line in self.http: - line = line.replace("XXemailXX", self.vhosts[vhostname].get('email')) - line = line.replace("XXdomainXX", vhostname) - line = line.replace("XXchoiceXX", choice) - config += line - entry.text = base64.encodestring(config) - perms = {'owner':'root', 'group':'root', 'perms':'0644', 'encoding':'base64'} - [entry.attrib.__setitem__(key, value) for (key, value) in perms.iteritems()] - -class Vhost(Plugin): - '''This Structure is good for the pile of independent configs needed for most actual systems''' - __name__ = 'Vhost' - __version__ = '$Id$' - __author__ = 'behrens@mcs.anl.gov' - - '''Vhost creates independent clauses based on client metadata''' - def __init__(self, core, datastore): - Plugin.__init__(self, core, datastore) - self.Vhost = VhostFile("%s/Vhost/Vhost.xml"%(datastore), self.core.fam) - self.BuildStructures = self.Vhost.BuildStructures - self.Entries = self.Vhost.dispatch -- cgit v1.2.3-1-g7c22