lib/ext

Jeroen van Meeuwen vanmeeuwen at kolabsys.com
Wed Jul 10 14:39:41 CEST 2013


 lib/ext/Net/LDAP3.php |  211 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 209 insertions(+), 2 deletions(-)

New commits:
commit 5b572df9f4033d132dcb3916e97789948afd8cb2
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Wed Jul 10 13:39:16 2013 +0100

    Merge new version of Net_LDAP3

diff --git a/lib/ext/Net/LDAP3.php b/lib/ext/Net/LDAP3.php
index 8a70145..8b46d85 100644
--- a/lib/ext/Net/LDAP3.php
+++ b/lib/ext/Net/LDAP3.php
@@ -151,7 +151,7 @@ class Net_LDAP3
      */
     public function add_entries($entries, $attributes = array())
     {
-        // If $entries is an associative array, it's keys are DNs and it's
+        // If $entries is an associative array, it's keys are DNs and its
         // values are the attributes for that DN.
         //
         // If $entries is a non-associative array, the attributes are expected
@@ -231,6 +231,148 @@ class Net_LDAP3
         return true;
     }
 
+    /**
+     * Add replication agreements and initialize the consumer(s) for
+     * $domain_root_dn.
+     *
+     * Searches the configured replicas for any of the current domain/config
+     * databases, and uses this information to configure the additional
+     * replication for the (new) domain database (at $domain_root_dn).
+     *
+     * Very specific to Netscape-based directory servers, and currently also
+     * very specific to multi-master replication.
+     */
+    public function add_replication_agreements($domain_root_dn)
+    {
+        $replica_hosts = $this->list_replicas();
+
+        if (empty($replica_hosts)) {
+            return;
+        }
+
+        $result = $this->search($this->config_get('config_root_dn'), "(&(objectclass=nsDS5Replica)(nsDS5ReplicaType=3))", "sub");
+
+        if (!$result) {
+            $this->_debug("No replication configuration found.");
+            return;
+        }
+
+        // Preserve the number of replicated databases we have, because the replication ID
+        // can be calculated from the number of databases replicated, and the number of
+        // servers.
+        $num_replica_dbs = $result->count();
+
+        $replicas = $result->entries(TRUE);
+
+        $max_replica_agreements = 0;
+
+        foreach ($replicas as $replica_dn => $replica_attrs) {
+            $result = $this->search($replica_dn, "(objectclass=nsDS5ReplicationAgreement)", "sub");
+            if ($result) {
+                if ($max_replica_agreements < $result->count()) {
+                    $max_replica_agreements = $result->count();
+                    $max_replica_agreements_dn = $replica_dn;
+                }
+            }
+        }
+
+        $max_repl_id = ($num_replica_dbs * count($replica_hosts));
+
+        $this->_debug("The current maximum replication ID is $max_repl_id");
+        $this->_debug("The current maximum number of replication agreements for any database is $max_replica_agreements (for $max_replica_agreements_dn)");
+
+        $this->_debug("With " . count($replica_hosts) . " replicas, the next is " . ($max_repl_id + 1) . " and the last one is " . ($max_repl_id + count($replica_hosts)));
+
+        // Then add the replication agreements
+        foreach ($replica_hosts as $num => $replica_host) {
+            $ldap = new Net_LDAP3($this->config);
+            $ldap->config_set('host', $replica_host);
+            $ldap->config_set('hosts', array($replica_host));
+            $ldap->connect();
+            $ldap->bind($this->config_get('bind_dn'), $this->config_get('bind_pw'));
+
+            $replica_attrs = Array(
+                    'cn' => 'replica',
+                    'objectclass' => Array(
+                            'top',
+                            'nsds5replica',
+                            'extensibleobject',
+                        ),
+                    'nsDS5ReplicaBindDN' => $ldap->get_entry_attribute($replica_dn, "nsDS5ReplicaBindDN"),
+                    'nsDS5ReplicaId' => ($max_repl_id + $num + 1),
+                    'nsDS5ReplicaRoot' => $domain_root_dn,
+                    'nsDS5ReplicaType' => $ldap->get_entry_attribute($replica_dn, "nsDS5ReplicaType"),
+                    'nsds5ReplicaPurgeDelay' => $ldap->get_entry_attribute($replica_dn, "nsds5ReplicaPurgeDelay"),
+                    'nsDS5Flags' => $ldap->get_entry_attribute($replica_dn, "nsDS5Flags")
+                );
+
+            $new_replica_dn = 'cn=replica,cn="' . $domain_root_dn . '",cn=mapping tree,cn=config';
+
+            $this->_debug("Would have added $new_replica_dn with attributes: " . var_export($replica_attrs, TRUE));
+
+            $result = $ldap->add_entry($new_replica_dn, $replica_attrs);
+
+            $result = $ldap->search($replica_dn, "(objectclass=nsDS5ReplicationAgreement)", "sub");
+
+            if (!$result) {
+                $this->_error("Host $replica_host does not have any replication agreements");
+                continue;
+            }
+
+            $entries = $result->entries(TRUE);
+            $replica_agreement_tpl_dn = key($entries);
+
+            $this->_debug("Using " . var_export($replica_agreement_tpl_dn, TRUE) . " as the template for new replication agreements");
+
+            foreach ($replica_hosts as $replicate_to_host) {
+                // Skip the current server
+                if ($replicate_to_host == $replica_host)
+                    continue;
+
+                $this->_debug("About to add a replication agreement for $domain_root_dn to $replicate_to_host on " . $ldap->config_get('host'));
+
+                $attrs = Array(
+                        'objectclass',
+                        'nsDS5ReplicaBindDN',
+                        'nsDS5ReplicaCredentials',
+                        'nsDS5ReplicaTransportInfo',
+                        'nsDS5ReplicaBindMethod',
+                        'nsDS5ReplicaHost',
+                        'nsDS5ReplicaPort'
+                    );
+
+                $replica_agreement_attrs = $ldap->get_entry_attributes($replica_agreement_tpl_dn, $attrs);
+                $replica_agreement_attrs['cn'] = array_shift(explode('.', $replicate_to_host)) . str_replace(array('dc=',','), array('_',''), $domain_root_dn);
+                $replica_agreement_attrs['nsDS5ReplicaRoot'] = $domain_root_dn;
+                $replica_agreement_dn = "cn=" . $replica_agreement_attrs['cn'] . "," . $new_replica_dn;
+
+                $this->_debug("Would have added $replica_agreement_dn with attributes: " . var_export($replica_agreement_attrs, TRUE));
+
+                $result = $ldap->add_entry($replica_agreement_dn, $replica_agreement_attrs);
+
+            }
+        }
+
+        $server_id = implode('', array_diff($replica_hosts, $this->_server_id_not));
+
+        $this->_debug("About to trigger consumer initialization for replicas on current 'parent': $server_id");
+
+        $result = $this->search($this->config_get('config_root_dn'), "(&(objectclass=nsDS5ReplicationAgreement)(nsds5replicaroot=$domain_root_dn))", "sub");
+
+        if ($result) {
+            foreach ($result->entries(TRUE) as $agreement_dn => $agreement_attrs) {
+                $this->modify_entry_attributes(
+                        $agreement_dn,
+                        Array(
+                                'replace' => Array(
+                                        'nsds5BeginReplicaRefresh' => 'start',
+                                    ),
+                            )
+                    );
+            }
+        }
+    }
+
     public function attribute_details($attributes = array())
     {
         $schema = $this->init_schema();
@@ -385,6 +527,7 @@ class Net_LDAP3
     {
         if ($this->conn) {
             $this->_debug("C: Close");
+            $this->_current_bind_dn = null;
             ldap_unbind($this->conn);
             $this->conn = null;
         }
@@ -745,7 +888,7 @@ class Net_LDAP3
     {
         $entry = $this->get_entry_attributes($subject_dn, (array)$attribute);
 
-        return $entry[$attribute];
+        return $entry[strtolower($attribute)];
     }
 
     public function get_entry_attributes($subject_dn, $attributes)
@@ -1911,6 +2054,70 @@ class Net_LDAP3
         return array_filter($group_members);
     }
 
+    private function list_replicas()
+    {
+        $this->_debug("Finding replicas for this server.");
+
+        // Search any host that is a replica for the current host
+        $replica_hosts = $this->config_get('replica_hosts', Array());
+
+        if (!empty($replica_hosts)) {
+            return $replica_hosts;
+        }
+
+        $ldap = new Net_LDAP3($this->config);
+        $ldap->connect();
+        $ldap->bind($this->config_get('bind_dn'), $this->config_get('bind_pw'));
+
+        $ldap->config_set('return_attributes', array('nsds5replicahost'));
+
+        $result = $ldap->search($this->config_get('config_root_dn'), '(objectclass=nsds5replicationagreement)', 'sub');
+
+        if (!$result) {
+            $this->_debug("No replicas configured");
+            return $replica_hosts;
+        }
+
+        foreach ($result->entries(TRUE) as $dn => $attrs) {
+            if (!in_array($attrs['nsds5replicahost'], $replica_hosts)) {
+                $replica_hosts[] = $attrs['nsds5replicahost'];
+            }
+        }
+
+        // $replica_hosts now holds the IDs of servers we are currently NOT
+        // connected to. We might need this later in order to set
+        $this->_server_id_not = $replica_hosts;
+
+        $this->_debug("So far, we have the following replicas: " . var_export($replica_hosts, TRUE));
+
+        $ldap->close();
+
+        foreach ($replica_hosts as $replica_host) {
+            $ldap->config_set('host', $replica_host);
+            $ldap->config_set('hosts', array($replica_host));
+            $ldap->connect();
+            $ldap->bind($this->config_get('bind_dn'), $this->config_get('bind_pw'));
+
+            $ldap->config_set('return_attributes', array('nsds5replicahost'));
+            $result = $ldap->search($this->config_get('config_root_dn'), '(objectclass=nsds5replicationagreement)', 'sub');
+            if (!$result) {
+                $this->_debug("No replicas configured");
+            }
+
+            foreach ($result->entries(TRUE) as $dn => $attrs) {
+                if (!in_array($attrs['nsds5replicahost'], $replica_hosts)) {
+                    $replica_hosts[] = $attrs['nsds5replicahost'];
+                }
+            }
+
+            $ldap->close();
+        }
+
+        $this->config_set('replica_hosts', $replica_hosts);
+
+        return $replica_hosts;
+    }
+
     /**
      * memberUrl attribute parser
      *




More information about the commits mailing list