|
|
f65af0 |
From 4d99ab7ce65064aacf2a7429d8ebc956c5b43b34 Mon Sep 17 00:00:00 2001
|
|
|
979ee0 |
From: Christian Heimes <cheimes@redhat.com>
|
|
|
979ee0 |
Date: Tue, 3 Jul 2018 19:40:05 +0200
|
|
|
979ee0 |
Subject: [PATCH] Tune DS replication settings
|
|
|
979ee0 |
|
|
|
979ee0 |
Tune 389-DS replication settings to improve performance and avoid
|
|
|
979ee0 |
timeouts. During installation of a replica, the value of
|
|
|
979ee0 |
nsDS5ReplicaBindDnGroupCheckInterval is reduced to 2 seconds. At the end
|
|
|
979ee0 |
of the installation, the value is increased sensible production
|
|
|
979ee0 |
settings. This avoids long delays during replication.
|
|
|
979ee0 |
|
|
|
979ee0 |
See: https://pagure.io/freeipa/issue/7617
|
|
|
979ee0 |
Signed-off-by: Christian Heimes <cheimes@redhat.com>
|
|
|
979ee0 |
Reviewed-By: Tibor Dudlak <tdudlak@redhat.com>
|
|
|
f65af0 |
Reviewed-By: Tibor Dudlak <tdudlak@redhat.com>
|
|
|
979ee0 |
---
|
|
|
f65af0 |
ipaserver/install/cainstance.py | 8 +-
|
|
|
f65af0 |
ipaserver/install/dsinstance.py | 48 ++++++----
|
|
|
f65af0 |
ipaserver/install/replication.py | 92 +++++++++++++++----
|
|
|
f65af0 |
ipaserver/install/server/replicainstall.py | 2 +
|
|
|
f65af0 |
ipaserver/install/server/upgrade.py | 12 ++-
|
|
|
f65af0 |
ipatests/test_integration/test_external_ca.py | 21 +++++
|
|
|
f65af0 |
6 files changed, 140 insertions(+), 43 deletions(-)
|
|
|
979ee0 |
|
|
|
979ee0 |
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
|
|
|
f65af0 |
index 51fdbe9c61e06ab9d72d78aee8786f9bceca137b..8193f3da854b3a20d175de523fbc453f5c5104d8 100644
|
|
|
979ee0 |
--- a/ipaserver/install/cainstance.py
|
|
|
979ee0 |
+++ b/ipaserver/install/cainstance.py
|
|
|
f65af0 |
@@ -410,6 +410,9 @@ class CAInstance(DogtagInstance):
|
|
|
f65af0 |
self.teardown_admin)
|
|
|
f65af0 |
self.step("starting certificate server instance",
|
|
|
f65af0 |
self.start_instance)
|
|
|
979ee0 |
+ if promote:
|
|
|
979ee0 |
+ self.step("Finalize replication settings",
|
|
|
979ee0 |
+ self.finalize_replica_config)
|
|
|
979ee0 |
# Step 1 of external is getting a CSR so we don't need to do these
|
|
|
979ee0 |
# steps until we get a cert back from the external CA.
|
|
|
979ee0 |
if self.external != 1:
|
|
|
f65af0 |
@@ -1245,13 +1248,16 @@ class CAInstance(DogtagInstance):
|
|
|
979ee0 |
api.Backend.ldap2.add_entry(entry)
|
|
|
979ee0 |
|
|
|
979ee0 |
def __setup_replication(self):
|
|
|
979ee0 |
-
|
|
|
979ee0 |
repl = replication.CAReplicationManager(self.realm, self.fqdn)
|
|
|
979ee0 |
repl.setup_cs_replication(self.master_host)
|
|
|
979ee0 |
|
|
|
979ee0 |
# Activate Topology for o=ipaca segments
|
|
|
979ee0 |
self.__update_topology()
|
|
|
979ee0 |
|
|
|
979ee0 |
+ def finalize_replica_config(self):
|
|
|
979ee0 |
+ repl = replication.CAReplicationManager(self.realm, self.fqdn)
|
|
|
979ee0 |
+ repl.finalize_replica_config(self.master_host)
|
|
|
979ee0 |
+
|
|
|
979ee0 |
def __enable_instance(self):
|
|
|
979ee0 |
basedn = ipautil.realm_to_suffix(self.realm)
|
|
|
979ee0 |
if not self.clone:
|
|
|
979ee0 |
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
|
|
|
f65af0 |
index 06c1273dc21a88f99a0f543cfd12bb6563c7e214..eefbde3356e1077d490d09c4ea47d961ce3ce8e6 100644
|
|
|
979ee0 |
--- a/ipaserver/install/dsinstance.py
|
|
|
979ee0 |
+++ b/ipaserver/install/dsinstance.py
|
|
|
f65af0 |
@@ -418,6 +418,20 @@ class DsInstance(service.Service):
|
|
|
979ee0 |
|
|
|
979ee0 |
self.start_creation(runtime=30)
|
|
|
979ee0 |
|
|
|
979ee0 |
+ def _get_replication_manager(self):
|
|
|
979ee0 |
+ # Always connect to self over ldapi
|
|
|
979ee0 |
+ ldap_uri = ipaldap.get_ldap_uri(protocol='ldapi', realm=self.realm)
|
|
|
979ee0 |
+ conn = ipaldap.LDAPClient(ldap_uri)
|
|
|
979ee0 |
+ conn.external_bind()
|
|
|
979ee0 |
+ repl = replication.ReplicationManager(
|
|
|
979ee0 |
+ self.realm, self.fqdn, self.dm_password, conn=conn
|
|
|
979ee0 |
+ )
|
|
|
979ee0 |
+ if self.dm_password is not None and not self.promote:
|
|
|
979ee0 |
+ bind_dn = DN(('cn', 'Directory Manager'))
|
|
|
979ee0 |
+ bind_pw = self.dm_password
|
|
|
979ee0 |
+ else:
|
|
|
979ee0 |
+ bind_dn = bind_pw = None
|
|
|
979ee0 |
+ return repl, bind_dn, bind_pw
|
|
|
979ee0 |
|
|
|
979ee0 |
def __setup_replica(self):
|
|
|
979ee0 |
"""
|
|
|
f65af0 |
@@ -434,26 +448,24 @@ class DsInstance(service.Service):
|
|
|
979ee0 |
self.realm,
|
|
|
979ee0 |
self.dm_password)
|
|
|
979ee0 |
|
|
|
979ee0 |
- # Always connect to self over ldapi
|
|
|
979ee0 |
- ldap_uri = ipaldap.get_ldap_uri(protocol='ldapi', realm=self.realm)
|
|
|
979ee0 |
- conn = ipaldap.LDAPClient(ldap_uri)
|
|
|
979ee0 |
- conn.external_bind()
|
|
|
979ee0 |
- repl = replication.ReplicationManager(self.realm,
|
|
|
979ee0 |
- self.fqdn,
|
|
|
979ee0 |
- self.dm_password, conn=conn)
|
|
|
979ee0 |
-
|
|
|
979ee0 |
- if self.dm_password is not None and not self.promote:
|
|
|
979ee0 |
- bind_dn = DN(('cn', 'Directory Manager'))
|
|
|
979ee0 |
- bind_pw = self.dm_password
|
|
|
979ee0 |
- else:
|
|
|
979ee0 |
- bind_dn = bind_pw = None
|
|
|
979ee0 |
-
|
|
|
979ee0 |
- repl.setup_promote_replication(self.master_fqdn,
|
|
|
979ee0 |
- r_binddn=bind_dn,
|
|
|
979ee0 |
- r_bindpw=bind_pw,
|
|
|
979ee0 |
- cacert=self.ca_file)
|
|
|
979ee0 |
+ repl, bind_dn, bind_pw = self._get_replication_manager()
|
|
|
979ee0 |
+ repl.setup_promote_replication(
|
|
|
979ee0 |
+ self.master_fqdn,
|
|
|
979ee0 |
+ r_binddn=bind_dn,
|
|
|
979ee0 |
+ r_bindpw=bind_pw,
|
|
|
979ee0 |
+ cacert=self.ca_file
|
|
|
979ee0 |
+ )
|
|
|
979ee0 |
self.run_init_memberof = repl.needs_memberof_fixup()
|
|
|
979ee0 |
|
|
|
979ee0 |
+ def finalize_replica_config(self):
|
|
|
979ee0 |
+ repl, bind_dn, bind_pw = self._get_replication_manager()
|
|
|
979ee0 |
+ repl.finalize_replica_config(
|
|
|
979ee0 |
+ self.master_fqdn,
|
|
|
979ee0 |
+ r_binddn=bind_dn,
|
|
|
979ee0 |
+ r_bindpw=bind_pw,
|
|
|
979ee0 |
+ cacert=self.ca_file
|
|
|
979ee0 |
+ )
|
|
|
979ee0 |
+
|
|
|
979ee0 |
def __configure_sasl_mappings(self):
|
|
|
979ee0 |
# we need to remove any existing SASL mappings in the directory as otherwise they
|
|
|
979ee0 |
# they may conflict.
|
|
|
979ee0 |
diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py
|
|
|
f65af0 |
index 5ce8fa689c1a6fd3b9d4cbddbd5454d36334b729..d0f92c76c108d237104a81c72567250583ac4ff1 100644
|
|
|
979ee0 |
--- a/ipaserver/install/replication.py
|
|
|
979ee0 |
+++ b/ipaserver/install/replication.py
|
|
|
f65af0 |
@@ -75,6 +75,20 @@ STRIP_ATTRS = ('modifiersName',
|
|
|
979ee0 |
'internalModifiersName',
|
|
|
979ee0 |
'internalModifyTimestamp')
|
|
|
979ee0 |
|
|
|
979ee0 |
+# settings for cn=replica,cn=$DB,cn=mapping tree,cn=config
|
|
|
979ee0 |
+# during replica installation
|
|
|
979ee0 |
+REPLICA_CREATION_SETTINGS = {
|
|
|
979ee0 |
+ "nsds5ReplicaReleaseTimeout": ["20"],
|
|
|
979ee0 |
+ "nsds5ReplicaBackoffMax": ["3"],
|
|
|
979ee0 |
+ "nsDS5ReplicaBindDnGroupCheckInterval": ["2"]
|
|
|
979ee0 |
+}
|
|
|
979ee0 |
+# after replica installation
|
|
|
979ee0 |
+REPLICA_FINAL_SETTINGS = {
|
|
|
979ee0 |
+ "nsds5ReplicaReleaseTimeout": ["60"],
|
|
|
979ee0 |
+ "nsds5ReplicaBackoffMax": ["300"], # default
|
|
|
979ee0 |
+ "nsDS5ReplicaBindDnGroupCheckInterval": ["60"]
|
|
|
979ee0 |
+}
|
|
|
979ee0 |
+
|
|
|
979ee0 |
|
|
|
979ee0 |
def replica_conn_check(master_host, host_name, realm, check_ca,
|
|
|
979ee0 |
dogtag_master_ds_port, admin_password=None,
|
|
|
f65af0 |
@@ -201,9 +215,13 @@ def wait_for_entry(connection, dn, timeout, attr=None, attrvalue='*',
|
|
|
979ee0 |
|
|
|
979ee0 |
|
|
|
979ee0 |
class ReplicationManager(object):
|
|
|
979ee0 |
- """Manage replication agreements between DS servers, and sync
|
|
|
979ee0 |
- agreements with Windows servers"""
|
|
|
979ee0 |
- def __init__(self, realm, hostname, dirman_passwd, port=PORT, starttls=False, conn=None):
|
|
|
979ee0 |
+ """Manage replication agreements
|
|
|
979ee0 |
+
|
|
|
979ee0 |
+ between DS servers, and sync agreements with Windows servers
|
|
|
979ee0 |
+ """
|
|
|
979ee0 |
+
|
|
|
979ee0 |
+ def __init__(self, realm, hostname, dirman_passwd=None, port=PORT,
|
|
|
979ee0 |
+ starttls=False, conn=None):
|
|
|
979ee0 |
self.hostname = hostname
|
|
|
979ee0 |
self.port = port
|
|
|
979ee0 |
self.dirman_passwd = dirman_passwd
|
|
|
f65af0 |
@@ -481,22 +499,16 @@ class ReplicationManager(object):
|
|
|
979ee0 |
except errors.NotFound:
|
|
|
979ee0 |
pass
|
|
|
979ee0 |
else:
|
|
|
979ee0 |
- managers = {DN(m) for m in entry.get('nsDS5ReplicaBindDN', [])}
|
|
|
979ee0 |
-
|
|
|
979ee0 |
- mods = []
|
|
|
979ee0 |
- if replica_binddn not in managers:
|
|
|
979ee0 |
+ binddns = entry.setdefault('nsDS5ReplicaBindDN', [])
|
|
|
979ee0 |
+ if replica_binddn not in {DN(m) for m in binddns}:
|
|
|
979ee0 |
# Add the new replication manager
|
|
|
979ee0 |
- mods.append(
|
|
|
979ee0 |
- (ldap.MOD_ADD, 'nsDS5ReplicaBindDN', replica_binddn)
|
|
|
979ee0 |
- )
|
|
|
979ee0 |
- if 'nsds5replicareleasetimeout' not in entry:
|
|
|
979ee0 |
- # See https://pagure.io/freeipa/issue/7488
|
|
|
979ee0 |
- mods.append(
|
|
|
979ee0 |
- (ldap.MOD_ADD, 'nsds5replicareleasetimeout', ['60'])
|
|
|
979ee0 |
- )
|
|
|
979ee0 |
-
|
|
|
979ee0 |
- if mods:
|
|
|
979ee0 |
- conn.modify_s(dn, mods)
|
|
|
979ee0 |
+ binddns.append(replica_binddn)
|
|
|
979ee0 |
+ for key, value in REPLICA_CREATION_SETTINGS.items():
|
|
|
979ee0 |
+ entry[key] = value
|
|
|
979ee0 |
+ try:
|
|
|
979ee0 |
+ conn.update_entry(entry)
|
|
|
979ee0 |
+ except errors.EmptyModlist:
|
|
|
979ee0 |
+ pass
|
|
|
979ee0 |
|
|
|
979ee0 |
self.set_replica_binddngroup(conn, entry)
|
|
|
979ee0 |
|
|
|
f65af0 |
@@ -515,9 +527,8 @@ class ReplicationManager(object):
|
|
|
979ee0 |
nsds5flags=["1"],
|
|
|
979ee0 |
nsds5replicabinddn=[replica_binddn],
|
|
|
979ee0 |
nsds5replicabinddngroup=[self.repl_man_group_dn],
|
|
|
979ee0 |
- nsds5replicabinddngroupcheckinterval=["60"],
|
|
|
979ee0 |
- nsds5replicareleasetimeout=["60"],
|
|
|
979ee0 |
nsds5replicalegacyconsumer=["off"],
|
|
|
979ee0 |
+ **REPLICA_CREATION_SETTINGS
|
|
|
979ee0 |
)
|
|
|
979ee0 |
conn.add_entry(entry)
|
|
|
979ee0 |
|
|
|
f65af0 |
@@ -543,6 +554,47 @@ class ReplicationManager(object):
|
|
|
979ee0 |
except errors.DuplicateEntry:
|
|
|
979ee0 |
return
|
|
|
979ee0 |
|
|
|
979ee0 |
+ def _finalize_replica_settings(self, conn):
|
|
|
979ee0 |
+ """Change replica settings to final values
|
|
|
979ee0 |
+
|
|
|
979ee0 |
+ During replica installation, some settings are configured for faster
|
|
|
979ee0 |
+ replication.
|
|
|
979ee0 |
+ """
|
|
|
979ee0 |
+ dn = self.replica_dn()
|
|
|
979ee0 |
+ entry = conn.get_entry(dn)
|
|
|
979ee0 |
+ for key, value in REPLICA_FINAL_SETTINGS.items():
|
|
|
979ee0 |
+ entry[key] = value
|
|
|
979ee0 |
+ try:
|
|
|
979ee0 |
+ conn.update_entry(entry)
|
|
|
979ee0 |
+ except errors.EmptyModlist:
|
|
|
979ee0 |
+ pass
|
|
|
979ee0 |
+
|
|
|
979ee0 |
+ def finalize_replica_config(self, r_hostname, r_binddn=None,
|
|
|
979ee0 |
+ r_bindpw=None, cacert=paths.IPA_CA_CRT):
|
|
|
979ee0 |
+ """Apply final cn=replica settings
|
|
|
979ee0 |
+
|
|
|
979ee0 |
+ replica_config() sets several attribute to fast cache invalidation
|
|
|
979ee0 |
+ and fast reconnects to optimize replicat installation. For
|
|
|
979ee0 |
+ production, longer timeouts and less aggressive cache invalidation
|
|
|
979ee0 |
+ is sufficient. finalize_replica_config() sets the values on new
|
|
|
979ee0 |
+ replica and the master.
|
|
|
979ee0 |
+
|
|
|
979ee0 |
+ When installing multiple replicas in parallel, one replica may
|
|
|
979ee0 |
+ finalize the values while another is still installing.
|
|
|
979ee0 |
+
|
|
|
979ee0 |
+ See https://pagure.io/freeipa/issue/7617
|
|
|
979ee0 |
+ """
|
|
|
979ee0 |
+ self._finalize_replica_settings(self.conn)
|
|
|
979ee0 |
+
|
|
|
979ee0 |
+ ldap_uri = ipaldap.get_ldap_uri(r_hostname)
|
|
|
979ee0 |
+ r_conn = ipaldap.LDAPClient(ldap_uri, cacert=cacert)
|
|
|
979ee0 |
+ if r_bindpw:
|
|
|
979ee0 |
+ r_conn.simple_bind(r_binddn, r_bindpw)
|
|
|
979ee0 |
+ else:
|
|
|
979ee0 |
+ r_conn.gssapi_bind()
|
|
|
979ee0 |
+ self._finalize_replica_settings(r_conn)
|
|
|
979ee0 |
+ r_conn.close()
|
|
|
979ee0 |
+
|
|
|
979ee0 |
def setup_chaining_backend(self, conn):
|
|
|
979ee0 |
chaindn = DN(('cn', 'chaining database'), ('cn', 'plugins'), ('cn', 'config'))
|
|
|
979ee0 |
benamebase = "chaindb"
|
|
|
979ee0 |
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
|
|
|
f65af0 |
index 542e1d4d145f266d6fd9ad8e0eaffcb12e8f6bc6..8826da232a90380084b0e4f3dca783125a5500da 100644
|
|
|
979ee0 |
--- a/ipaserver/install/server/replicainstall.py
|
|
|
979ee0 |
+++ b/ipaserver/install/server/replicainstall.py
|
|
|
f65af0 |
@@ -1506,6 +1506,8 @@ def install(installer):
|
|
|
979ee0 |
# Apply any LDAP updates. Needs to be done after the replica is synced-up
|
|
|
979ee0 |
service.print_msg("Applying LDAP updates")
|
|
|
979ee0 |
ds.apply_updates()
|
|
|
979ee0 |
+ service.print_msg("Finalize replication settings")
|
|
|
979ee0 |
+ ds.finalize_replica_config()
|
|
|
979ee0 |
|
|
|
979ee0 |
if kra_enabled:
|
|
|
979ee0 |
kra.install(api, config, options, custodia=custodia)
|
|
|
979ee0 |
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
|
|
|
f65af0 |
index ee3cedd78a2f45f33665bf562e9426cf68325544..4e5096e598cd10e3bd98f91946b4d26377d0de6e 100644
|
|
|
979ee0 |
--- a/ipaserver/install/server/upgrade.py
|
|
|
979ee0 |
+++ b/ipaserver/install/server/upgrade.py
|
|
|
f65af0 |
@@ -45,6 +45,7 @@ from ipaserver.install import dnskeysyncinstance
|
|
|
979ee0 |
from ipaserver.install import dogtaginstance
|
|
|
979ee0 |
from ipaserver.install import krbinstance
|
|
|
979ee0 |
from ipaserver.install import adtrustinstance
|
|
|
979ee0 |
+from ipaserver.install import replication
|
|
|
979ee0 |
from ipaserver.install.upgradeinstance import IPAUpgrade
|
|
|
979ee0 |
from ipaserver.install.ldapupdate import BadSyntax
|
|
|
979ee0 |
|
|
|
f65af0 |
@@ -1645,11 +1646,14 @@ def update_replica_config(db_suffix):
|
|
|
979ee0 |
except ipalib.errors.NotFound:
|
|
|
979ee0 |
return # entry does not exist until a replica is installed
|
|
|
979ee0 |
|
|
|
979ee0 |
- if 'nsds5replicareleasetimeout' not in entry:
|
|
|
979ee0 |
- # See https://pagure.io/freeipa/issue/7488
|
|
|
f65af0 |
- logger.info("Adding nsds5replicaReleaseTimeout=60 to %s", dn)
|
|
|
979ee0 |
- entry['nsds5replicareleasetimeout'] = '60'
|
|
|
979ee0 |
+ for key, value in replication.REPLICA_FINAL_SETTINGS.items():
|
|
|
979ee0 |
+ entry[key] = value
|
|
|
979ee0 |
+ try:
|
|
|
979ee0 |
api.Backend.ldap2.update_entry(entry)
|
|
|
979ee0 |
+ except ipalib.errors.EmptyModlist:
|
|
|
979ee0 |
+ pass
|
|
|
979ee0 |
+ else:
|
|
|
f65af0 |
+ logger.info("Updated entry %s", dn)
|
|
|
979ee0 |
|
|
|
979ee0 |
|
|
|
979ee0 |
def upgrade_configuration():
|
|
|
979ee0 |
diff --git a/ipatests/test_integration/test_external_ca.py b/ipatests/test_integration/test_external_ca.py
|
|
|
f65af0 |
index d21e6d543f51dcee1e548e322cbe01fbe0c13d48..2fc2478ae8bb49d95f7ec60270fb5bb6e582d6f5 100644
|
|
|
979ee0 |
--- a/ipatests/test_integration/test_external_ca.py
|
|
|
979ee0 |
+++ b/ipatests/test_integration/test_external_ca.py
|
|
|
f65af0 |
@@ -130,6 +130,27 @@ class TestExternalCA(IntegrationTest):
|
|
|
979ee0 |
result = self.master.run_command(['ipa', 'user-show', 'admin'])
|
|
|
979ee0 |
assert 'User login: admin' in result.stdout_text
|
|
|
f65af0 |
|
|
|
979ee0 |
+ # check that we can also install replica
|
|
|
979ee0 |
+ tasks.install_replica(self.master, self.replicas[0])
|
|
|
979ee0 |
+
|
|
|
979ee0 |
+ # check that nsds5ReplicaReleaseTimeout option was set
|
|
|
979ee0 |
+ result = self.master.run_command([
|
|
|
979ee0 |
+ 'ldapsearch',
|
|
|
979ee0 |
+ '-x',
|
|
|
979ee0 |
+ '-D',
|
|
|
979ee0 |
+ 'cn=directory manager',
|
|
|
979ee0 |
+ '-w', self.master.config.dirman_password,
|
|
|
979ee0 |
+ '-b', 'cn=mapping tree,cn=config',
|
|
|
979ee0 |
+ '(cn=replica)',
|
|
|
979ee0 |
+ '-LLL',
|
|
|
979ee0 |
+ '-o',
|
|
|
979ee0 |
+ 'ldif-wrap=no'])
|
|
|
979ee0 |
+ # case insensitive match
|
|
|
979ee0 |
+ text = result.stdout_text.lower()
|
|
|
979ee0 |
+ # see ipaserver.install.replication.REPLICA_FINAL_SETTINGS
|
|
|
979ee0 |
+ assert 'nsds5ReplicaReleaseTimeout: 60'.lower() in text
|
|
|
979ee0 |
+ assert 'nsDS5ReplicaBindDnGroupCheckInterval: 60'.lower() in text
|
|
|
f65af0 |
+
|
|
|
f65af0 |
def test_client_installation_with_otp(self):
|
|
|
f65af0 |
# Test for issue 7526: client installation fails with one-time
|
|
|
f65af0 |
# password when the master is installed with an externally signed
|
|
|
979ee0 |
--
|
|
|
979ee0 |
2.17.1
|
|
|
979ee0 |
|