I am working on the db dumper/ ldap importer and I can't seem to figure a couple of things out with the python ldif libraries. I am working on getting the info out to an LDIF file. I think this is accomplished by putting the data into a dictionary (line 200) and making a call to LDIFWriter (line 204). I was hoping that all I had to do was pass the dictionary to the unparse function, but that's not working right. When I call the unparse function I get output like the following: dn: dc=fedoraproject,dc=org cn=Tom Lynema telephoneNumber: N telephoneNumber: o telephoneNumber: n telephoneNumber: e It's always one character per line for some reason. If anyone has insight as to how I'm supposed to do this please fill me in. Since LDIF is fairly easy, I may just end up writing my own functions to write a dictionary object to LDIF. If there's a better place to ask, let me know. Thanks, ~tom
#!/usr/bin/env python """ PgToLDAP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. PgToLDAP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with PgToLDAP; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Id: $Id$ """ import sys, time import ldap, ldif, pgdb, ldap.modlist from optparse import OptionParser version = "0.11" def parseArgs(): parser = OptionParser(version="%prog " + version) parser.add_option ("-v", "--verbose", dest="verbose", action="store_true", default=False, help="Verbose output") parser.add_option ("--pgUser", dest="pgUser", default="postgres", help="PostgreSQL User [default: %default]", metavar="USER") parser.add_option ("--pgPassword", dest="pgPassword", help="PostgreSQL Password", metavar="PASSWORD") parser.add_option ("--pgHost", dest="pgHost", default="localhost", help="PostgreSQL Host [default: %default]", metavar="HOST") parser.add_option ("--pgPort", dest="pgPort", default="5432", help="PostgreSQL Port [default: %default]", metavar="PORT") parser.add_option ("--pgDb", dest="pgDB", help="PostgreSQL Database", metavar="DATABASE") parser.add_option ("-o", "--output", dest="outType", default="file", help="Output Type [file|ldap] [default: %default]") parser.add_option ("-f", "--file", dest="outFile", default="out.ldif", help="Output file [default: %default]", metavar="FILE") parser.add_option ("--ldapUser", dest="ldapUser", default="cn=Directory Manager", help="LDAP User [default: %default]", metavar="USER") parser.add_option ("--ldapPassword", dest="ldapPassword", help="LDAP Password", metavar="PASSWORD") parser.add_option ("--ldapHost", dest="ldapHost", default="localhost", help="LDAP Host [default: %default]", metavar="HOST") parser.add_option ("--ldapPort", dest="ldapPort", default="389", help="LDAP Port [default: %default]", metavar="PORT") parser.add_option ("--ldapOU", dest="ldapBaseOU", default="dc=fedoraproject, dc=org", help="LDAP Base OU [default: %default]", ) (options, args) = parser.parse_args() if options.outType != "file" and options.outType != "ldap": parser.error("Output type must be file or ldap") return (options, args) def connPostgres(user, password, db, host, port): """Tries to connect to the Postgres db server. Will exit with exit code 1 it it fails.""" global verbose if verbose: print "Connecting to postgres://%s@%s:%s" % (user, host, port) try: dbConn = pgdb.connect(user=user, password=password, database=db, host='%s:%s' %(host, port)) return dbConn except: print "Error connecting to Postgres server" # TODO: Remove exit comment sys.exit(1) def connLDAP(user, password, host, port): """Tries to bind to the LDAP server. Will exit with exit code 1 it it fails.""" global verbose if verbose: print "Connecting to ldap://%s@%s:%s" % (user, host, port) try: ldapConn = ldap.open(host) ldapConn.protocol_version = ldap.VERSION3 ldapConn.simple_bind_s(user, password) return ldapConn except ldap.LDAPError, error_message: print 'Error connecting to LDAP Server' print error_message sys.exit(1) def openLdifFile(filename): """Tries to open the output file for writing. Will exit with exit code 1 it it fails.""" global verbose if verbose: print "Opening output file %s" % filename try: #ldifWriter = ldif.LDIFWriter(ldap.initialize('ldap://localhost:1390'),filename) fileHandel = open (filename,'w') ldifWriter = ldif.LDIFWriter(fileHandel,None,80) return ldifWriter except ldap.LDAPError, error_message: print "Error opening output file: %s" % (filename) print error_message sys.exit(1) def cleanLDAP(ldapConn, ldapBaseOU): """Removes all existing entries under ou=People and ou=Groups for the defined base OU. Will exit with exit code 1 if an LDAP error is encountered.""" global verbose if verbose: print "Deleting existing users from LDAP" try: timeout = 0 result_id = ldapConn.search("ou=People, " + ldapBaseOU, ldap.SCOPE_ONELEVEL, "cn=*", None) while 1: result_type, result_data = ldapConn.result(result_id, timeout) if (result_data == []): break else: if result_type == ldap.RES_SEARCH_ENTRY: if verbose: print "Deleting LDAP user: " + result_data[0][1]['cn'][0] ldapConn.delete_s(result_data[0][0]) except ldap.LDAPError, error_message: print "Error deleting existing users from LDAP" print error_message sys.exit(1) if verbose: print "Deleting existing groups from LDAP" try: timeout = 0 result_id = ldapConn.search("ou=Groups, " + ldapBaseOU, ldap.SCOPE_ONELEVEL, "cn=*", None) while 1: result_type, result_data = ldapConn.result(result_id, timeout) if (result_data == []): break else: if result_type == ldap.RES_SEARCH_ENTRY: if verbose: print "Deleting LDAP group: " + result_data[0][1]['cn'][0] ldapConn.delete_s(result_data[0][0]) except ldap.LDAPError, error_message: print "Error deleting existing groups from LDAP" print error_message sys.exit(1) def main(): global verbose (options, cruft) = parseArgs() verbose = options.verbose dbConn = connPostgres(options.pgUser, options.pgPassword, options.pgDB, options.pgHost, options.pgPort) # Cleanup LDAP (if necessary) if options.outType == "ldap": ldapConn = connLDAP(options.ldapUser, options.ldapPassword, options.ldapHost, options.ldapPort) #cleanLDAP(ldapConn, options.ldapBaseOU) else: ldifWriter = openLdifFile(options.outFile) # Copy all users from db to ldap/ldif try: if verbose: print "Selecting all users from Postgres Database" userCursor = dbConn.cursor() userCursor.execute ("SELECT * FROM person") #id, username, email, human_name, gpg_keyid, ssh_key, password, comments, postal_address, telephone, facsimile, affiliation, creation, approval_status, internal_comments, wiki_prefs, ircnick except: print "Error selecting users from db" raise sys.exit(1) while 1: user = userCursor.fetchone() if user == None: break # TODO: Create method createLdapUserEntry(user) #(dn, entry) = createLdapUserEntry(user) if options.outType == "ldif": ldifWriter.unparse(dn, entry) else: print "Adding ldif info for " + user[3] + "." userLdif = {"objectClass" : "fedoraPerson" , "displayName": user[1] , "mail": user[2] , "givenName" : user[3] , "userCertificate" : user[4] , "userPassword" : user[6] , "o":"fedoraproject" , "postalAddress" : user[8] , "telephoneNumber" : user[9] , "fax" : user [10]} for userKey in userLdif.keys(): print "Key Name -> " + userKey print "Key Value -> " + str(userLdif[userKey]) ldifWriter.unparse("dc=fedoraproject,dc=org cn=" + user[3] , { userKey : str(userLdif[userKey]) } ) #print userLdif.keys() #print userLdif.values() #ldifWriter.unparse("dc=fedoraproject,dc=org cn=" + user[3] , userLdif ) time.sleep (2) #ldapConn.add_s(dn, entry) userCursor.close() # Select all groups from the DB try: if verbose: print "Selecting all groups from Postgres Database" groupCursor = dbConn.cursor() groupCursor.execute ("SELECT * FROM project_group") #id, name, owner_id, group_type, needs_sponsor, user_can_remove, prerequisite_id, joinmsg except: print "Error selecting groups from db" raise sys.exit(1) while 1: group = groupCursor.fetchone() if group == None: break # TODO: Create method createLdapGroupEntry(group) #(dn, entry) = createLdapGroupEntry(group) if options.outType == "ldif": ldifWriter.unparse(dn, entry) else: #ldapConn.add_s(dn, entry) print "Adding group info for " + group[1] + "." userCursor.close() # Select all roles from the DB try: if verbose: print "Selecting all roles from Postgres Database" roleCursor = dbConn.cursor() roleCursor.execute ("SELECT * FROM role") #person_id, project_group_id, role_type, role_domain, role_status, internal_comments, sponsor_id (Points to a person), creation (TIMESTAMP), approval (TIMESTAMP) except: print "Error selecting roles from db" raise sys.exit(1) while 1: role = roleCursor.fetchone() if role == None: break # TODO: Create method createLdapRoleEntry(group) #(dn, entry) = createLdapGroupRole(group) if options.outType == "ldif": ldifWriter.unparse(dn, entry) else: #ldapConn.add_s(dn, entry) print "Adding role info for " + role[4] + "for user" + str(role[1]) + "." userCursor.close() sys.exit(1) if __name__ == "__main__": main()