summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/1.0-roadmap10
-rw-r--r--doc/plugin-roles34
-rw-r--r--src/lib/Server/Core.py52
3 files changed, 63 insertions, 33 deletions
diff --git a/doc/1.0-roadmap b/doc/1.0-roadmap
index 2d90d6f66..dc2236879 100644
--- a/doc/1.0-roadmap
+++ b/doc/1.0-roadmap
@@ -1,12 +1,12 @@
This document details the major work needed before Bcfg2 is ready for
-a 1.0 release.
+a 1.0 release. The high-level goal for 1.0 is to fix long-standing
+architecture warts and provide a reasonable internal API for the
+server.
* Goals for 1.0
** Fix the POSIX path problem
** Build a comprehensive server plugin architecture
-*** Metadata Connectors (done)
-*** Multi-stats
-*** Structure Verifier/Modifier
-*** Configuration Validator/Modifier
+*** see plugin-roles for details and implementation status
** Version Control Backend
** Clean up client/server statistics data format
+** Multithreaded server (sync from Cobalt)
diff --git a/doc/plugin-roles b/doc/plugin-roles
index d34a88c77..5d072dcbd 100644
--- a/doc/plugin-roles
+++ b/doc/plugin-roles
@@ -18,13 +18,27 @@ This documents available plugin roles.
| Syncing | Syncing | none |
|---------------+--------------------+---------------|
-
-2) Configuration of plugins
-
-3) Implementation Plan
-
-* Switch Plugin.__name__ => Plugin.name (Fix spurious pylint errors) [done]
-* Switch all plugins to new class hierarchy [done]
-* Fix Core to use memberships in new classes
-
-
+2) Interactions between plugins and the core
+* Metadata Construction
+** Get Base Metadata from (single) Metadata plugin instance
+** Get additional data from each Connector plugin instance
+** Merge in additional connector data into single ClientMetadata instance
+*
+
+3) Configuration of plugins
+
+Plugin configuration will be simplified substantially. Now, a single
+list of plugins (including plugins of all capabilities) is specified
+upon startup (either via bcfg2.conf or equivalent). This mechanism
+replaces the current split configuration mechanism where generators,
+structures, and other plugins are listed independently. Instead, all
+plugins included in the startup list will be initialized, and each
+will be enabled in all roles that it supports. This will remove a
+current source of confusion and potential configuration errors,
+wherein a plugin is enabled for an improper set of goals. (ie Cfg
+enabled as a structure, etc) This does remove the possibility of
+partially enabling a plugin for one of its roles without activating it
+across the board, but I think this is a corner case, which will be
+poorly supported by plugin implementers. If needed, this use case can
+be explicitly supported by the plugin author, through use of a config
+file directive.
diff --git a/src/lib/Server/Core.py b/src/lib/Server/Core.py
index 4e014809b..d2eaed5dd 100644
--- a/src/lib/Server/Core.py
+++ b/src/lib/Server/Core.py
@@ -126,10 +126,28 @@ class Core(object):
logger.error("Unexpected instantiation failure for plugin %s" %
(plugin), exc_info=1)
+
+ def validate_data(self, metadata, data, base_cls):
+ for plugin in self.plugins.values():
+ if isinstance(plugin, base_cls):
+ try:
+ if base_cls == Bcfg2.Server.Plugin.StructureValidator:
+ plugin.validate_structures(metadata, data)
+ elif base_cls == Bcfg2.Server.Plugin.GoalValidator:
+ plugin.validate_goals(metadata, data)
+ except Bcfg2.Server.Plugin.ValidationError, err:
+ logger.error("Plugin %s structure validation failed: %s" \
+ % (plugin.name, err.message))
+ raise
+ except:
+ logger.error("Plugin %s: unexpected structure val failure" \
+ % (plugin.name), exc_info=1)
+
def GetStructures(self, metadata):
'''Get all structures for client specified by metadata'''
return reduce(lambda x, y:x+y,
- [struct.BuildStructures(metadata) for struct in self.structures], [])
+ [struct.BuildStructures(metadata) for struct \
+ in self.structures], [])
def BindStructure(self, structure, metadata):
'''Bind a complete structure'''
@@ -140,10 +158,11 @@ class Core(object):
try:
self.Bind(entry, metadata)
except PluginExecutionError:
- logger.error("Failed to bind entry: %s %s" % (entry.tag, entry.get('name')))
+ logger.error("Failed to bind entry: %s %s" % \
+ (entry.tag, entry.get('name')))
except:
- logger.error("Unexpected failure in BindStructure: %s %s" % (entry.tag, entry.get('name')),
- exc_info=1)
+ logger.error("Unexpected failure in BindStructure: %s %s" \
+ % (entry.tag, entry.get('name')), exc_info=1)
def Bind(self, entry, metadata):
'''Bind an entry using the appropriate generator'''
@@ -194,16 +213,8 @@ class Core(object):
logger.error("error in GetStructures", exc_info=1)
return lxml.etree.Element("error", type='structure error')
- for plugin in self.plugins.values():
- if isinstance(plugin, Bcfg2.Server.Plugin.StructureValidator):
- try:
- plugin.validate_structures(meta, structures)
- except Bcfg2.Server.Plugin.ValidationError, err:
- logger.error("Plugin %s structure validation failed: %s" \
- % (plugin.name, err.message))
- except:
- logger.error("Plugin %s: unexpected structure val failure" \
- % (plugin.name), exc_info=1)
+ self.validate_data(meta, structures,
+ Bcfg2.Server.Plugin.StructureValidator)
# Perform altsrc consistency checking
esrcs = {}
@@ -223,7 +234,9 @@ class Core(object):
config.append(astruct)
except:
logger.error("error in BindStructure", exc_info=1)
- logger.info("Generated config for %s in %s seconds"%(client, time() - start))
+ self.validate_data(meta, config, Bcfg2.Server.Plugin.GoalValidator)
+ logger.info("Generated config for %s in %s seconds" % \
+ (client, time() - start))
return config
def Service(self):
@@ -239,8 +252,10 @@ class Core(object):
def read_svn_revision(self):
'''Read svn revision information for the bcfg2 repository'''
try:
- data = os.popen("env LC_ALL=C svn info %s" % (self.datastore)).readlines()
- revline = [line.split(': ')[1].strip() for line in data if line[:9] == 'Revision:'][-1]
+ data = os.popen("env LC_ALL=C svn info %s" \
+ % (self.datastore)).readlines()
+ revline = [line.split(': ')[1].strip() for line in data \
+ if line[:9] == 'Revision:'][-1]
self.revision = revline
except IndexError:
logger.error("Failed to read svn info; disabling svn support")
@@ -255,7 +270,8 @@ class Core(object):
if isinstance(plugin, Bcfg2.Server.Plugin.Decision):
result += plugin.GetDecisions(metadata, mode)
except:
- logger.error("Plugin: %s failed to generate decision list" % plugin.name, exc_info=1)
+ logger.error("Plugin: %s failed to generate decision list" \
+ % plugin.name, exc_info=1)
return result
def build_metadata(self, client_name):