#!/usr/bin/env python import sys, os, re, ConfigParser from optparse import OptionParser sanitize_mapping = [ ('_','--') ] def guesssyntax(parm): # integer value if re.match('^\d+$', parm): return 'integerMatch', '1.3.6.1.4.1.1466.115.121.1.27' # boolean value if parm.lower() in [ 'true', 'false' ]: return 'caseExactIA5Match', '1.3.6.1.4.1.1466.115.121.1.26' #return 'booleanMatch', '1.3.6.1.4.1.1466.115.121.1.7' # FIXME # string value (default) return 'caseExactIA5Match', '1.3.6.1.4.1.1466.115.121.1.26' def sanitize(name): """Certain characters are not allowed in LDAP schema definitions. Maps to okay values.""" sanitized = name for old, new in sanitize_mapping: sanitized = sanitized.replace(old, new) return sanitized def desanitize(name): """Certain characters are not allowed in LDAP schema definitions. This returns to the original value.""" sanitized = name for old, new in sanitize_mapping: sanitized = sanitized.replace(new, old) return sanitized def formatattributes(attributes, maxperline=3): """openLDAP does not like long lines of attributes. This function splits to multiple lines based on maxperline""" if len(attributes) <= maxperline: return ' $ '.join(attributes) else: return '%s $ \\\n %s' % \ (' $ '.join(attributes[0:maxperline]), formatattributes(attributes[maxperline :], maxperline)) def genschema(oid, conffile, project='x-com-example', out=sys.stdout): cp = ConfigParser.SafeConfigParser() cp.read(conffile) shortname = os.path.basename(conffile).replace('.conf', '') out.write('#\n# schema based on config file %s\n#\n' % (conffile)) attributes = [] sectionsN = 0 for section in cp.sections(): sectionsN += 1 #print '\nSection: %s\n%s' % (section, '-'*50) optionsN = 0 for option in cp.options(section): optionsN += 1 #print '%s = "%s"' % (option, cp.get(section, option)) equality, syntax = guesssyntax(cp.get(section,option)) attribute_name = sanitize('%s--%s--%s' % (shortname, section, option)) attributes.append(attribute_name) out.write('%s\n' % (""" attributetype ( %s.1.%d.%d NAME '%s' DESC 'Brief description of %s found in section %s - UPDATEME' EQUALITY %s SYNTAX %s )""" % (oid, sectionsN, optionsN, \ attribute_name, \ option, section, \ equality, \ syntax))) out.write('%s\n' % (""" objectclass ( %s.2.%d NAME '%s-%s' SUP top STRUCTURAL DESC 'object collection description for %s-%s - UPDATEME' MUST ( cn ) MAY ( %s ) )\n""" % (oid, sectionsN, project, shortname, \ shortname, section, \ formatattributes(attributes)))) def genldif(conffile, project='x-com-example', basedn='dc=my-domain,dc=com', out=sys.stdout): cp = ConfigParser.SafeConfigParser() cp.read(conffile) shortname = os.path.basename(conffile).replace('.conf', '') out.write('#\n# LDIF data based on config file date from %s\n#\n' % (conffile)) out.write('dn: cn=%s,%s\n' % (shortname, basedn)) out.write('objectclass: %s-%s\n' % (project, shortname)) out.write('cn: %s\n' % (shortname)) for section in cp.sections(): for option in cp.options(section): attribute_name = sanitize('%s--%s--%s' % (shortname, section, option)) out.write('%s: %s\n' % (attribute_name, cp.get(section, option).replace('\n', '--\\NEWLINE--\n '))) #for option_section in cp.get(section, option).split('\n'): # out.write('%s: %s\n' % (attribute_name, option_section)) out.write('\n') # extra newline to denote the end of the entry if __name__ == '__main__': USAGE = """%s configfile [configfile2...] Each config file should be in the form used by ConfigParser or typical ini style config. Will attempt to produce LDAP schema for you and LDIF from your data. E.g. If your package is called BLAH, then try: %s -o 666.1 -n BLAH $(rpm -ql BLAH | egrep '\.conf$)""" % \ (os.path.basename(sys.argv[0]), os.path.basename(sys.argv[0])) parser = OptionParser(usage=USAGE) parser.add_option("-o", "--oid", dest="oid", default="1.3.6.1.4.1.1733", help="Base OID value to use when generating a sample LDAP schema") parser.add_option("-n", "--name", dest="name", default="x-com-example", help="Base NAME value used in labeling the new ObjectClasses") parser.add_option("-b", "--basedn", dest="basedn", default="dc=my-domain,dc=com", help="BaseDN used in anchoring values in the LDIF data") parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="Tell you what I'm doing or not") (options, args) = parser.parse_args() N = 0 schemafile = '%s.schema' % os.path.join(os.path.dirname(sys.argv[0]), options.name) fh = open(schemafile, 'w') for conf in args: N += 1 if options.verbose: print 'Compiling %s data to build schema file %s' % (conf, schemafile) genschema("%s.%d" % (options.oid, N), conf, options.name, fh) fh.close() ldiffile = '%s.ldif' % os.path.join(os.path.dirname(sys.argv[0]), options.name) fh = open(ldiffile, 'w') for conf in args: if options.verbose: print 'Compiling %s data to build ldif file %s' % (conf, ldiffile) genldif(conf, options.name, options.basedn, fh) fh.close()