diff options
author | Narayan Desai <desai@mcs.anl.gov> | 2006-07-10 21:27:47 +0000 |
---|---|---|
committer | Narayan Desai <desai@mcs.anl.gov> | 2006-07-10 21:27:47 +0000 |
commit | 8ea40c8c26141f1a5e36c9a98b451bd1599c2e5c (patch) | |
tree | 8b50bed6a3df4bd5fd968860584206c69a30db60 | |
parent | a50f44d85caefe94a0e15dd5b24232c8af29440c (diff) | |
download | bcfg2-8ea40c8c26141f1a5e36c9a98b451bd1599c2e5c.tar.gz bcfg2-8ea40c8c26141f1a5e36c9a98b451bd1599c2e5c.tar.bz2 bcfg2-8ea40c8c26141f1a5e36c9a98b451bd1599c2e5c.zip |
Add basic dependency processing code
* To enable, add a Deps directory and enable the Deps plugin
* schema validation works
* prerequisites are automatically added to configurations
git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@1924 ce84e21b-d406-0410-9b95-82705330c041
-rw-r--r-- | schemas/deps.xsd | 52 | ||||
-rw-r--r-- | src/lib/Server/Core.py | 5 | ||||
-rw-r--r-- | src/lib/Server/Plugins/Deps.py | 92 | ||||
-rw-r--r-- | src/sbin/bcfg2-repo-validate | 3 |
4 files changed, 151 insertions, 1 deletions
diff --git a/schemas/deps.xsd b/schemas/deps.xsd new file mode 100644 index 000000000..19ec5af2d --- /dev/null +++ b/schemas/deps.xsd @@ -0,0 +1,52 @@ +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xml:lang="en"> + + <xsd:annotation> + <xsd:documentation> + dependency schema for bcfg2 + Narayan Desai, Argonne National Laboratory + </xsd:documentation> + </xsd:annotation> + + <xsd:complexType name='StructureEntry'> + <xsd:choice minOccurs='0' maxOccurs='unbounded'> + <xsd:element name='Package' type='StructureEntry'/> + <xsd:element name='Service' type='StructureEntry'/> + <xsd:element name='ConfigFile' type='StructureEntry'/> + <xsd:element name='Directory' type='StructureEntry'/> + <xsd:element name='SymLink' type='StructureEntry'/> + <xsd:element name='Permissions' type='StructureEntry'/> + <xsd:element name='PostInstall' type='StructureEntry'/> + </xsd:choice> + <xsd:attribute type='xsd:string' name='name' use='required'/> + </xsd:complexType> + + <xsd:complexType name='GroupType'> + <xsd:choice minOccurs='0' maxOccurs='unbounded'> + <xsd:element name='Package' type='StructureEntry'/> + <xsd:element name='Service' type='StructureEntry'/> + <xsd:element name='ConfigFile' type='StructureEntry'/> + <xsd:element name='Directory' type='StructureEntry'/> + <xsd:element name='SymLink' type='StructureEntry'/> + <xsd:element name='Permissions' type='StructureEntry'/> + <xsd:element name='PostInstall' type='StructureEntry'/> + <xsd:element name='Group' type='GroupType'/> + </xsd:choice> + <xsd:attribute type='xsd:string' name='name' use='required'/> + </xsd:complexType> + + <xsd:element name='Dependencies'> + <xsd:complexType> + <xsd:choice minOccurs='0' maxOccurs='unbounded'> + <xsd:element name='Package' type='StructureEntry'/> + <xsd:element name='Service' type='StructureEntry'/> + <xsd:element name='ConfigFile' type='StructureEntry'/> + <xsd:element name='Directory' type='StructureEntry'/> + <xsd:element name='SymLink' type='StructureEntry'/> + <xsd:element name='Permission' type='StructureEntry'/> + <xsd:element name='PostInstall' type='StructureEntry'/> + <xsd:element name='Group' type='GroupType'/> + </xsd:choice> + <xsd:attribute type='xsd:string' name='priority' use='required'/> + </xsd:complexType> + </xsd:element> +</xsd:schema>
\ No newline at end of file diff --git a/src/lib/Server/Core.py b/src/lib/Server/Core.py index e417f9aa0..6f11e83e7 100644 --- a/src/lib/Server/Core.py +++ b/src/lib/Server/Core.py @@ -293,6 +293,11 @@ class Core(object): except: logger.error("error in GetStructures", exc_info=1) return lxml.etree.Element("error", type='structure error') + + if self.plugins.has_key('Deps'): + # do prereq processing + prereqs = self.plugins['Deps'].GeneratePrereqs(structures, meta) + structures.append(prereqs) for astruct in structures: try: diff --git a/src/lib/Server/Plugins/Deps.py b/src/lib/Server/Plugins/Deps.py new file mode 100644 index 000000000..945c53e70 --- /dev/null +++ b/src/lib/Server/Plugins/Deps.py @@ -0,0 +1,92 @@ +'''This plugin provides automatic dependency handling''' +__revision__ = '$Revision:$' + +import Bcfg2.Server.Plugin, lxml.etree + +class DNode(Bcfg2.Server.Plugin.INode): + '''DNode provides supports for single predicate types for dependencies''' + raw = {'Group':"lambda x:'%s' in x.groups and predicate(x)"} + containers = ['Group'] + + def __init__(self, data, idict, parent=None): + self.data = data + self.contents = {} + if parent == None: + self.predicate = lambda x:True + else: + predicate = parent.predicate + if data.tag in self.raw.keys(): + self.predicate = eval(self.raw[data.tag] % (data.get('name')), {'predicate':predicate}) + else: + raise Exception + mytype = self.__class__ + self.children = [] + for item in data.getchildren(): + if item.tag in self.containers: + self.children.append(mytype(item, idict, self)) + else: + data = [(child.tag, child.get('name')) for child in item.getchildren()] + try: + self.contents[item.tag][item.get('name')] = data + except KeyError: + self.contents[item.tag] = {item.get('name'):data} + +class DepXMLSrc(Bcfg2.Server.Plugin.XMLSrc): + __node__ = DNode + +class Deps(Bcfg2.Server.Plugin.PrioDir): + __name__ = 'Deps' + __version__ = '$Id:$' + __author__ = 'bcfg-dev@mcs.anl.gov' + __child__ = DepXMLSrc + + def __init__(self, core, datastore): + Bcfg2.Server.Plugin.PrioDir.__init__(self, core, datastore) + self.cache = {} + + def HandleEvent(self, event): + self.cache = {} + Bcfg2.Server.Plugin.PrioDir.HandleEvent(self, event) + + def GeneratePrereqs(self, structures, metadata): + entries = [] + prereqs = [] + for structure in structures: + for entry in structure.getchildren(): + if (entry.tag, entry.get('name')) not in entries: + entries.append((entry.tag, entry.get('name'))) + entries.sort() + entries = tuple(entries) + gdata = metadata.groups[:] + gdata.sort() + gdata = tuple(gdata) + if self.cache.has_key((entries, gdata)): + prereqs = self.cache[(entries, gdata)] + else: + [src.Cache(metadata) for src in self.entries.values()] + + for entry in entries: + matching = [src for src in self.entries.values() + if src.cache and src.cache[1].has_key(entry[0]) + and src.cache[1][entry[0]].has_key(entry[1])] + if len(matching) > 1: + prio = [int(src.priority) for src in matching] + if prio.count(max(prio)) > 1: + self.logger.error("Found conflicting %s sources with same priority for %s, pkg %s" % + (entry[0].lower(), metadata.hostname, entry[1])) + raise PluginExecutionError + index = prio.index(max(prio)) + matching = [matching[index]] + + if not matching: + continue + elif len(matching) == 1: + for prq in src.cache[1][entry[0]][entry[1]]: + if prq not in prereqs: + prereqs.append(prq) + self.cache[(entries, gdata)] = prereqs + + newstruct = lxml.etree.Element("Independant") + for tag, name in prereqs: + lxml.etree.SubElement(newstruct, tag, name=name) + return newstruct diff --git a/src/sbin/bcfg2-repo-validate b/src/sbin/bcfg2-repo-validate index 2ec7a20b4..360dbf45f 100644 --- a/src/sbin/bcfg2-repo-validate +++ b/src/sbin/bcfg2-repo-validate @@ -31,7 +31,8 @@ if __name__ == '__main__': 'base':("%s/Base/*.xml", "%s/base.xsd"), 'base':("%s/Rules/*.xml", "%s/rules.xsd"), 'imageinfo':("%s/etc/reports.xml", "%s/report-configuration.xsd"), - 'services':("%s/Svcmgr/*.xml", "%s/services.xsd")} + 'services':("%s/Svcmgr/*.xml", "%s/services.xsd"), + 'deps':("%s/Deps/*.xml", "%s/deps.xsd")} failures = 0 for k, (spec, schemaname) in filesets.iteritems(): |