mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2026-07-29 15:55:47 -05:00
Tune DS replication settings
Tune 389-DS replication settings to improve performance and avoid timeouts. During installation of a replica, the value of nsDS5ReplicaBindDnGroupCheckInterval is reduced to 2 seconds. At the end of the installation, the value is increased sensible production settings. This avoids long delays during replication. See: https://pagure.io/freeipa/issue/7617 Signed-off-by: Christian Heimes <cheimes@redhat.com> Reviewed-By: Tibor Dudlak <tdudlak@redhat.com>
This commit is contained in:
@@ -419,6 +419,9 @@ class CAInstance(DogtagInstance):
|
|||||||
self.teardown_admin)
|
self.teardown_admin)
|
||||||
self.step("starting certificate server instance",
|
self.step("starting certificate server instance",
|
||||||
self.start_instance)
|
self.start_instance)
|
||||||
|
if promote:
|
||||||
|
self.step("Finalize replication settings",
|
||||||
|
self.finalize_replica_config)
|
||||||
# Step 1 of external is getting a CSR so we don't need to do these
|
# Step 1 of external is getting a CSR so we don't need to do these
|
||||||
# steps until we get a cert back from the external CA.
|
# steps until we get a cert back from the external CA.
|
||||||
if self.external != 1:
|
if self.external != 1:
|
||||||
@@ -1253,13 +1256,16 @@ class CAInstance(DogtagInstance):
|
|||||||
api.Backend.ldap2.add_entry(entry)
|
api.Backend.ldap2.add_entry(entry)
|
||||||
|
|
||||||
def __setup_replication(self):
|
def __setup_replication(self):
|
||||||
|
|
||||||
repl = replication.CAReplicationManager(self.realm, self.fqdn)
|
repl = replication.CAReplicationManager(self.realm, self.fqdn)
|
||||||
repl.setup_cs_replication(self.master_host)
|
repl.setup_cs_replication(self.master_host)
|
||||||
|
|
||||||
# Activate Topology for o=ipaca segments
|
# Activate Topology for o=ipaca segments
|
||||||
self.__update_topology()
|
self.__update_topology()
|
||||||
|
|
||||||
|
def finalize_replica_config(self):
|
||||||
|
repl = replication.CAReplicationManager(self.realm, self.fqdn)
|
||||||
|
repl.finalize_replica_config(self.master_host)
|
||||||
|
|
||||||
def __enable_instance(self):
|
def __enable_instance(self):
|
||||||
basedn = ipautil.realm_to_suffix(self.realm)
|
basedn = ipautil.realm_to_suffix(self.realm)
|
||||||
if not self.clone:
|
if not self.clone:
|
||||||
|
|||||||
@@ -418,6 +418,20 @@ class DsInstance(service.Service):
|
|||||||
|
|
||||||
self.start_creation(runtime=30)
|
self.start_creation(runtime=30)
|
||||||
|
|
||||||
|
def _get_replication_manager(self):
|
||||||
|
# Always connect to self over ldapi
|
||||||
|
ldap_uri = ipaldap.get_ldap_uri(protocol='ldapi', realm=self.realm)
|
||||||
|
conn = ipaldap.LDAPClient(ldap_uri)
|
||||||
|
conn.external_bind()
|
||||||
|
repl = replication.ReplicationManager(
|
||||||
|
self.realm, self.fqdn, self.dm_password, conn=conn
|
||||||
|
)
|
||||||
|
if self.dm_password is not None and not self.promote:
|
||||||
|
bind_dn = DN(('cn', 'Directory Manager'))
|
||||||
|
bind_pw = self.dm_password
|
||||||
|
else:
|
||||||
|
bind_dn = bind_pw = None
|
||||||
|
return repl, bind_dn, bind_pw
|
||||||
|
|
||||||
def __setup_replica(self):
|
def __setup_replica(self):
|
||||||
"""
|
"""
|
||||||
@@ -434,26 +448,24 @@ class DsInstance(service.Service):
|
|||||||
self.realm,
|
self.realm,
|
||||||
self.dm_password)
|
self.dm_password)
|
||||||
|
|
||||||
# Always connect to self over ldapi
|
repl, bind_dn, bind_pw = self._get_replication_manager()
|
||||||
ldap_uri = ipaldap.get_ldap_uri(protocol='ldapi', realm=self.realm)
|
repl.setup_promote_replication(
|
||||||
conn = ipaldap.LDAPClient(ldap_uri)
|
self.master_fqdn,
|
||||||
conn.external_bind()
|
r_binddn=bind_dn,
|
||||||
repl = replication.ReplicationManager(self.realm,
|
r_bindpw=bind_pw,
|
||||||
self.fqdn,
|
cacert=self.ca_file
|
||||||
self.dm_password, conn=conn)
|
)
|
||||||
|
|
||||||
if self.dm_password is not None and not self.promote:
|
|
||||||
bind_dn = DN(('cn', 'Directory Manager'))
|
|
||||||
bind_pw = self.dm_password
|
|
||||||
else:
|
|
||||||
bind_dn = bind_pw = None
|
|
||||||
|
|
||||||
repl.setup_promote_replication(self.master_fqdn,
|
|
||||||
r_binddn=bind_dn,
|
|
||||||
r_bindpw=bind_pw,
|
|
||||||
cacert=self.ca_file)
|
|
||||||
self.run_init_memberof = repl.needs_memberof_fixup()
|
self.run_init_memberof = repl.needs_memberof_fixup()
|
||||||
|
|
||||||
|
def finalize_replica_config(self):
|
||||||
|
repl, bind_dn, bind_pw = self._get_replication_manager()
|
||||||
|
repl.finalize_replica_config(
|
||||||
|
self.master_fqdn,
|
||||||
|
r_binddn=bind_dn,
|
||||||
|
r_bindpw=bind_pw,
|
||||||
|
cacert=self.ca_file
|
||||||
|
)
|
||||||
|
|
||||||
def __configure_sasl_mappings(self):
|
def __configure_sasl_mappings(self):
|
||||||
# we need to remove any existing SASL mappings in the directory as otherwise they
|
# we need to remove any existing SASL mappings in the directory as otherwise they
|
||||||
# they may conflict.
|
# they may conflict.
|
||||||
|
|||||||
@@ -75,6 +75,20 @@ STRIP_ATTRS = ('modifiersName',
|
|||||||
'internalModifiersName',
|
'internalModifiersName',
|
||||||
'internalModifyTimestamp')
|
'internalModifyTimestamp')
|
||||||
|
|
||||||
|
# settings for cn=replica,cn=$DB,cn=mapping tree,cn=config
|
||||||
|
# during replica installation
|
||||||
|
REPLICA_CREATION_SETTINGS = {
|
||||||
|
"nsds5ReplicaReleaseTimeout": ["20"],
|
||||||
|
"nsds5ReplicaBackoffMax": ["3"],
|
||||||
|
"nsDS5ReplicaBindDnGroupCheckInterval": ["2"]
|
||||||
|
}
|
||||||
|
# after replica installation
|
||||||
|
REPLICA_FINAL_SETTINGS = {
|
||||||
|
"nsds5ReplicaReleaseTimeout": ["60"],
|
||||||
|
"nsds5ReplicaBackoffMax": ["300"], # default
|
||||||
|
"nsDS5ReplicaBindDnGroupCheckInterval": ["60"]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def replica_conn_check(master_host, host_name, realm, check_ca,
|
def replica_conn_check(master_host, host_name, realm, check_ca,
|
||||||
dogtag_master_ds_port, admin_password=None,
|
dogtag_master_ds_port, admin_password=None,
|
||||||
@@ -201,9 +215,13 @@ def wait_for_entry(connection, dn, timeout, attr=None, attrvalue='*',
|
|||||||
|
|
||||||
|
|
||||||
class ReplicationManager(object):
|
class ReplicationManager(object):
|
||||||
"""Manage replication agreements between DS servers, and sync
|
"""Manage replication agreements
|
||||||
agreements with Windows servers"""
|
|
||||||
def __init__(self, realm, hostname, dirman_passwd, port=PORT, starttls=False, conn=None):
|
between DS servers, and sync agreements with Windows servers
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, realm, hostname, dirman_passwd=None, port=PORT,
|
||||||
|
starttls=False, conn=None):
|
||||||
self.hostname = hostname
|
self.hostname = hostname
|
||||||
self.port = port
|
self.port = port
|
||||||
self.dirman_passwd = dirman_passwd
|
self.dirman_passwd = dirman_passwd
|
||||||
@@ -481,22 +499,16 @@ class ReplicationManager(object):
|
|||||||
except errors.NotFound:
|
except errors.NotFound:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
managers = {DN(m) for m in entry.get('nsDS5ReplicaBindDN', [])}
|
binddns = entry.setdefault('nsDS5ReplicaBindDN', [])
|
||||||
|
if replica_binddn not in {DN(m) for m in binddns}:
|
||||||
mods = []
|
|
||||||
if replica_binddn not in managers:
|
|
||||||
# Add the new replication manager
|
# Add the new replication manager
|
||||||
mods.append(
|
binddns.append(replica_binddn)
|
||||||
(ldap.MOD_ADD, 'nsDS5ReplicaBindDN', replica_binddn)
|
for key, value in REPLICA_CREATION_SETTINGS.items():
|
||||||
)
|
entry[key] = value
|
||||||
if 'nsds5replicareleasetimeout' not in entry:
|
try:
|
||||||
# See https://pagure.io/freeipa/issue/7488
|
conn.update_entry(entry)
|
||||||
mods.append(
|
except errors.EmptyModlist:
|
||||||
(ldap.MOD_ADD, 'nsds5replicareleasetimeout', ['60'])
|
pass
|
||||||
)
|
|
||||||
|
|
||||||
if mods:
|
|
||||||
conn.modify_s(dn, mods)
|
|
||||||
|
|
||||||
self.set_replica_binddngroup(conn, entry)
|
self.set_replica_binddngroup(conn, entry)
|
||||||
|
|
||||||
@@ -515,9 +527,8 @@ class ReplicationManager(object):
|
|||||||
nsds5flags=["1"],
|
nsds5flags=["1"],
|
||||||
nsds5replicabinddn=[replica_binddn],
|
nsds5replicabinddn=[replica_binddn],
|
||||||
nsds5replicabinddngroup=[self.repl_man_group_dn],
|
nsds5replicabinddngroup=[self.repl_man_group_dn],
|
||||||
nsds5replicabinddngroupcheckinterval=["60"],
|
|
||||||
nsds5replicareleasetimeout=["60"],
|
|
||||||
nsds5replicalegacyconsumer=["off"],
|
nsds5replicalegacyconsumer=["off"],
|
||||||
|
**REPLICA_CREATION_SETTINGS
|
||||||
)
|
)
|
||||||
conn.add_entry(entry)
|
conn.add_entry(entry)
|
||||||
|
|
||||||
@@ -543,6 +554,47 @@ class ReplicationManager(object):
|
|||||||
except errors.DuplicateEntry:
|
except errors.DuplicateEntry:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def _finalize_replica_settings(self, conn):
|
||||||
|
"""Change replica settings to final values
|
||||||
|
|
||||||
|
During replica installation, some settings are configured for faster
|
||||||
|
replication.
|
||||||
|
"""
|
||||||
|
dn = self.replica_dn()
|
||||||
|
entry = conn.get_entry(dn)
|
||||||
|
for key, value in REPLICA_FINAL_SETTINGS.items():
|
||||||
|
entry[key] = value
|
||||||
|
try:
|
||||||
|
conn.update_entry(entry)
|
||||||
|
except errors.EmptyModlist:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def finalize_replica_config(self, r_hostname, r_binddn=None,
|
||||||
|
r_bindpw=None, cacert=paths.IPA_CA_CRT):
|
||||||
|
"""Apply final cn=replica settings
|
||||||
|
|
||||||
|
replica_config() sets several attribute to fast cache invalidation
|
||||||
|
and fast reconnects to optimize replicat installation. For
|
||||||
|
production, longer timeouts and less aggressive cache invalidation
|
||||||
|
is sufficient. finalize_replica_config() sets the values on new
|
||||||
|
replica and the master.
|
||||||
|
|
||||||
|
When installing multiple replicas in parallel, one replica may
|
||||||
|
finalize the values while another is still installing.
|
||||||
|
|
||||||
|
See https://pagure.io/freeipa/issue/7617
|
||||||
|
"""
|
||||||
|
self._finalize_replica_settings(self.conn)
|
||||||
|
|
||||||
|
ldap_uri = ipaldap.get_ldap_uri(r_hostname)
|
||||||
|
r_conn = ipaldap.LDAPClient(ldap_uri, cacert=cacert)
|
||||||
|
if r_bindpw:
|
||||||
|
r_conn.simple_bind(r_binddn, r_bindpw)
|
||||||
|
else:
|
||||||
|
r_conn.gssapi_bind()
|
||||||
|
self._finalize_replica_settings(r_conn)
|
||||||
|
r_conn.close()
|
||||||
|
|
||||||
def setup_chaining_backend(self, conn):
|
def setup_chaining_backend(self, conn):
|
||||||
chaindn = DN(('cn', 'chaining database'), ('cn', 'plugins'), ('cn', 'config'))
|
chaindn = DN(('cn', 'chaining database'), ('cn', 'plugins'), ('cn', 'config'))
|
||||||
benamebase = "chaindb"
|
benamebase = "chaindb"
|
||||||
|
|||||||
@@ -1505,6 +1505,8 @@ def install(installer):
|
|||||||
# Apply any LDAP updates. Needs to be done after the replica is synced-up
|
# Apply any LDAP updates. Needs to be done after the replica is synced-up
|
||||||
service.print_msg("Applying LDAP updates")
|
service.print_msg("Applying LDAP updates")
|
||||||
ds.apply_updates()
|
ds.apply_updates()
|
||||||
|
service.print_msg("Finalize replication settings")
|
||||||
|
ds.finalize_replica_config()
|
||||||
|
|
||||||
if kra_enabled:
|
if kra_enabled:
|
||||||
kra.install(api, config, options, custodia=custodia)
|
kra.install(api, config, options, custodia=custodia)
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ from ipaserver.install import dnskeysyncinstance
|
|||||||
from ipaserver.install import dogtaginstance
|
from ipaserver.install import dogtaginstance
|
||||||
from ipaserver.install import krbinstance
|
from ipaserver.install import krbinstance
|
||||||
from ipaserver.install import adtrustinstance
|
from ipaserver.install import adtrustinstance
|
||||||
|
from ipaserver.install import replication
|
||||||
from ipaserver.install.upgradeinstance import IPAUpgrade
|
from ipaserver.install.upgradeinstance import IPAUpgrade
|
||||||
from ipaserver.install.ldapupdate import BadSyntax
|
from ipaserver.install.ldapupdate import BadSyntax
|
||||||
|
|
||||||
@@ -1680,11 +1681,14 @@ def update_replica_config(db_suffix):
|
|||||||
except ipalib.errors.NotFound:
|
except ipalib.errors.NotFound:
|
||||||
return # entry does not exist until a replica is installed
|
return # entry does not exist until a replica is installed
|
||||||
|
|
||||||
if 'nsds5replicareleasetimeout' not in entry:
|
for key, value in replication.REPLICA_FINAL_SETTINGS.items():
|
||||||
# See https://pagure.io/freeipa/issue/7488
|
entry[key] = value
|
||||||
logger.info("Adding nsds5replicaReleaseTimeout=60 to %s", dn)
|
try:
|
||||||
entry['nsds5replicareleasetimeout'] = '60'
|
|
||||||
api.Backend.ldap2.update_entry(entry)
|
api.Backend.ldap2.update_entry(entry)
|
||||||
|
except ipalib.errors.EmptyModlist:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
logger.info("Updated entry %s", dn)
|
||||||
|
|
||||||
|
|
||||||
def migrate_to_authselect():
|
def migrate_to_authselect():
|
||||||
|
|||||||
@@ -148,7 +148,11 @@ class TestExternalCA(IntegrationTest):
|
|||||||
'-LLL',
|
'-LLL',
|
||||||
'-o',
|
'-o',
|
||||||
'ldif-wrap=no'])
|
'ldif-wrap=no'])
|
||||||
assert 'nsds5ReplicaReleaseTimeout: 60' in result.stdout_text
|
# case insensitive match
|
||||||
|
text = result.stdout_text.lower()
|
||||||
|
# see ipaserver.install.replication.REPLICA_FINAL_SETTINGS
|
||||||
|
assert 'nsds5ReplicaReleaseTimeout: 60'.lower() in text
|
||||||
|
assert 'nsDS5ReplicaBindDnGroupCheckInterval: 60'.lower() in text
|
||||||
|
|
||||||
def test_client_installation_with_otp(self):
|
def test_client_installation_with_otp(self):
|
||||||
# Test for issue 7526: client installation fails with one-time
|
# Test for issue 7526: client installation fails with one-time
|
||||||
|
|||||||
Reference in New Issue
Block a user