freeipa/ipaserver/install/plugins/update_dna_shared_config.py
Christian Heimes c78d1341ad Redesign subid feature
Subordinate ids are now handled by a new plugin class and stored in
separate entries in the cn=subids,cn=accounts subtree.

Signed-off-by: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Francois Cami <fcami@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2021-07-09 09:47:30 -04:00

148 lines
4.8 KiB
Python

#
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
#
import logging
import time
import ldap
from ipalib.plugable import Registry
from ipalib import errors
from ipalib import Updater
from ipapython.dn import DN
logger = logging.getLogger(__name__)
register = Registry()
@register()
class update_dna_shared_config(Updater):
dna_plugin_names = ('posix IDs', 'Subordinate IDs')
dna_plugin_dn = DN(
('cn', 'Distributed Numeric Assignment Plugin'),
('cn', 'plugins'),
('cn', 'config')
)
def is_dna_enabled(self):
"""Check the plugin is enabled
Else it is useless to update the shared entry
"""
try:
entry = self.api.Backend.ldap2.get_entry(self.dna_plugin_dn)
enabled = entry.single_value.get('nsslapd-pluginenabled')
if enabled.lower() == 'off':
return False
else:
return True
except errors.NotFound:
logger.error("Could not find DNA plugin entry: %s",
self.dna_plugin_dn)
return False
def get_shared_cfg(self, plugin_name):
dna_config_base = DN(('cn', plugin_name), self.dna_plugin_dn)
try:
entry = self.api.Backend.ldap2.get_entry(dna_config_base)
except errors.NotFound:
logger.error("Could not find DNA config entry: %s",
dna_config_base)
return False, ()
else:
logger.debug('Found DNA config %s', dna_config_base)
sharedcfgdn = entry.single_value.get("dnaSharedCfgDN")
if sharedcfgdn is not None:
sharedcfgdn = DN(sharedcfgdn)
logger.debug("dnaSharedCfgDN: %s", sharedcfgdn)
return sharedcfgdn
else:
logger.error(
"Could not find DNA shared config DN in entry: %s",
dna_config_base)
return None
def update_shared_cfg(self, sharedcfgdn, **options):
"""Update the shared config entry related to that host
If the shared config entry already exists (like upgrade)
the update occurs immediately without sleep.
If the shared config entry does not exist (fresh install)
DS server waits for 30s after its startup to create it.
Startup likely occurred few sec before this function is
called so this loop will wait for 30s max.
In case the server is not able to create the entry
The loop gives a grace period of slightly more than 60 seconds
before it logs a failure and aborts the update.
"""
method = options.get('method', "SASL/GSSAPI")
protocol = options.get('protocol', "LDAP")
max_wait = 30 # times 2 second sleep
conn = self.api.Backend.ldap2
fqdn = self.api.env.host
for _i in range(0, max_wait + 1):
try:
entries = conn.get_entries(
sharedcfgdn, scope=ldap.SCOPE_ONELEVEL,
filter='dnaHostname=%s' % fqdn
)
# There must be two entries:
# - dnaHostname=fqdn+dnaPortNum=0
# - dnaHostname=fqdn+dnaPortNum=389
if len(entries) >= 2:
break
logger.debug("Got only one entry. Retry again in 2 sec.")
time.sleep(2)
except errors.NotFound:
logger.debug(
"Unable to find DNA shared config entry for "
"dnaHostname=%s (under %s) so far. Retry in 2 sec.",
fqdn, sharedcfgdn
)
time.sleep(2)
else:
logger.error(
"Could not get dnaHostname entries in %s seconds",
max_wait * 2
)
return False
# time to set the bind method and the protocol in the
# shared config entries
for entry in entries:
entry["dnaRemoteBindMethod"] = method
entry["dnaRemoteConnProtocol"] = protocol
try:
conn.update_entry(entry)
except errors.EmptyModlist:
logger.debug("Entry %s is already updated", entry.dn)
except Exception as e:
logger.error(
"Failed to set SASL/GSSAPI bind method/protocol "
"in entry %s: %s", entry, e
)
else:
logger.debug("Updated entry %s", entry.dn)
return True
def execute(self, **options):
if not self.is_dna_enabled():
return False, ()
for plugin_name in self.dna_plugin_names:
sharedcfgdn = self.get_shared_cfg(plugin_name)
if sharedcfgdn is not None:
self.update_shared_cfg(sharedcfgdn, **options)
# no restart, no update
return False, ()