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