From 6f6180867cb8d72a6933c30e7b0ee5a993898e9c Mon Sep 17 00:00:00 2001 From: xschlef Date: Fri, 27 Apr 2018 09:09:16 +0200 Subject: [PATCH 1/3] add hierarchy plugin that re-adds the lost group hierarchy information for use in bcfg2 --- src/lib/Bcfg2/Server/Plugins/Hierarchy.py | 100 ++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 src/lib/Bcfg2/Server/Plugins/Hierarchy.py diff --git a/src/lib/Bcfg2/Server/Plugins/Hierarchy.py b/src/lib/Bcfg2/Server/Plugins/Hierarchy.py new file mode 100644 index 0000000000..1767c11271 --- /dev/null +++ b/src/lib/Bcfg2/Server/Plugins/Hierarchy.py @@ -0,0 +1,100 @@ +""" + Support for metadata.Hierarchy, which adds + group hierarchy information with the profile + as anchor. +""" + +import copy +import os +import sys + +import lxml + +import Bcfg2.Server.Plugin +from Bcfg2.Server.Cache import Cache +from Bcfg2.Server.Plugin import PluginExecutionError + + +class Hierarchy(Bcfg2.Server.Plugin.Plugin, + Bcfg2.Server.Plugin.Connector): + """ adds the group hierarchy information to metadata + this information is lost in metadata.groups """ + + def __init__(self, core): + Bcfg2.Server.Plugin.Plugin.__init__(self, core) + Bcfg2.Server.Plugin.Connector.__init__(self) + self._cache = Bcfg2.Server.Cache.Cache("Hierarchy") + + # inform us when a cache has been expired + # if a metadata object changed we have to + # expire the cache as well + Bcfg2.Server.Cache.add_expire_hook(self._cache_expire_handler) + + __init__.__doc__ = Bcfg2.Server.Plugin.Plugin.__init__.__doc__ + + def get_additional_data(self, metadata): + """ Parse through all groups of this client + add hierarchy information so it can be used + by other tools later """ + self.debug_log("Hierarchy: Getting hierarchy for %s" % + metadata.hostname) + if metadata.hostname in self._cache: + return self._cache[metadata.hostname] + + # profile is our anchor group + # if we don't add it here we get a circular reference + visited_groups = set([metadata.profile]) + hierarchy = dict() + for grp in metadata.groups: + hierarchy[grp] = set() + # get all children of the group + for child in self.core.metadata.groups_xml.xdata.xpath( + "//Groups/Group[@name='%s']//Group" % grp): + # safeguard so only groups are added that this + # client is part of + if child.get('name') in metadata.groups: + hierarchy[grp].add(child.get('name')) + visited_groups.add(child.get('name')) + + # postprocessing for groups that are added by probes or other plugins + # these are children of profile in the hierarchy + for grp in (set(metadata.groups) - visited_groups): + hierarchy[metadata.profile].add(grp) + + self._cache[metadata.hostname] = hierarchy + return hierarchy + + def _cache_expire_handler(self, tags, exact, count): + """ listens for caches that were expired. + If the metadata cache was expired for + a single host or entirely, then the local + cache is cleared as well. """ + self.logger.debug("Hierarchy: Got Cache expire event. " + "Tags: %s, exact=%s, count=%s" % + (tags, exact, count)) + if not tags or "Hierarchy" in tags: + return + try: + # tags are tuples (hostname, "Metadata") to expire + # a single hostname + # or ("Metadata",) if the whole metadata cache was cleared + if len(tags) == 2 and "Metadata" in tags: + if tags[0] == "Metadata": + self._cache.expire() + self.debug_log("Hierarchy: Expiring cache %s %s" % + (str(tags), str(exact))) + else: + self._cache.expire(tags[0]) + self.debug_log("Hierarchy: Expiring cache %s %s" % + (str(tags), str(exact))) + except: + self.logger.warn("Hierarchy: Error choosing if" + " cache should be expired. Expiring anyway. %s" + % (str(tags))) + self._cache.expire() + + def set_debug(self, debug): + rv = Bcfg2.Server.Plugin.Plugin.set_debug(self, debug) + return rv + + set_debug.__doc__ = Bcfg2.Server.Plugin.Plugin.set_debug.__doc__ From c33262f6bcd478c9044bc80b7be6b887aac43bc7 Mon Sep 17 00:00:00 2001 From: xschlef Date: Fri, 27 Apr 2018 10:02:57 +0200 Subject: [PATCH 2/3] fix imports and tightened exception --- src/lib/Bcfg2/Server/Plugins/Hierarchy.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/lib/Bcfg2/Server/Plugins/Hierarchy.py b/src/lib/Bcfg2/Server/Plugins/Hierarchy.py index 1767c11271..0747208db3 100644 --- a/src/lib/Bcfg2/Server/Plugins/Hierarchy.py +++ b/src/lib/Bcfg2/Server/Plugins/Hierarchy.py @@ -5,14 +5,9 @@ """ import copy -import os -import sys - -import lxml import Bcfg2.Server.Plugin from Bcfg2.Server.Cache import Cache -from Bcfg2.Server.Plugin import PluginExecutionError class Hierarchy(Bcfg2.Server.Plugin.Plugin, @@ -87,10 +82,12 @@ def _cache_expire_handler(self, tags, exact, count): self._cache.expire(tags[0]) self.debug_log("Hierarchy: Expiring cache %s %s" % (str(tags), str(exact))) - except: + except Exception as e: self.logger.warn("Hierarchy: Error choosing if" - " cache should be expired. Expiring anyway. %s" - % (str(tags))) + " cache should be expired. Expiring anyway. " + "Tags %s, " + "Error: %s" + % (str(tags), e)) self._cache.expire() def set_debug(self, debug): From 5d0442ad47bd8a1ceb4dda11f60416537e76bcf7 Mon Sep 17 00:00:00 2001 From: xschlef Date: Thu, 4 Oct 2018 09:35:26 +0200 Subject: [PATCH 3/3] fix imports and a too general exception --- src/lib/Bcfg2/Server/Plugins/Hierarchy.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/lib/Bcfg2/Server/Plugins/Hierarchy.py b/src/lib/Bcfg2/Server/Plugins/Hierarchy.py index 0747208db3..33190a03b3 100644 --- a/src/lib/Bcfg2/Server/Plugins/Hierarchy.py +++ b/src/lib/Bcfg2/Server/Plugins/Hierarchy.py @@ -4,10 +4,8 @@ as anchor. """ -import copy - import Bcfg2.Server.Plugin -from Bcfg2.Server.Cache import Cache +import Bcfg2.Server.Cache class Hierarchy(Bcfg2.Server.Plugin.Plugin, @@ -82,12 +80,12 @@ def _cache_expire_handler(self, tags, exact, count): self._cache.expire(tags[0]) self.debug_log("Hierarchy: Expiring cache %s %s" % (str(tags), str(exact))) - except Exception as e: + except KeyError as error: self.logger.warn("Hierarchy: Error choosing if" " cache should be expired. Expiring anyway. " "Tags %s, " "Error: %s" - % (str(tags), e)) + % (str(tags), error)) self._cache.expire() def set_debug(self, debug):