From 3610288cbcbf4d1adedefa03166cd77ee15aad96 Mon Sep 17 00:00:00 2001 From: Narayan Desai Date: Sat, 29 Dec 2007 04:57:53 +0000 Subject: Refactor of bcfg2-admin (all modes moved to discrete modules in Bcfg2.Server.Admin git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@4125 ce84e21b-d406-0410-9b95-82705330c041 --- src/lib/Server/Admin/Compare.py | 131 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 src/lib/Server/Admin/Compare.py (limited to 'src/lib/Server/Admin/Compare.py') diff --git a/src/lib/Server/Admin/Compare.py b/src/lib/Server/Admin/Compare.py new file mode 100644 index 000000000..962e54606 --- /dev/null +++ b/src/lib/Server/Admin/Compare.py @@ -0,0 +1,131 @@ + +import lxml.etree, os +import Bcfg2.Server.Admin + +class Compare(Bcfg2.Server.Admin.Mode): + __shorthelp__ = "bcfg2-admin compare \nbcfg2-admin compare -r " + __longhelp__ = __shorthelp__ + '''\n\tCompare mode determines differences between directories of client specification instances''' + + def __init__(self, configfile): + Bcfg2.Server.Admin.Mode.__init__(self, configfile) + self.important = {'Package':['name', 'version'], + 'Service':['name', 'status'], + 'Directory':['name', 'owner', 'group', 'perms'], + 'SymLink':['name', 'to'], + 'ConfigFile':['name', 'owner', 'group', 'perms'], + 'Permissions':['name', 'perms'], + 'PostInstall':['name']} + + def compareStructures(self, new, old): + for child in new.getchildren(): + equiv = old.xpath('%s[@name="%s"]' % (child.tag, child.get('name'))) + if child.tag in self.important: + print "tag type %s not handled" % (child.tag) + continue + if len(equiv) == 0: + print "didn't find matching %s %s" % (child.tag, child.get('name')) + continue + elif len(equiv) >= 1: + if child.tag == 'ConfigFile': + if child.text != equiv[0].text: + print " %s %s contents differ" \ + % (child.tag, child.get('name')) + continue + noattrmatch = [field for field in self.important[child.tag] if \ + child.get(field) != equiv[0].get(field)] + if not noattrmatch: + new.remove(child) + old.remove(equiv[0]) + else: + print " %s %s attributes %s do not match" % \ + (child.tag, child.get('name'), noattrmatch) + if len(old.getchildren()) == 0 and len(new.getchildren()) == 0: + return True + if new.tag == 'Independant': + name = 'Base' + else: + name = new.get('name') + both = [] + oldl = ["%s %s" % (entry.tag, entry.get('name')) for entry in old] + newl = ["%s %s" % (entry.tag, entry.get('name')) for entry in new] + for entry in newl: + if entry in oldl: + both.append(entry) + newl.remove(entry) + oldl.remove(entry) + for entry in both: + print " %s differs (in bundle %s)" % (entry, name) + for entry in oldl: + print " %s only in old configuration (in bundle %s)" % (entry, name) + for entry in newl: + print " %s only in new configuration (in bundle %s)" % (entry, name) + return False + + def compareSpecifications(self, path1, path2): + try: + new = lxml.etree.parse(path1).getroot() + except IOError: + print "Failed to read %s" % (path1) + raise SystemExit(1) + + try: + old = lxml.etree.parse(path2).getroot() + except IOError: + print "Failed to read %s" % (path2) + raise SystemExit(1) + + for src in [new, old]: + for bundle in src.findall('./Bundle'): + if bundle.get('name')[-4:] == '.xml': + bundle.set('name', bundle.get('name')[:-4]) + + rcs = [] + for bundle in new.findall('./Bundle'): + equiv = old.xpath('Bundle[@name="%s"]' % (bundle.get('name'))) + if len(equiv) == 0: + print "couldnt find matching bundle for %s" % bundle.get('name') + continue + if len(equiv) == 1: + if self.compareStructures(bundle, equiv[0]): + new.remove(bundle) + old.remove(equiv[0]) + rcs.append(True) + else: + rcs.append(False) + else: + print "Unmatched bundle %s" % (bundle.get('name')) + rcs.append(False) + i1 = new.find('./Independant') + i2 = old.find('./Independant') + if self.compareStructures(i1, i2): + new.remove(i1) + old.remove(i2) + else: + rcs.append(False) + return False not in rcs + + def __call__(self, args): + Bcfg2.Server.Admin.Mode.__call__(self, args) + if '-r' in args: + args = list(args) + args.remove('-r') + (oldd, newd) = args + (old, new) = [os.listdir(spot) for spot in args] + for item in old: + print "Entry:", item + state = self.__call__([oldd + '/' + item, newd + '/' + item]) + new.remove(item) + if state: + print "Entry:", item, "good" + else: + print "Entry:", item, "bad" + if new: + print "new has extra entries", new + return + try: + (old, new) = args + except IndexError: + print self.__call__.__doc__ + raise SystemExit + + -- cgit v1.2.3-1-g7c22