diff options
author | Narayan Desai <desai@mcs.anl.gov> | 2006-04-10 20:01:43 +0000 |
---|---|---|
committer | Narayan Desai <desai@mcs.anl.gov> | 2006-04-10 20:01:43 +0000 |
commit | 4521ebcfcf106db5a67cf126bf94d0cd987cebc4 (patch) | |
tree | 6141b504a1885db71149af98ec8c9eea5e57853e | |
parent | 9a2c22595a8261462ed17e7fc9df49cc4d7ba77f (diff) | |
download | bcfg2-4521ebcfcf106db5a67cf126bf94d0cd987cebc4.tar.gz bcfg2-4521ebcfcf106db5a67cf126bf94d0cd987cebc4.tar.bz2 bcfg2-4521ebcfcf106db5a67cf126bf94d0cd987cebc4.zip |
* Fix schema validation for host specific service entries
* Move to using generic rule-based core (in preparation for the rules plugin)
git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@1827 ce84e21b-d406-0410-9b95-82705330c041
-rw-r--r-- | schemas/services.xsd | 2 | ||||
-rw-r--r-- | src/lib/Server/Plugin.py | 77 | ||||
-rw-r--r-- | src/lib/Server/Plugins/Pkgmgr.py | 31 | ||||
-rw-r--r-- | src/lib/Server/Plugins/Svcmgr.py | 12 |
4 files changed, 71 insertions, 51 deletions
diff --git a/schemas/services.xsd b/schemas/services.xsd index f7524ec4d..25b59b33c 100644 --- a/schemas/services.xsd +++ b/schemas/services.xsd @@ -38,7 +38,7 @@ <xsd:choice minOccurs='0' maxOccurs='unbounded'> <xsd:element name='Service' type='ServiceType'/> <xsd:element name='Group' type='ContainerType'/> - <xsd:element name='Host' type='ContainerType'/> + <xsd:element name='Client' type='ContainerType'/> </xsd:choice> <xsd:attribute name='priority' type='xsd:integer'/> </xsd:complexType> diff --git a/src/lib/Server/Plugin.py b/src/lib/Server/Plugin.py index 4c4406747..dad8bec46 100644 --- a/src/lib/Server/Plugin.py +++ b/src/lib/Server/Plugin.py @@ -191,13 +191,14 @@ class StructFile(XMLFileBacked): logger.error("File %s got null match" % (self.name)) return [] -class LNode: +class INode: '''LNodes provide lists of things available at a particular group intersection''' raw = {'Client':"lambda x:'%s' == x.hostname and predicate(x)", 'Group':"lambda x:'%s' in x.groups and predicate(x)"} - __leaf__ = './Child' + containers = ['Group', 'Client'] + ignore = [] - def __init__(self, data, plist, parent=None): + def __init__(self, data, idict, parent=None): self.data = data self.contents = {} if parent == None: @@ -209,30 +210,46 @@ class LNode: else: raise Exception mytype = self.__class__ - self.children = [mytype(child, plist, self) for child in data.getchildren() - if child.tag in ['Group', 'Client']] - for leaf in data.findall(self.__leaf__): - self.contents[leaf.get('name')] = leaf.attrib - if leaf.get('name') not in plist: - plist.append(leaf.get('name')) + self.children = [] + for item in data.getchildren(): + if item.tag in self.ignore: + continue + elif item.tag in self.containers: + self.children.append(mytype(item, idict, self)) + else: + try: + self.contents[item.tag][item.get('name')] = item.attrib + except KeyError: + self.contents[item.tag] = {item.get('name'):item.attrib} + if item.text: + self.contents[item.tag]['__text__'] = item.text + try: + idict[item.tag].append(item.get('name')) + except KeyError: + idict[item.tag] = [item.get('name')] def Match(self, metadata, data): '''Return a dictionary of package mappings''' if self.predicate(metadata): - data.update(self.contents) + for key in self.contents: + try: + data[key].update(self.contents[key]) + except: + data[key] = {} + data[key].update(self.contents[key]) for child in self.children: child.Match(metadata, data) class XMLSrc(XMLFileBacked): '''XMLSrc files contain a LNode hierarchy that returns matching entries''' - __node__ = LNode + __node__ = INode def __init__(self, filename): XMLFileBacked.__init__(self, filename) - self.names = [] + self.items = {} self.cache = None self.pnode = None - self.priority = '1000' + self.priority = -1 def HandleEvent(self, event=None): '''Read file upon update''' @@ -241,15 +258,18 @@ class XMLSrc(XMLFileBacked): except IOError: logger.error("Failed to read file %s" % (self.name)) return - self.names = [] + self.items = {} try: xdata = lxml.etree.XML(data) except lxml.etree.XMLSyntaxError: logger.error("Failed to parse file %s" % (self.name)) return - self.pnode = self.__node__(xdata, self.names) + self.pnode = self.__node__(xdata, self.items) self.cache = None - self.priority = xdata.get('priority') + try: + self.priority = int(xdata.get('priority')) + except: + logger.error("Got bogus priority %s for file %s" % (xdata.get('priority'), self.name)) del xdata, data def Cache(self, metadata): @@ -263,27 +283,29 @@ class XMLSrc(XMLFileBacked): self.pnode.Match(metadata, cache[1]) self.cache = cache -class XMLPrioDir(Plugin, DirectoryBacked): +class PrioDir(Plugin, DirectoryBacked): '''This is a generator that handles package assignments''' - __name__ = 'XMLPrioDir' + __name__ = 'PrioDir' __child__ = XMLSrc - __element__ = 'Dummy' def __init__(self, core, datastore): Plugin.__init__(self, core, datastore) - self.Entries[self.__element__] = {} try: DirectoryBacked.__init__(self, self.data, self.core.fam) except OSError: - self.logger.error("Failed to load %s indices" % (self.__element__.lower())) + self.logger.error("Failed to load %s indices" % (self.__name__)) raise PluginInitError def HandleEvent(self, event): '''Handle events and update dispatch table''' DirectoryBacked.HandleEvent(self, event) for src in self.entries.values(): - for child in src.names: - self.Entries[self.__element__][child] = self.BindEntry + for itype, children in src.items.iteritems(): + for child in children: + try: + self.Entries[itype][child] = self.BindEntry + except KeyError: + self.Entries[itype] = {child: self.BindEntry} def BindEntry(self, entry, metadata): '''Check package lists of package entries''' @@ -293,7 +315,7 @@ class XMLPrioDir(Plugin, DirectoryBacked): self.logger.error("Called before data loaded") raise PluginExecutionError matching = [src for src in self.entries.values() - if src.cache[1].has_key(name)] + if src.cache[1].has_key(entry.tag) and src.cache[1][entry.tag].has_key(name)] if len(matching) == 0: raise PluginExecutionError elif len(matching) == 1: @@ -302,9 +324,12 @@ class XMLPrioDir(Plugin, DirectoryBacked): 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" % - (self.__element__.lower(), metadata.hostname, entry.get('name'))) + (entry.tag.lower(), metadata.hostname, entry.get('name'))) raise PluginExecutionError index = prio.index(max(prio)) - data = matching[index].cache[1][name] + data = matching[index].cache[1][entry.tag][name] [entry.attrib.__setitem__(key, data[key]) for key in data.keys()] + if data.has_key('__text__'): + del entry.attrib['__text__'] + entry.text = data['__text__'] diff --git a/src/lib/Server/Plugins/Pkgmgr.py b/src/lib/Server/Plugins/Pkgmgr.py index 2367c7c22..a322af0d0 100644 --- a/src/lib/Server/Plugins/Pkgmgr.py +++ b/src/lib/Server/Plugins/Pkgmgr.py @@ -5,24 +5,29 @@ import logging, re, Bcfg2.Server.Plugin logger = logging.getLogger('Bcfg2.Plugins.Pkgmgr') -class PNode(Bcfg2.Server.Plugin.LNode): +class PNode(Bcfg2.Server.Plugin.INode): '''PNode has a list of packages available at a particular group intersection''' splitters = {'rpm':re.compile('^(?P<name>[\w\+\d\.]+(-[\w\+\d\.]+)*)-' + \ '(?P<version>[\w\d\.]+-([\w\d\.]+))\.(?P<arch>\w+)\.rpm$'), 'encap':re.compile('^(?P<name>\w+)-(?P<version>[\w\d\.-]+).encap.*$')} + ignore = ['Package'] - def __init__(self, data, plist, parent=None): + def __init__(self, data, pdict, parent=None): # copy local attributes to all child nodes if no local attribute exists + if not pdict.has_key('Package'): + pdict['Package'] = [] for child in data.getchildren(): for attr in [key for key in data.attrib.keys() if key != 'name' and not child.attrib.has_key(key)]: child.set(attr, data.get(attr)) - Bcfg2.Server.Plugin.LNode.__init__(self, data, plist, parent) + Bcfg2.Server.Plugin.INode.__init__(self, data, pdict, parent) + if not self.contents.has_key('Package'): + self.contents['Package'] = {} for pkg in data.findall('./Package'): - if pkg.attrib.has_key('name') and pkg.get('name') not in plist: - plist.append(pkg.get('name')) + if pkg.attrib.has_key('name') and pkg.get('name') not in pdict['Package']: + pdict['Package'].append(pkg.get('name')) if pkg.attrib.has_key('simplefile'): pkg.set('url', "%s/%s" % (pkg.get('uri'), pkg.get('simplefile'))) - self.contents[pkg.get('name')] = pkg.attrib + self.contents['Package'][pkg.get('name')] = pkg.attrib else: if pkg.attrib.has_key('file'): pkg.set('url', '%s/%s' % (pkg.get('uri'), pkg.get('file'))) @@ -32,20 +37,20 @@ class PNode(Bcfg2.Server.Plugin.LNode): logger.error("Failed to match pkg %s" % pkg.get('file')) continue pkgname = mdata.group('name') - self.contents[pkgname] = mdata.groupdict() + self.contents['Package'][pkgname] = mdata.groupdict() if pkg.attrib.get('file'): - self.contents[pkgname]['url'] = pkg.get('url') - self.contents[pkgname]['type'] = pkg.get('type') - if pkgname not in plist: - plist.append(pkgname) + self.contents['Package'][pkgname]['url'] = pkg.get('url') + self.contents['Package'][pkgname]['type'] = pkg.get('type') + if pkgname not in pdict['Package']: + pdict['Package'].append(pkgname) else: - self.contents[pkg.get('name')] = pkg.attrib + self.contents['Package'][pkg.get('name')] = pkg.attrib class PkgSrc(Bcfg2.Server.Plugin.XMLSrc): '''PkgSrc files contain a PNode hierarchy that returns matching package entries''' __node__ = PNode -class Pkgmgr(Bcfg2.Server.Plugin.XMLPrioDir): +class Pkgmgr(Bcfg2.Server.Plugin.PrioDir): '''This is a generator that handles package assignments''' __name__ = 'Pkgmgr' __version__ = '$Id$' diff --git a/src/lib/Server/Plugins/Svcmgr.py b/src/lib/Server/Plugins/Svcmgr.py index da5ab341c..23f06b627 100644 --- a/src/lib/Server/Plugins/Svcmgr.py +++ b/src/lib/Server/Plugins/Svcmgr.py @@ -3,18 +3,8 @@ __revision__ = '$Revision$' import Bcfg2.Server.Plugin -class SNode(Bcfg2.Server.Plugin.LNode): - '''SNode has a list of services available at a particular group intersection''' - __leaf__ = './Service' - -class SvcSrc(Bcfg2.Server.Plugin.XMLSrc): - '''SvcSrc files contain prioritized service definitions''' - __node__ = SNode - -class Svcmgr(Bcfg2.Server.Plugin.XMLPrioDir): +class Svcmgr(Bcfg2.Server.Plugin.PrioDir): '''This is a generator that handles service assignments''' __name__ = 'Svcmgr' __version__ = '$Id$' __author__ = 'bcfg-dev@mcs.anl.gov' - __child__ = SvcSrc - __element__ = 'Service' |