From 10eb57597eecdb42e931a5f817af58b508e2fff9 Mon Sep 17 00:00:00 2001 From: Sol Jerome Date: Fri, 27 Apr 2012 18:51:15 -0500 Subject: DBStats: Add unpruned entry reporting (#659) Path type='directory' entries previously had no 'reason' associated with their 'dirty' state. This change adds a database field for unpruned entries which are present in a pruned directory and displays that list in the web reporting interface. There is also a change made to the POSIX client tool which forces it to display the extra entry list when running in interactive mode without debugging enabled. Signed-off-by: Sol Jerome --- src/lib/Bcfg2/Client/Tools/POSIX.py | 20 ++++++++++---------- src/lib/Bcfg2/Server/Plugins/DBStats.py | 2 ++ src/lib/Bcfg2/Server/Reports/importscript.py | 8 +++++++- src/lib/Bcfg2/Server/Reports/reports/models.py | 1 + .../Reports/reports/templates/config_items/item.html | 15 +++++++++++++++ .../Server/Reports/reports/templatetags/split.py | 8 ++++++++ src/lib/Bcfg2/Server/Reports/updatefix.py | 1 + 7 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 src/lib/Bcfg2/Server/Reports/reports/templatetags/split.py (limited to 'src') diff --git a/src/lib/Bcfg2/Client/Tools/POSIX.py b/src/lib/Bcfg2/Client/Tools/POSIX.py index 9dd0362f3..0d67dbbab 100644 --- a/src/lib/Bcfg2/Client/Tools/POSIX.py +++ b/src/lib/Bcfg2/Client/Tools/POSIX.py @@ -20,7 +20,7 @@ import Bcfg2.Client.Tools import Bcfg2.Options from Bcfg2.Client import XML -log = logging.getLogger('posix') +log = logging.getLogger('POSIX') # map between dev_type attribute and stat constants device_map = {'block': stat.S_IFBLK, @@ -258,8 +258,8 @@ class POSIX(Bcfg2.Client.Tools.Tool): if entry.get('perms') == None or \ entry.get('owner') == None or \ entry.get('group') == None: - self.logger.error('Entry %s not completely specified. ' - 'Try running bcfg2-lint.' % (entry.get('name'))) + self.logger.error("POSIX: Entry %s not completely specified. " + "Try running bcfg2-lint." % (entry.get('name'))) return False while len(entry.get('perms', '')) < 4: entry.set('perms', '0' + entry.get('perms', '')) @@ -267,15 +267,15 @@ class POSIX(Bcfg2.Client.Tools.Tool): ondisk = os.stat(entry.get('name')) except OSError: entry.set('current_exists', 'false') - self.logger.debug("%s %s does not exist" % + self.logger.info("POSIX: %s %s does not exist" % (entry.tag, entry.get('name'))) return False try: owner = str(ondisk[stat.ST_UID]) group = str(ondisk[stat.ST_GID]) except (OSError, KeyError): - self.logger.error('User/Group resolution failed for path %s' % \ - entry.get('name')) + self.logger.info("POSIX: User/Group resolution failed " + "for path %s" % entry.get('name')) owner = 'root' group = '0' finfo = os.stat(entry.get('name')) @@ -300,11 +300,11 @@ class POSIX(Bcfg2.Client.Tools.Tool): ex_ents = [e for e in entries if e not in modlist] if ex_ents: pruneTrue = False - self.logger.debug("Directory %s contains extra entries:" % \ - entry.get('name')) - self.logger.debug(ex_ents) + self.logger.info("POSIX: Directory %s contains " + "extra entries:" % entry.get('name')) + self.logger.info(ex_ents) nqtext = entry.get('qtext', '') + '\n' - nqtext += "Directory %s contains extra entries:" % \ + nqtext += "Directory %s contains extra entries: " % \ entry.get('name') nqtext += ":".join(ex_ents) entry.set('qtest', nqtext) diff --git a/src/lib/Bcfg2/Server/Plugins/DBStats.py b/src/lib/Bcfg2/Server/Plugins/DBStats.py index 95395f74e..999e078b9 100644 --- a/src/lib/Bcfg2/Server/Plugins/DBStats.py +++ b/src/lib/Bcfg2/Server/Plugins/DBStats.py @@ -99,6 +99,8 @@ class DBStats(Bcfg2.Server.Plugin.Plugin, ret.append(getattr(entry.reason, "current_%s" % t)) if entry.reason.is_sensitive: raise Bcfg2.Server.Plugin.PluginExecutionError + elif len(entry.reason.unpruned) != 0: + ret.append('\n'.join(entry.reason.unpruned)) elif entry.reason.current_diff != '': if entry.reason.is_binary: ret.append(binascii.a2b_base64(entry.reason.current_diff)) diff --git a/src/lib/Bcfg2/Server/Reports/importscript.py b/src/lib/Bcfg2/Server/Reports/importscript.py index ea89c70cd..16df86a9b 100755 --- a/src/lib/Bcfg2/Server/Reports/importscript.py +++ b/src/lib/Bcfg2/Server/Reports/importscript.py @@ -40,6 +40,7 @@ from Bcfg2.Bcfg2Py3k import ConfigParser def build_reason_kwargs(r_ent, encoding, logger): binary_file = False sensitive_file = False + unpruned_entries = '' if r_ent.get('sensitive') in ['true', 'True']: sensitive_file = True rc_diff = '' @@ -57,6 +58,10 @@ def build_reason_kwargs(r_ent, encoding, logger): rc_diff = r_ent.get('current_diff') else: rc_diff = '' + # detect unmanaged entries in pruned directories + if r_ent.get('prune', 'false') == 'true' and r_ent.get('qtest'): + unpruned_elist = [e.get('path') for e in r_ent.findall('Prune')] + unpruned_entries = "\n".join(unpruned_elist) if not binary_file: try: rc_diff = rc_diff.decode(encoding) @@ -78,7 +83,8 @@ def build_reason_kwargs(r_ent, encoding, logger): current_exists=r_ent.get('current_exists', default="True").capitalize() == "True", current_diff=rc_diff, is_binary=binary_file, - is_sensitive=sensitive_file) + is_sensitive=sensitive_file, + unpruned=unpruned_entries) def load_stats(cdata, sdata, encoding, vlevel, logger, quick=False, location=''): diff --git a/src/lib/Bcfg2/Server/Reports/reports/models.py b/src/lib/Bcfg2/Server/Reports/reports/models.py index d141846a2..0438ea133 100644 --- a/src/lib/Bcfg2/Server/Reports/reports/models.py +++ b/src/lib/Bcfg2/Server/Reports/reports/models.py @@ -277,6 +277,7 @@ class Reason(models.Model): current_diff = models.TextField(max_length=1280, blank=True) is_binary = models.BooleanField(default=False) is_sensitive = models.BooleanField(default=False) + unpruned = models.TextField(max_length=1280, blank=True) def _str_(self): return "Reason" diff --git a/src/lib/Bcfg2/Server/Reports/reports/templates/config_items/item.html b/src/lib/Bcfg2/Server/Reports/reports/templates/config_items/item.html index cc99ef503..cadc178a7 100644 --- a/src/lib/Bcfg2/Server/Reports/reports/templates/config_items/item.html +++ b/src/lib/Bcfg2/Server/Reports/reports/templates/config_items/item.html @@ -1,4 +1,5 @@ {% extends "base.html" %} +{% load split %} {% load syntax_coloring %} @@ -91,6 +92,20 @@ div.entry_list h3 { {% endif %} + + {% if item.reason.unpruned %} +
+
+

Extra entries found

+
+ + {% for unpruned_item in item.reason.unpruned|split %} + + {% endfor %} +
{{ unpruned_item }}
+
+ {% endif %} +
diff --git a/src/lib/Bcfg2/Server/Reports/reports/templatetags/split.py b/src/lib/Bcfg2/Server/Reports/reports/templatetags/split.py new file mode 100644 index 000000000..a9b4f0371 --- /dev/null +++ b/src/lib/Bcfg2/Server/Reports/reports/templatetags/split.py @@ -0,0 +1,8 @@ +from django import template +register = template.Library() + + +@register.filter +def split(s): + """split by newlines""" + return s.split('\n') diff --git a/src/lib/Bcfg2/Server/Reports/updatefix.py b/src/lib/Bcfg2/Server/Reports/updatefix.py index 90eaacf89..39fc10b56 100644 --- a/src/lib/Bcfg2/Server/Reports/updatefix.py +++ b/src/lib/Bcfg2/Server/Reports/updatefix.py @@ -171,6 +171,7 @@ _fixes = [_merge_database_table_entries, 'alter table reports_reason add is_binary bool NOT NULL default False;', 'alter table reports_reason add is_sensitive bool NOT NULL default False;', _remove_table_column('reports_interaction', 'client_version'), + "alter table reports_reason add unpruned varchar(1280) not null default 'N/A';", ] # this will calculate the last possible version of the database -- cgit v1.2.3-1-g7c22