Generating a Backlinks LDIF from a Links Export



By: rkalfane

January 2, 2008 11:42 am

Reads: 220

Comments:0

Rating:0

Vim_LDIF_BackLinks_0.png

Here is a powerful Vim script to generate an LDIF backlinks export from a links export, such as to generate a user groupMemberships LDIF from a group members export. This has been useful during large first loads, when creating thousands of users with hundreds of groups and thousands of links and backlinks.

Script Installation

To install the script and use it in Vim,

1. Copy the file ldap_links.vim in your home folder, in a “.vim” folder.

2. Use the following code in your Vim init file in your home folder (“.vimrc” in Linux, “_vimrc” in Windows):

source $HOME/.vim/ldap_links.vim
map <F7>   :call LDIF:GenerateBackLinksAuto()<CR>
map <F8>   :call LDIF:GenerateBackLinks(input("Link name (eg. member): ",'member'),input("Backlink name(eg. groupMembership): ",'groupMembership'))<CR>

The second line maps the function to the F7 key, to auto-generate the backlinks export. The third line takes the input of the link name and the backlink name before calling the function, and maps it to the F8 key.

Script Execution

To execute the script, simply press F7. If it is a member, groupMembership, manager, directReports, securityEquals or equivalentToMe export, the backlinks LDIF will automatically be generated. Otherwise, it will ask for the link name and the backlink name. Pressing F8 will directly ask for the link name and the backlink name to use.

Here is a short example of transformation. Let’s take the following group members export:

 1 # LDIF export of groups
 2 version: 1
 3
 4 dn: cn=group2,ou=groups,ou=organizationalunit3,ou=organizationalunit2,ou=organ
 5  izationalunit1,o=organization
 6 changetype: modify
 7 modify: member
 8 member: cn=member1,ou=organizationalunit3,ou=organizationalunit2,ou=organizati
 9  onalunit1,o=organization
10 member: cn=member2,ou=organizationalunit3,ou=organizationalunit2,ou=organizati
11  onalunit1,o=organization
12
13 dn: cn=group1,ou=groups,ou=organizationalunit3,ou=organizationalunit2,ou=organ
14  izationalunit1,o=organization
15 changetype: modify
16 modify: member
17 member: cn=member4,ou=organizationalunit3,ou=organizationalunit2,ou=organizati
18  onalunit1,o=organization
19 member: cn=member1,ou=organizationalunit3,ou=organizationalunit2,ou=organizati
20  onalunit1,o=organization

Here is the result when pressing F7:

 1 # LDIF generated by Vim
 2 # "groupMembership" back links generated from "member" links
 3 # 3 entries with 4 total back links created
 4 version: 1
 5
 6 dn: cn=member1,ou=organizationalunit3,ou=organizationalunit2,ou=organizational
 7  unit1,o=organization
 8 changetype: modify
 9 add: groupMembership
10 groupMembership: cn=group1,ou=groups,ou=organizationalunit3,ou=organizationalu
11  nit2,ou=organizationalunit1,o=organization
12 groupMembership: cn=group2,ou=groups,ou=organizationalunit3,ou=organizationalu
13  nit2,ou=organizationalunit1,o=organization
14
15 dn: cn=member2,ou=organizationalunit3,ou=organizationalunit2,ou=organizational
16  unit1,o=organization
17 changetype: modify
18 add: groupMembership
19 groupMembership: cn=group2,ou=groups,ou=organizationalunit3,ou=organizationalu
20  nit2,ou=organizationalunit1,o=organization
21
22 dn: cn=member4,ou=organizationalunit3,ou=organizationalunit2,ou=organizational
23  unit1,o=organization
24 changetype: modify
25 add: groupMembership
26 groupMembership: cn=group1,ou=groups,ou=organizationalunit3,ou=organizationalu
27  nit2,ou=organizationalunit1,o=organization
28

Pressing F7 again will revert back to the previous state. You can also call the script using the following command:

:call LDIF:GenerateBackLinks("member","groupMembership")
or
:call LDIF:GenerateBackLinks("groupMembership","member")

The same will work with managers export:

 1 # LDIF generated by Vim
 2 version: 1
 3
 4 dn: cn=employee1,ou=organizationalunit3,ou=organizationalunit2,ou=organization
 5  alunit1,o=organization
 6 changetype: modify
 7 add: manager
 8 manager: cn=manager1,ou=managers,ou=organizationalunit3,ou=organizationalunit2
 9  ,ou=organizationalunit1,o=organization
10
11 dn: cn=employee2,ou=organizationalunit3,ou=organizationalunit2,ou=organization
12  alunit1,o=organization
13 changetype: modify
14 add: manager
15 manager: cn=manager1,ou=managers,ou=organizationalunit3,ou=organizationalunit2
16  ,ou=organizationalunit1,o=organization

Here is the result when pressing F7:

 1 # LDIF generated by Vim
 2 # "directReports" back links generated from "manager" links
 3 # 1 entries with 2 total back links created
 4 version: 1
 5
 6 dn: cn=manager1,ou=managers,ou=organizationalunit3,ou=organizationalunit2,ou=o
 7  rganizationalunit1,o=organization
 8 changetype: modify
 9 add: directReports
10 directReports: cn=employee1,ou=organizationalunit3,ou=organizationalunit2,ou=o
11  rganizationalunit1,o=organization
12 directReports: cn=employee2,ou=organizationalunit3,ou=organizationalunit2,ou=o
13  rganizationalunit1,o=organization

And for a custom links export:

 1 # LDIF generated by Vim
 2 version: 1
 3
 4 dn: cn=employee1,ou=organizationalunit3,ou=organizationalunit2,ou=organization
 5  alunit1,o=organization
 6 changetype: modify
 7 add: manager
 8 mySuperiorDn: cn=manager1,ou=managers,ou=organizationalunit3,ou=organizationalunit2
 9  ,ou=organizationalunit1,o=organization
10
11 dn: cn=employee2,ou=organizationalunit3,ou=organizationalunit2,ou=organization
12  alunit1,o=organization
13 changetype: modify
14 add: manager
15 mySuperiorDn: cn=manager1,ou=managers,ou=organizationalunit3,ou=organizationalunit2
16  ,ou=organizationalunit1,o=organization

Pressing F7 or F8 will ask for the link name and backlink name. In this example we use “mySuperiorDn” and “myEmployeesDn”:

 1 # LDIF generated by Vim
 2 # "myEmployeesDn" back links generated from "mySuperiorDn" links
 3 # 1 entries with 2 total back links created
 4 version: 1
 5
 6 dn: cn=manager1,ou=managers,ou=organizationalunit3,ou=organizationalunit2,ou=o
 7  rganizationalunit1,o=organization
 8 changetype: modify
 9 add: myEmployeesDn
10 myEmployeesDn: cn=employee1,ou=organizationalunit3,ou=organizationalunit2,ou=o
11  rganizationalunit1,o=organization
12 myEmployeesDn: cn=employee2,ou=organizationalunit3,ou=organizationalunit2,ou=o
13  rganizationalunit1,o=organization

Try the script on the different test exports attached. These are group members, equivalentToMe and managers exports that will be converted into user groupMemberships, securityEquals and directReports exports.

More about the Vim Script

There are two versions of the GenerateBackLinks function in the Vim script. One is an old one I created for version 6 and earlier of Vim; the other one is a new one for version 7 of Vim and higher. This is because Vim introduced new dictionary and list objects in Vim 7.

Old Script for Vim version 6 and Earlier

The old version of the function uses a few regular expressions. For instance, the following command simply deletes all lines in the export that do not contain “dn:” or the link attribute (such as “member:”).

:v/^dn:\|^member:/d

This one delete all empty dn entries:

:v/^dn:.*\n^member:\|^member:/d

This very powerful one sorts the links by block:

:g/^dn:/+1,/^$/-1!sort

Starting with Vim 7, there is a built-in sort function that can work as shown below (“!” was calling an external sort command):

:g/^dn:/+1,/^$/-1sort

New Script for Vim version 7 and Later

The new version of the script uses new Dictionary and List object types. The Dictionary type is like HashMap in Java, or the associative array in Php.

You can, for instance, create new lists in Vim using the following code:

:let mylist1 = [ "member1", "member2" ]
:let mylist2 = [ "member3", "member4" ]

You can then easily access lists content:

:echo mylist1[0]
member1
:echo mylist2[1]
member4

You can create a new group dictionary with the following:

:let mydic = { "group2": mylist2, "group1": mylist1 }

When such a structure is created, there are many Vim functions to manipulate it:

:echo mydic["group1"][0]
member1
:echo sort(keys(mydic))
['group1', 'group2']
:echo has_key(mydic,"group1")
1
:echo has_key(mydic,"group3")
0

The script builds a structure with all members and their groups from all the groups and their members. Then it’s pretty easy to cycle through it and build the final LDIF export.

Here is the most important part of the script. It cycles through all the lines, checks which is the current dn, and retrieves links values in the dictionary structure:

266         "Analyse LDIF content, links and dn are stored in a dictionary
267         let s:linksdic = {}
268         let s:currentdn = ''
269         let s:count = 1
270         let s:totaldn = 0
271         let s:totalbl = 0
272         while s:count < line('$')
273             let s:count = s:count + 1
274             let s:line = getline(s:count)
275             
276             "Check if current line contains a new dn
277             if matchstr(s:line,'^dn:.*') != ''
278                 let s:currentdn = substitute(s:line,'^dn: \(.*\)','\1','')
279
280             "Check if current line contains a new link
281             elseif matchstr(s:line,'^'.a:linkname.':.*') != ''
282
283                 "Get link dn
284                 let s:link = substitute(s:line,'^'.a:linkname.': \(.*\)','\1','')
285                 
286                 "Check if current link already exists in the dictionary
287                 "and add the current dn in the list entry if dn not in the list
288                 if has_key( s:linksdic, s:link )
289                     let s:backlinks = s:linksdic[s:link]
290                     if count( s:backlinks, s:currentdn ) == 0
291                         call add( s:backlinks, s:currentdn )
292                         let s:totalbl = s:totalbl + 1
293                     endif
294                 else
295                     "Create a new list entry with current dn if key does not exist
296                     let s:backlinks = [s:currentdn]
297                     let s:linksdic[s:link] = s:backlinks
298                     let s:totaldn = s:totaldn + 1
299                     let s:totalbl = s:totalbl + 1
300                 endif
301             endif
302         endwhile

You can also have a look at the source code to see how the dictionary “s:linksdic” is used. Using the same technique, you can easily get a virtual representation of any LDIF objects and manipulate them (convert to CSV, XML, filter, run stats, merge LDIF contents, etc.). Have fun!

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)

Tags: ,
Categories: Identity Manager, Technical Solutions

Disclaimer: As with everything else at NetIQ Cool Solutions, this content is definitely not supported by NetIQ, so Customer Support will not be able to help you if it has any adverse effect on your environment.  It just worked for at least one person, and perhaps it will be useful for you too.  Be sure to test in a non-production environment.

Comment