#!perl # # BEGIN COPYRIGHT BLOCK # Copyright 2001 Sun Microsystems, Inc. # Portions copyright 1999, 2001-2003 Netscape Communications Corporation. # All rights reserved. # END COPYRIGHT BLOCK # # Migrate a SuiteSpot 2.X or 3.X localdb to a 4.0 directory server BEGIN { $isNT = -d '\\'; $PATHSEP = $isNT ? "\\" : "/"; @INC = ( '.', '../../../admin/admin/bin' ); grep { s@/@\\@g } @INC if $isNT; $script_suffix = $isNT ? ".bat" : ""; $exe_suffix = $isNT ? ".exe" : ""; # NT needs quotes around some things unix doesn't $quote = $isNT ? "\"" : ""; } sub getNextEntry { my $fh = shift; my @entry = (); # an array of strings, each string is 1 attr/value pair my $line = ""; while (($line = <$fh>) && !($line =~ /^$/)) { # entry is terminated by EOF or empty line34 chop $line; if ($line =~ /^\s/) { # line begins with a single space char $entry[@entry-1] .= $'; # add continuation to line } else { push @entry, $line; } } return @entry; } # given a string of the form string:value, return everything to the left of the : sub getAttrName { my $s = shift; $s =~ s/[:].*$//; return $s; } sub printEntry { my $fh = shift; foreach (@_) { print $fh $_, "\n"; } print $fh "\n"; } sub usage { print 'Usage: perl migrateLocalDb []', "\n"; print "\t", ' - full path to the userdb directory to migrate', "\n"; print "\t", ' e.g. /usr/netscape/suitespot3/userdb', "\n"; print "\t", ' - new suffix e.g. dc=example,dc=com; may be empty', "\n"; print "\t", ' - full path to the destination instance', "\n"; print "\t", ' e.g. /usr/netscape/server4/slapd-foo', "\n"; print "The new instance is optional. If not given, the local db will\n"; print "be converted to the LDIF file userdb/localdb.ldif, but\n"; print "it will not be added to the database of the new instance.\n"; } sub sigDieHandler { print @_, "\n"; print "\n"; &usage(); print "\n"; print "NMC_STATUS: ", 0+$!, "\n"; exit $!; } $SIG{__DIE__} = 'sigDieHandler'; # check for command line arguments if (@ARGV > 0) { $localDBPath = $ARGV[0]; $newSuffix = $ARGV[1]; $instanceDir = $ARGV[2]; $bindDN = $ARGV[3]; $bindPwd = $ARGV[4]; # the perl executable should be in server root/install/ $relPath = '/install/'; $relPath =~ s#/#\\#g if ($isNT); ($sroot = $) =~ s#$relPath.*$##; } elsif ($ENV{'REQUEST_METHOD'}) { $| = 1; # print CGI header print "Content-type: text/plain\n\n"; # process the CGI input use Cgi; # get the server root directory $sroot = $ENV{'NETSITE_ROOT'}; $localDBPath = $cgiVars{'localDBPath'}; $newSuffix = $cgiVars{'newSuffix'}; $instanceDir = $cgiVars{'instanceDir'}; $bindDN = $cgiVars{'bindDN'}; $bindPwd = $cgiVars{'bindPwd'}; } else { die ""; } # this is a table of attributes which have DN syntax %dnAttrs = ( 'aliasedobjectname', "\n", 'member', "\n", 'owner', "\n", 'roleoccupant', "\n", 'seealso', "\n", 'dn', "\n", 'uniquemember', "\n", 'creatorsname', "\n", 'modifiersname', "\n", 'manager', "\n", 'documentauthor', "\n", 'secretary', "\n", 'associatedname', "\n", 'ditredirect', "\n", 'targetdn', "\n", 'newrdn', "\n", 'newsuperior', "\n", 'lastmodifiedby', "\n", 'replicaroot', "\n", 'replicabinddn', "\n", 'cirreplicaroot', "\n", 'cirbinddn', "\n", 'vlvbase', "\n", 'netscapemdsuffix', "\n", 'changelog', "\n", 'obsoletedbydocument', "\n", 'obsoletesdocument', "\n", 'reciprocalnaminglink', "\n", 'updatedbydocument', "\n", 'updatesdocument', "\n" ); print "Begin local db migration\n"; # see if the parameters are valid # check localdb path die "Error: could not find the local db $localDBPath" if (! -d $localDBPath); # check suffix? # get the old server root directory # step 1: convert the local db to an ldif file # lookup the old suffix from the lcache.conf $lcache = $localDBPath . $PATHSEP . 'ldap' . $PATHSEP . 'config' . $PATHSEP . 'lcache.conf'; open(LCACHE, "$lcache") or die "Error: could not open config file $lcache"; while () { chop; if (/^suffix\s+/i) { $oldSuffix = $'; $oldSuffix =~ s/^[\"]//; # trim leading " $oldSuffix =~ s/[\"]$//; # trim trailing " print "The old suffix is $oldSuffix\n"; } } close(LCACHE); print "Converting the local db to LDIF . . .\n"; # run the ldapsearch -C command $cmddir = $localDBPath . $PATHSEP . 'ldap' . $PATHSEP . 'tools'; @cmd = ($quote . $cmddir . $PATHSEP . 'ldapsearch' . $quote, '-C', "${quote}$lcache${quote}", '-s', 'sub', '-b', "\"$oldSuffix\"", '"objectclass=*"'); chdir($cmddir) or die "Error: could not change to directory $cmddir"; open(READCMD, "${quote}@cmd${quote}|") or die "Error: could not execute @cmd"; if ($instanceDir) { $outputFile = $instanceDir . $PATHSEP . 'ldif' . $PATHSEP . 'localdb.ldif'; } else { $outputFile = $localDBPath . $PATHSEP . 'localdb.ldif'; } open(OUT, ">$outputFile") or die "Error: could not write file $outputFile"; while (@entry = getNextEntry(\*READCMD)) { # for each entry, replace the old suffix with the new one; if there # was no old suffix, just append the new one to the DN value attrs if ($newSuffix && $newSuffix ne '""') { if ($oldSuffix && $oldSuffix ne '""') { grep { s/$oldSuffix/$newSuffix/ig } @entry; } else { for ($ii = 0; $ii < @entry; ++$ii) { $name = &getAttrName($entry[$ii]); if ($dnAttrs{lc($name)}) { $entry[$ii] .= ", $newSuffix"; } } } } printEntry(\*OUT, @entry); } close(READCMD); close(OUT); if ($? != 0) { die "Error: could not read local db from $localDBPath"; } elsif (! -s $outputFile) { die "Error: converted local db is empty"; } # check instance dir if ($instanceDir) { if (! -d $instanceDir) { # use may have given relative path $instanceDir = $sroot . $PATHSEP . $instanceDir; die "Error: could not find the instance dir $instanceDir in server root $sroot" if (! -d $instanceDir); } # step 2: load the converted LDIF file into the target directory server # if the bindDN and password were given, attempt to use ldif2ldap, otherwise, # shutdown the server and use ldif2db if ($bindDN && $bindPwd) { } else { print "Shutting down the server . . .\n"; # shutdown the server $stopCmd = $quote . $instanceDir . $PATHSEP . 'stop-slapd' . $script_suffix . $quote; system($stopCmd); print "Warning: could not shutdown the server in $instanceDir.\nThe server may already be down." if ($? != 0); sleep(10); # give the server time to shutdown # add the new suffix to the slapd.ldbm.conf if ($newSuffix && $newSuffix ne '""') { print "Adding suffix $newSuffix . . .\n"; $slc = $instanceDir . $PATHSEP . 'config' . $PATHSEP . 'slapd.ldbm.conf'; open(SLC, ">>$slc") or print "Warning: could not add the suffix $newSuffix: import may fail.\n"; print SLC "suffix\t\"$newSuffix\"\n"; close(SLC); } print "Importing the local db LDIF file . . .\n"; # import the LDIF file @impCmd = ($quote . $instanceDir . $PATHSEP . 'ldif2db' . $quote, '-C', '-i', "${quote}$outputFile${quote}"); system(@impCmd); die "Error: could not import LDIF file $outputFile" if ($? != 0); print "Restarting the server . . .\n"; # start the server $startCmd = $quote . $instanceDir . $PATHSEP . 'start-slapd' . $script_suffix . $quote; system($startCmd); print "Warning: could not restart the server in $instanceDir" if ($? != 0); } print "Finished. The local db has been imported to $instanceDir.\n"; } else { print "Finished. The local db has been written to $outputFile.\n"; } if (%cgiVars) { print "NMC_STATUS: 0\n"; } exit 0;