Deleting Driver Associations in Identity Manager

0 Likes

Problem



A Forum reader recently asked:



"I'm looking for a better way to remove an IDM driver from a large eDirectory tree. The user count is approx 150,000.



Deleting a driver using iManager loads up the change cache on each server to nearly 150,000 (deleted user associations), and it takes about 6 hours for the four servers to process out the change and recover. So I'm trying to find another possible method of removing a driver, where the tree wouldn't take as big of a hit. I was thinking that manually removing each user association using LDIF might ease the pain."



And here's the response from Yancey Yeargan ...



Solution



I have the same situation, with over 450,000 accounts, so I know exactly how you feel about deleting a driver ...



I wrote a PERL script that logs into eDirectory, searches for any account with the DirXML-Associations attribute set, iterates through the attribute values looking for associations that belong to a particular driver, and removes them. You can insert or tune the sleep statements so that it can process the accounts as fast or slow as you need.



I run the script from a Linux system, but you could use Windows or MacOS too - anything with PERL. I also use the "screen" program so that I can start the script, detach from the "screen", leave it over night and come back to check on it later (with screen -r).



I usually execute the script as "perl scriptname.pl | tee assoc.log" or something simliar so that I can log everything and watch the progress. Of course, I could do "perl script.pl > assoc.log" and use "tail -f assoc.log" to watch it.



This PERL script also generates an LDIF file with all the changes it makes to your directory. This is great as a log, because you get to see exactly what changed. But you could quickly modify the script so that it only generates the LDIF file, which you could then import with ICE or other LDAP tools (like ldapmodify from the OpenLDAP tools).



This particular version uses two nested loops to break up the accounts into smaller sets. The first set begins with "aa*", then "ab*", and so on until it gets to "az*", then "ba*", "bb*", ... , "zx*", "zy*", and "zz*". This means you'll have over 600 searches, but it will process far fewer accounts with each search (rather than pulling 150,000 users with a single search).



Script



#!/usr/bin/perl

use Net::LDAP;
use Net::LDAP::LDIF;
use Net::LDAP::Entry;
use Time::HiRes qw(sleep);

# Do not buffer output - useful for watching with the "tee" command
$|=1;

##
## LDAP connection parameters
##
$ldaphost = 'ldaps://ldap1.company.com:636';
$ldapuser = 'cn=admin,o=company';
$ldappass = 'AdminPassword';
$ldapbase = "ou=people,o=company";

##
## This is a string containing the _FULL_ DN of the
## Identity Manager driver that we want to remove from
## the directory. This will be compared to values of
## the DirXML-Associations attribute. Any value which
## starts with this will be removed from the entries
## in which it is found.
##
$targeted_DirXML_driver = "cn=DriverName,cn=DirXML,o=company";


##
## Subroutine to generate a time stamp
##
sub TimeStamp {
my ($TS, $Second, $Minute, $Hour, $Day, $Month, $Year, $WeekDay,
$DayOfYear, $IsDST);
($Second, $Minute, $Hour, $Day, $Month, $Year, $WeekDay, $DayOfYear,
$IsDST) = localtime(time) ;
$TS = sprintf("d-d-d d:d:d", $Month 1, $Day,
$Year 1900, $Hour, $Minute, $Second);
return $TS;
}

##
## Indicate when the script starts
##
print "\n\n--START-- " , TimeStamp() , "\n" ;




################################################################################
##
## Open connection to LDAP server and log into that server.
##
################################################################################

#LDAP Connect to server
$idldap = Net::LDAP->new($ldaphost);
die "Cannot connect to LDAP" unless $idldap;

# LDAP Login
$msg = $idldap->bind($ldapuser, password=>$ldappass);
$msg->code && die $msg->error;





################################################################################
##
## Create a unique name for an LDIF-formatted "log" of LDAP changes.
##
################################################################################

($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime;
$year = 1900;
$mon ;
$today = sprintf("ddd", $year,$mon,$mday);
$logprefix =
sprintf("assoc-ddd-dd",$year,$mon,$mday,$hour,$min);
$logsuffix = ".ldif";
$i = 1;
do {
$logfile = "$logprefix-$i$logsuffix";
print "Logfile: $logfile\n" if ($debugging>2);
$i ;
} while (-f $logfile);
$LOG = Net::LDAP::LDIF->new($logfile, 'w', change=>1);
print "\n\nLDIF file used for this run: " , $logfile , "\n";


################################################################################
##
## Main Routine
##
################################################################################

foreach my $i ( 'a' .. 'z' )
{

foreach my $j ( 'a' .. 'z' )
{

sleep 1.0;

my $filter = "(&(cn=" . $i . $j . "*)(DirXML-Associations=*))";

print "\nSearching for [$filter]\n";

$msg = $idldap->search(
base => $ldapbase ,
filter => $filter ,
attrs => ['DirXML-Associations'] );
$msg->code && die $msg->error;

print "There are " , $msg->count , " entries\n";

my $entry;

foreach $entry ( $msg->sorted )
{

#print $entry->dn , "\n";

foreach $value ( $entry->get_value('DirXML-Associations') )
{

if ( $value =~ /$targeted_DirXML_driver/i )
{

print $entry->dn , "\n";
$entry->delete( 'DirXML-Associations' => [$value] );
$LOG->write_entry($entry); #Write to LDIF log
$msg = $entry->update($idldap);
$msg->code && die $msg->error;
sleep 0.5;

}#if


}#foreach value

}#foreach entry

}#foreach j

}#foreach i




##
## Indicate when the script ends
##
FINISH: print "\n\n--END-- " , TimeStamp() , "\n\n\n" ;


##
## END OF FILE
##

Labels:

How To-Best Practice
Comment List
Related
Recommended