Selaa lähdekoodia

Bug 703990 - Support upgrade from Red Hat Directory Server

https://bugzilla.redhat.com/show_bug.cgi?id=703990
Resolves: bug 703990
Bug Description: Support upgrade from Red Hat Directory Server
Reviewed by: nkinder (Thanks!)
Branch: master
Fix Description: added 50fixNsState.pl - if upgrading from a machine of
a different arch, we need to fix the nsState attribute value used by the
uniqueid generator and the CSN generator.  If upgrading from a 32-bit to
a 64-bit, we cannot update the uniqueid generator due to a bug in the
generator code, so we just delete the entry and let the server
recreate it.
Platforms tested: RHEL6 x86_64 (from RHEL 5 32-bit and 64-bit)
Flag Day: no
Doc impact: yes
Rich Megginson 14 vuotta sitten
vanhempi
sitoutus
c4d9f45af8
4 muutettua tiedostoa jossa 179 lisäystä ja 0 poistoa
  1. 1 0
      Makefile.am
  2. 1 0
      Makefile.in
  3. 176 0
      ldap/admin/src/scripts/50fixNsState.pl
  4. 1 0
      ldap/admin/src/scripts/setup-ds.res.in

+ 1 - 0
Makefile.am

@@ -461,6 +461,7 @@ update_DATA = ldap/admin/src/scripts/exampleupdate.pl \
 	ldap/admin/src/scripts/50faxnumbersyntaxplugin.ldif \
 	ldap/admin/src/scripts/50teletexterminalidsyntaxplugin.ldif \
 	ldap/admin/src/scripts/50faxsyntaxplugin.ldif \
+	ldap/admin/src/scripts/50fixNsState.pl \
 	ldap/admin/src/scripts/50telexnumbersyntaxplugin.ldif \
 	ldap/admin/src/scripts/50guidesyntaxplugin.ldif \
 	ldap/ldif/50replication-plugins.ldif \

+ 1 - 0
Makefile.in

@@ -1650,6 +1650,7 @@ update_DATA = ldap/admin/src/scripts/exampleupdate.pl \
 	ldap/admin/src/scripts/50faxnumbersyntaxplugin.ldif \
 	ldap/admin/src/scripts/50teletexterminalidsyntaxplugin.ldif \
 	ldap/admin/src/scripts/50faxsyntaxplugin.ldif \
+	ldap/admin/src/scripts/50fixNsState.pl \
 	ldap/admin/src/scripts/50telexnumbersyntaxplugin.ldif \
 	ldap/admin/src/scripts/50guidesyntaxplugin.ldif \
 	ldap/ldif/50replication-plugins.ldif \

+ 176 - 0
ldap/admin/src/scripts/50fixNsState.pl

@@ -0,0 +1,176 @@
+use Mozilla::LDAP::Conn;
+use Mozilla::LDAP::Entry;
+use Mozilla::LDAP::Utils qw(normalizeDN);
+use Mozilla::LDAP::API qw(:constant ldap_url_parse ldap_explode_dn);
+use DSUtil qw(debug);
+use Config;
+
+# # Determine the endianness of your system
+my $packfmt32 = "QA6SCx3"; # must be 20 bytes
+my $packfmt64 = "QA6SCx7"; # must be 24 bytes
+
+my $is_big_endian = unpack('xc', pack('s', 1));
+# see if we are on an LP64 system
+my $is64 = ($Config{longsize} == 8);
+
+sub convert_uniqueid {
+    my $ent = shift;
+    my $val = shift;
+
+    if (!$ent || !$val) {
+        return (0, 0);
+    }
+
+    my $hex = unpack('H*', $val);
+    #print "hex=$hex\n";
+
+    my $fmt32 = "QA6SC";
+    my $fmt64 = "QA6SC";
+    my $fmt = $fmt32;
+    if (length($val) > 20) {
+        $fmt = $fmt64;
+    } elsif ($is64) {
+        # cannot convert 32-bit to 64-bit - just delete the entry and continue
+        debug(1, "Cannot convert 32-bit nsState value $hex to 64-bit - deleting entry " .
+              $ent->getDN() . " and continuing\n");
+        return (-1, 0);
+    }
+    if ($is_big_endian) {
+        $packfmt32 = "(QA6SCx3)>";
+        $packfmt64 = "(QA6SCx7)>";
+    }
+
+    my $packfmt = $packfmt32;
+    if ($is64) {
+        $packfmt = $packfmt64;
+    }
+    
+    my ($ts, $node, $clockseq, $last_update) = unpack($fmt, $val);
+    # if we think it is from bigendian, do 
+    # $bigfmt = "(" . $fmt . ")>";
+    my $tssecs = ($ts - 0x01B21DD213814000) / 10000000;
+    my $curts = time;
+    my $tsdiff = abs($curts - $tssecs);
+    my $maxdiff = 86400*365*10; # 10 years
+    if (($tsdiff > $maxdiff) || (($last_update != 0) && ($last_update != 1))) {
+        # try big endian
+        ($ts, $node, $clockseq, $last_update) = unpack("($fmt)>", $val);
+        $tssecs = ($ts - 0x01B21DD213814000) / 10000000;
+        $tsdiff = abs($curts - $tssecs);
+        if (($tsdiff > $maxdiff) || (($last_update != 0) && ($last_update != 1))) {
+            debug(0, "Error: could not parse nsstate $hex - tsdiff is $tsdiff seconds or ", ($tsdiff/86400), " days\n");
+            return (0, 0, 'error_could_not_parse_nsstate', $ent->getDN(), $hex);
+        }
+    }
+
+    # format for the target system
+    my $newval = pack($packfmt, $ts, $node, $clockseq, $last_update);
+    my $rc = 0;
+    if ($val != $newval) { # changed
+        my $hex2 = unpack('H*', $newval);
+        debug(1, "Converted old nsState val in ", $ent->getDN(), " from $hex to $hex2\n");
+        $rc = 1; # changed
+    }
+    return ($rc, $newval);
+}
+
+sub convert_replica {
+    my $ent = shift;
+    my $val = shift;
+
+    if (!$ent || !$val) {
+        return (0, 0);
+    }
+
+    my $len = length($val);
+    my $pad;
+    my $timefmt;
+    if ($len <= 20) {
+        $pad = 2; # padding for short H values
+        $timefmt = 'I'; # timevals are unsigned 32-bit int
+    } else {
+        $pad = 6; # padding for short H values
+        $timefmt = 'Q'; # timevals are unsigned 64-bit int
+    }
+    # short - padbytes - 3 timevals - short - padbytes
+    my $fmtstr = "Sx" . $pad . $timefmt . "3Sx" . $pad;
+    my ($rid, $sampled_time, $local_offset, $remote_offset, $seq_num) = unpack($fmtstr, $val);
+    my $hex = unpack('H*', $val);
+    my $now = time;
+    my $tdiff = abs($now - $sampled_time);
+    my $maxdiff = 86400*365*10; # 10 years
+    if ($tdiff > $maxdiff) { # try big endian
+        ($rid, $sampled_time, $local_offset, $remote_offset, $seq_num) = unpack("($fmtstr)>", $val);
+        my $tdiff = abs($now - $sampled_time);
+        if ($tdiff > $maxdiff) { # error
+            debug(0, "Error: could not parse nsstate $hex - tdiff is $tdiff seconds or", ($tdiff/86400), " days\n");
+            return (0, 0, 'error_could_not_parse_nsstate', $ent->getDN(), $hex);
+        }
+    }
+    # format for the target system
+    if ($is_big_endian) {
+        $fmtstr = "($fmtstr)>";
+    }
+    my $newval = pack($fmtstr, $rid, $sampled_time, $local_offset, $remote_offset, $seq_num);
+    my $rc = 0;
+    if ($val != $newval) { # changed
+        my $hex2 = unpack('H*', $newval);
+        debug(1, "Converted old nsState val in ", $ent->getDN(), " from $hex to $hex2\n");
+        $rc = 1; # changed
+    }
+    return ($rc, $newval);
+}
+
+sub runinst {
+    my ($inf, $inst, $dseldif, $conn) = @_;
+
+    my $ent = $conn->search("cn=config", "sub", "(cn=uniqueid generator)");
+    if ($ent) {
+        my ($rc, $newval, @errs) = convert_uniqueid($ent, $ent->getValues('nsState'));
+        if (@errs) {
+            return @errs;
+        }
+        if ($rc) { # changed
+            if ($rc == -1) { # delete it
+                if (!$conn->delete($ent->getDN())) {
+                    return ("error_deleteall_entries", $ent->getDN(), $conn->getErrorString());
+                }
+            } else {
+                $ent->setValues('nsState', $newval);
+                if (!$conn->update($ent)) {
+                    return ("error_updating_entry", $ent->getDN(), $conn->getErrorString());
+                }
+            }
+        }
+    }
+
+    for ($ent = $conn->search("cn=config", "sub", "(cn=replica)");
+        $ent; $ent = $conn->nextEntry) {
+        my ($rc, $newval, @errs) = convert_replica($ent, $ent->getValues('nsState'));
+        if (@errs) {
+            return @errs;
+        }
+        if ($rc) { # changed
+            $ent->setValues('nsState', $newval);
+            if (!$conn->update($ent)) {
+                return ("error_updating_entry", $ent->getDN(), $conn->getErrorString());
+            }
+        }
+    }
+
+    return ();
+}
+
+sub testit {
+#my $val = 'ACm2BdIdsgH+tw/8AAB+swEAAAA=';
+#my $val = 'AOj+tyuA4AHsNZ7S9NnxZwEAAAAAAAAA';
+my $testval = "00a43cb4d11db2018b7912fd0000a42e01000000";
+my $testdecval = $testval;
+# base16 decode
+$testdecval =~ s/(..)/chr(hex($1))/eg;
+my $ent = new Mozilla::LDAP::Entry;
+$ent->setDN("cn=uniqueid generator");
+my ($rc, $newval) = convert_uniqueid($ent, $testdecval);
+}
+
+1;

+ 1 - 0
ldap/admin/src/scripts/setup-ds.res.in

@@ -201,3 +201,4 @@ If you proceed with this hostname, you may encounter problems.\
 \
 Do you want to proceed with hostname '%s'?
 error_import_check_log = Error: unable to import file '%s' for backend '%s' - %s.  Check the errrors log for additional information\n
+error_could_not_parse_nsstate = Error: could not parse nsState from %s.  Value: %s\n