diff options
-rw-r--r-- | doc/1.0-roadmap | 10 | ||||
-rw-r--r-- | doc/plugin-roles | 34 | ||||
-rw-r--r-- | src/lib/Server/Core.py | 52 |
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): |