summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNarayan Desai <desai@mcs.anl.gov>2008-06-09 15:56:41 +0000
committerNarayan Desai <desai@mcs.anl.gov>2008-06-09 15:56:41 +0000
commit34b24211eb8baddec7daf6fa7ecb151fd9aa82e3 (patch)
tree7935aa537394f32383e026d2e0dead3cad13a30a
parentdc0f82b0b3bce69f9a146126aabf0b2063e64a47 (diff)
downloadbcfg2-34b24211eb8baddec7daf6fa7ecb151fd9aa82e3.tar.gz
bcfg2-34b24211eb8baddec7daf6fa7ecb151fd9aa82e3.tar.bz2
bcfg2-34b24211eb8baddec7daf6fa7ecb151fd9aa82e3.zip
Change to typed plugin system
git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@4680 ce84e21b-d406-0410-9b95-82705330c041
-rw-r--r--src/lib/Server/Core.py47
-rw-r--r--src/lib/Server/Plugin.py39
-rw-r--r--src/lib/Server/Plugins/Account.py2
-rw-r--r--src/lib/Server/Plugins/Base.py3
-rw-r--r--src/lib/Server/Plugins/Bundler.py3
-rw-r--r--src/lib/Server/Plugins/Hostbase.py4
-rw-r--r--src/lib/Server/Plugins/Metadata.py3
-rw-r--r--src/lib/Server/Plugins/SGenshi.py2
-rw-r--r--src/lib/Server/Plugins/SSHbase.py2
-rw-r--r--src/lib/Server/Plugins/Vhost.py116
-rwxr-xr-xsrc/sbin/bcfg2-server3
11 files changed, 69 insertions, 155 deletions
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
diff --git a/src/sbin/bcfg2-server b/src/sbin/bcfg2-server
index 09d2ce619..6cffd2253 100755
--- a/src/sbin/bcfg2-server
+++ b/src/sbin/bcfg2-server
@@ -100,7 +100,8 @@ class Bcfg2Serv(Bcfg2.Component.Component):
name = self.Core.metadata.resolve_client(address)
meta = self.Core.metadata.get_metadata(name)
- for plugin in self.Core.plugins.values():
+ for plugin in [p for p in self.Core.plugins.values() \
+ if isinstance(p, Bcfg2.Server.Plugin.ProbingPlugin)]:
for probe in plugin.GetProbes(meta):
resp.append(probe)
return tostring(resp)