#!/usr/bin/env python ''' bcfg2-repo-validate checks all xml files in Bcfg2 repos against their respective XML schemas ''' __revision__ = '$Revision$' import glob, lxml.etree, os, sys import Bcfg2.Options try: pdlist = set except NameError: class pdlist(list): def add(self, item): if item not in self: self.append(item) def discard(self, item): if item in self: self.remove(item) if __name__ == '__main__': opts = {'repo': Bcfg2.Options.SERVER_REPOSITORY, 'prefix': Bcfg2.Options.INSTALL_PREFIX, 'verbose': Bcfg2.Options.VERBOSE, 'configfile': Bcfg2.Options.CFILE} setup = Bcfg2.Options.OptionParser(opts) setup.parse(sys.argv[1:]) verbose = setup['verbose'] cpath = setup['configfile'] prefix = setup['prefix'] schemadir = "%s/share/bcfg2/schemas" % (prefix) os.chdir(schemadir) repo = setup['repo'] # Get a list of all info.xml files in the bcfg2 repository info_list = [] for root, dirs, files in os.walk('%s' % repo): for filename in files: if filename == 'info.xml': info_list.append(os.path.join(root, filename)) if 'Bundler' in dirs: dirs.remove('Bundler') # get metadata list (with all included files) metadata_list = glob.glob("%s/Metadata/groups.xml" % repo) ref_bundles = pdlist() xdata = lxml.etree.parse("%s/Metadata/groups.xml" % repo) included = pdlist([ent.get('href') for ent in \ xdata.findall('./{http://www.w3.org/2001/XInclude}include')]) while included: try: filename = included.pop() except KeyError: continue metadata_list.append("%s/Metadata/%s" % (repo, filename)) groupdata = lxml.etree.parse("%s/Metadata/%s" % (repo, filename)) group_ents = [ent.get('href') for ent in \ groupdata.findall('./{http://www.w3.org/2001/XInclude}include')] for ent in group_ents: included.add(ent) included.discard(filename) # get all XIncluded bundles xdata.xinclude() for bundle in xdata.findall("//Bundle"): ref_bundles.add("%s/Bundler/%s.xml" % (repo, bundle.get('name'))) # get lists of all other xml files to validate clients_list = glob.glob("%s/Metadata/clients.xml" % repo) bundle_list = glob.glob("%s/Bundler/*.xml" % repo) pkg_list = glob.glob("%s/Pkgmgr/*.xml" % repo) base_list = glob.glob("%s/Base/*.xml" % repo) rules_list = glob.glob("%s/Rules/*.xml" % repo) imageinfo_list = glob.glob("%s/etc/report-configuration.xml" % repo) services_list = glob.glob("%s/Svcmgr/*.xml" % repo) deps_list = glob.glob("%s/Deps/*.xml" % repo) dec_list = glob.glob("%s/Decisions/*" % repo) filesets = {'metadata':(metadata_list, "%s/metadata.xsd"), 'clients':(clients_list, "%s/clients.xsd"), 'info':(info_list, "%s/info.xsd"), 'bundle':(bundle_list, "%s/bundle.xsd"), 'pkglist':(pkg_list, "%s/pkglist.xsd"), 'base':(base_list, "%s/base.xsd"), 'rules':(rules_list, "%s/rules.xsd"), 'imageinfo':(imageinfo_list, "%s/report-configuration.xsd"), 'services':(services_list, "%s/services.xsd"), 'deps':(deps_list, "%s/deps.xsd"), 'decisions': (dec_list, "%s/decisions.xsd")} failures = 0 for k, (filelist, schemaname) in filesets.iteritems(): try: schema = lxml.etree.XMLSchema(lxml.etree.parse(open(schemaname%(schemadir)))) except: print "Failed to process schema %s" % (schemaname%(schemadir)) failures = 1 continue for filename in filelist: try: datafile = lxml.etree.parse(open(filename)) except SyntaxError: print "%s ***FAILS*** to parse \t\t<----" % (filename) os.system("xmllint %s" % filename) failures = 1 continue except IOError: print "Failed to open file %s \t\t<---" % (filename) failures = 1 continue if schema.validate(datafile): if verbose: print "%s checks out" % (filename) else: rc = os.system("xmllint --noout --xinclude --schema \ %s %s > /dev/null 2>/dev/null" % \ (schemaname % schemadir, filename)) if rc: failures = 1 print "%s ***FAILS*** to verify \t\t<----" % (filename) os.system("xmllint --noout --xinclude --schema %s %s" % \ (schemaname % schemadir, filename)) elif verbose: print "%s checks out" % (filename) # print out missing bundle information if verbose: print("") for bundle in ref_bundles: if bundle not in bundle_list: print ("*** Warning: Bundle %s referenced, but does not " "exist." % bundle) raise SystemExit, failures