mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Move Managed Entries into their own container in the replicated space.
Repoint cn=Managed Entries,cn=plugins,cn=config in common_setup Create: cn=Managed Entries,cn=etc,$SUFFIX Create: cn=Definitions,cn=Managed Entries,cn=etc,$SUFFIX Create: cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX Create method for dynamically migrating any and all custom Managed Entries from the cn=config space into the new container. Separate the connection creation during update so that a restart can be performed to initialize changes before performing a delete. Add wait_for_open_socket() method in installutils https://fedorahosted.org/freeipa/ticket/1708
This commit is contained in:
parent
7c50d17983
commit
3b633d559c
@ -42,6 +42,8 @@ app_DATA = \
|
||||
schema_compat.uldif \
|
||||
ldapi.ldif \
|
||||
wsgi.py \
|
||||
repoint-managed-entries.ldif \
|
||||
managed-entries.ldif \
|
||||
user_private_groups.ldif \
|
||||
host_nis_groups.ldif \
|
||||
uuid-ipauniqueid.ldif \
|
||||
|
@ -1,4 +1,4 @@
|
||||
dn: cn=NGP HGP Template,cn=etc,$SUFFIX
|
||||
dn: cn=NGP HGP Template,cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX
|
||||
changetype: add
|
||||
objectclass: mepTemplateEntry
|
||||
cn: NGP HGP Template
|
||||
@ -13,11 +13,11 @@ mepMappedAttr: description: ipaNetgroup $$cn
|
||||
|
||||
# Changes to this definition need to be reflected in
|
||||
# updates/20-host_nis_groups.update
|
||||
dn: cn=NGP Definition,cn=Managed Entries,cn=plugins,cn=config
|
||||
dn: cn=NGP Definition,cn=Definitions,cn=Managed Entries,cn=etc,$SUFFIX
|
||||
changetype: add
|
||||
objectclass: extensibleObject
|
||||
cn: NGP Definition
|
||||
originScope: cn=hostgroups,cn=accounts,$SUFFIX
|
||||
originFilter: objectclass=ipahostgroup
|
||||
managedBase: cn=ng,cn=alt,$SUFFIX
|
||||
managedTemplate: cn=NGP HGP Template,cn=etc,$SUFFIX
|
||||
managedTemplate: cn=NGP HGP Template,cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX
|
||||
|
17
install/share/managed-entries.ldif
Normal file
17
install/share/managed-entries.ldif
Normal file
@ -0,0 +1,17 @@
|
||||
dn: cn=Managed Entries,cn=etc,$SUFFIX
|
||||
changetype: add
|
||||
objectClass: nsContainer
|
||||
objectClass: top
|
||||
cn: Managed Entries
|
||||
|
||||
dn: cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX
|
||||
changetype: add
|
||||
objectClass: nsContainer
|
||||
objectClass: top
|
||||
cn: Templates
|
||||
|
||||
dn: cn=Definitions,cn=Managed Entries,cn=etc,$SUFFIX
|
||||
changetype: add
|
||||
objectClass: nsContainer
|
||||
objectClass: top
|
||||
cn: Definitions
|
5
install/share/repoint-managed-entries.ldif
Normal file
5
install/share/repoint-managed-entries.ldif
Normal file
@ -0,0 +1,5 @@
|
||||
# Repoint Managed Entries to the replicated cn=etc space
|
||||
dn: cn=Managed Entries,cn=plugins,cn=config
|
||||
changetype: modify
|
||||
add: nsslapd-pluginConfigArea
|
||||
nsslapd-pluginConfigArea: cn=Definitions,cn=Managed Entries,cn=etc,$SUFFIX
|
@ -1,4 +1,4 @@
|
||||
dn: cn=UPG Template,cn=etc,$SUFFIX
|
||||
dn: cn=UPG Template,cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX
|
||||
changetype: add
|
||||
objectclass: mepTemplateEntry
|
||||
cn: UPG Template
|
||||
@ -12,12 +12,12 @@ mepMappedAttr: description: User private group for $$uid
|
||||
|
||||
# Changes to this definition need to be reflected in
|
||||
# updates/20-user_private_groups.update
|
||||
dn: cn=UPG Definition,cn=Managed Entries,cn=plugins,cn=config
|
||||
dn: cn=UPG Definition,cn=Definitions,cn=Managed Entries,cn=etc,$SUFFIX
|
||||
changetype: add
|
||||
objectclass: extensibleObject
|
||||
cn: UPG Definition
|
||||
originScope: cn=users,cn=accounts,$SUFFIX
|
||||
originFilter: (&(objectclass=posixAccount)(!(description=__no_upg__)))
|
||||
managedBase: cn=groups,cn=accounts,$SUFFIX
|
||||
managedTemplate: cn=UPG Template,cn=etc,$SUFFIX
|
||||
managedTemplate: cn=UPG Template,cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX
|
||||
|
||||
|
17
install/updates/19-managed-entries.update
Normal file
17
install/updates/19-managed-entries.update
Normal file
@ -0,0 +1,17 @@
|
||||
dn: cn=Managed Entries,cn=plugins,cn=config
|
||||
only: nsslapd-pluginConfigArea: 'cn=Definitions,cn=Managed Entries,cn=etc,$SUFFIX'
|
||||
|
||||
dn: cn=Managed Entries,cn=etc,$SUFFIX
|
||||
default: objectClass: nsContainer
|
||||
default: objectClass: top
|
||||
default: cn: Managed Entries
|
||||
|
||||
dn: cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX
|
||||
default: objectClass: nsContainer
|
||||
default: objectClass: top
|
||||
default: cn: Templates
|
||||
|
||||
dn: cn=Definitions,cn=Managed Entries,cn=etc,$SUFFIX
|
||||
default: objectClass: nsContainer
|
||||
default: objectClass: top
|
||||
default: cn: Definitions
|
@ -2,14 +2,22 @@
|
||||
# This is required for replication. The template entry will get
|
||||
# replicated but the plugin configuration will not.
|
||||
|
||||
dn: cn=NGP Definition,cn=Managed Entries,cn=plugins,cn=config
|
||||
dn: cn=NGP HGP Template,cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX
|
||||
default:objectclass: mepTemplateEntry
|
||||
default:cn: NGP HGP Template
|
||||
default:mepRDNAttr: cn
|
||||
default:mepStaticAttr: ipaUniqueId: autogenerate
|
||||
default:mepStaticAttr: objectclass: ipanisnetgroup
|
||||
default:mepStaticAttr: objectclass: ipaobject
|
||||
default:mepStaticAttr: nisDomainName: $DOMAIN
|
||||
default:mepMappedAttr: cn: $$cn
|
||||
default:mepMappedAttr: memberHost: $$dn
|
||||
default:mepMappedAttr: description: ipaNetgroup $$cn
|
||||
|
||||
dn: cn=NGP Definition,cn=Definitions,cn=Managed Entries,cn=etc,$SUFFIX
|
||||
default:objectclass: extensibleObject
|
||||
default:cn: NGP Definition
|
||||
only:cn: NGP Definition
|
||||
default:originScope: cn=hostgroups,cn=accounts,$SUFFIX
|
||||
default:originFilter: objectclass=ipahostgroup
|
||||
default:managedBase: cn=ng,cn=alt,$SUFFIX
|
||||
default:managedTemplate: cn=NGP HGP Template,cn=etc,$SUFFIX
|
||||
|
||||
# Fix an existing configuration with the wrong cn
|
||||
dn: cn=NGP Definition,cn=Managed Entries,cn=plugins,cn=config
|
||||
only:cn: NGP Definition
|
||||
default:managedTemplate: cn=NGP HGP Template,cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX
|
||||
|
@ -2,10 +2,23 @@
|
||||
# This is required for replication. The template entry will get
|
||||
# replicated but the plugin configuration will not.
|
||||
|
||||
dn: cn=UPG Definition,cn=Managed Entries,cn=plugins,cn=config
|
||||
dn: cn=UPG Template,cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX
|
||||
default:objectclass: mepTemplateEntry
|
||||
default:cn: UPG Template
|
||||
default:mepRDNAttr: cn
|
||||
default:mepStaticAttr: objectclass: posixgroup
|
||||
default:mepStaticAttr: objectclass: ipaobject
|
||||
default:mepStaticAttr: ipaUniqueId: autogenerate
|
||||
default:mepMappedAttr: cn: $$uid
|
||||
default:mepMappedAttr: gidNumber: $$uidNumber
|
||||
default:mepMappedAttr: description: User private group for $$uid
|
||||
|
||||
|
||||
dn: cn=UPG Definition,cn=Definitions,cn=Managed Entries,cn=etc,$SUFFIX
|
||||
default:objectclass: extensibleObject
|
||||
replace:originFilter:objectclass=posixAccount::(&(objectclass=posixAccount)(!(description=__no_upg__)))
|
||||
default:cn: UPG Definition
|
||||
default:originScope: cn=users,cn=accounts,$SUFFIX
|
||||
default:originFilter: (&(objectclass=posixAccount)(!(description=__no_upg__)))
|
||||
default:originFilter: objectclass=posixAccount
|
||||
default:managedBase: cn=groups,cn=accounts,$SUFFIX
|
||||
default:managedTemplate: cn=UPG Template,cn=etc,$SUFFIX
|
||||
default:managedTemplate: cn=UPG Template,cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX
|
||||
|
@ -1,2 +0,0 @@
|
||||
dn: cn=UPG Definition,cn=Managed Entries,cn=plugins,cn=config
|
||||
replace: originFilter:objectclass=posixAccount::(&(objectclass=posixAccount)(!(description=__no_upg__)))
|
@ -7,6 +7,7 @@ app_DATA = \
|
||||
10-RFC4876.update \
|
||||
10-config.update \
|
||||
10-sudo.update \
|
||||
19-managed-entries.update \
|
||||
20-aci.update \
|
||||
20-dna.update \
|
||||
20-host_nis_groups.update \
|
||||
@ -22,7 +23,6 @@ app_DATA = \
|
||||
50-lockout-policy.update \
|
||||
50-groupuuid.update \
|
||||
50-hbacservice.update \
|
||||
50-suppress-upg.update \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
|
@ -201,6 +201,7 @@ class DsInstance(service.Service):
|
||||
self.step("configuring ssl for ds instance", self.__enable_ssl)
|
||||
self.step("configuring certmap.conf", self.__certmap_conf)
|
||||
self.step("configure autobind for root", self.__root_autobind)
|
||||
self.step("configure new location for managed entries", self.__repoint_managed_entries)
|
||||
self.step("restarting directory server", self.__restart_instance)
|
||||
|
||||
def __common_post_setup(self):
|
||||
@ -237,6 +238,7 @@ class DsInstance(service.Service):
|
||||
self.step("adding default layout", self.__add_default_layout)
|
||||
self.step("adding delegation layout", self.__add_delegation_layout)
|
||||
self.step("adding replication acis", self.__add_replication_acis)
|
||||
self.step("creating container for managed entries", self.__managed_entries)
|
||||
self.step("configuring user private groups", self.__user_private_groups)
|
||||
self.step("configuring netgroups from hostgroups", self.__host_nis_groups)
|
||||
self.step("creating default Sudo bind user", self.__add_sudo_binduser)
|
||||
@ -277,8 +279,6 @@ class DsInstance(service.Service):
|
||||
# See LDIFs for automember configuration during replica install
|
||||
self.step("setting Auto Member configuration", self.__add_replica_automember_config)
|
||||
|
||||
# Managed Entries configuration is done via update files
|
||||
|
||||
self.__common_post_setup()
|
||||
|
||||
self.start_creation("Configuring directory server", 60)
|
||||
@ -485,6 +485,16 @@ class DsInstance(service.Service):
|
||||
def __config_lockout_module(self):
|
||||
self._ldap_mod("lockout-conf.ldif")
|
||||
|
||||
def __repoint_managed_entries(self):
|
||||
if not has_managed_entries(self.fqdn, self.dm_password):
|
||||
raise errors.NotFound(reason='Missing Managed Entries Plugin')
|
||||
self._ldap_mod("repoint-managed-entries.ldif", self.sub_dict)
|
||||
|
||||
def __managed_entries(self):
|
||||
if not has_managed_entries(self.fqdn, self.dm_password):
|
||||
raise errors.NotFound(reason='Missing Managed Entries Plugin')
|
||||
self._ldap_mod("managed-entries.ldif", self.sub_dict)
|
||||
|
||||
def __user_private_groups(self):
|
||||
if not has_managed_entries(self.fqdn, self.dm_password):
|
||||
raise errors.NotFound(reason='Missing Managed Entries Plugin')
|
||||
|
@ -440,6 +440,27 @@ def wait_for_open_ports(host, ports, timeout=0):
|
||||
else:
|
||||
raise e
|
||||
|
||||
def wait_for_open_socket(socket_name, timeout=0):
|
||||
"""
|
||||
Wait until the specified socket on the local host is open. Timeout
|
||||
in seconds may be specified to limit the wait.
|
||||
"""
|
||||
op_timeout = time.time() + timeout
|
||||
|
||||
while True:
|
||||
try:
|
||||
s = socket.socket(socket.AF_UNIX)
|
||||
s.connect(socket_name)
|
||||
s.close()
|
||||
break;
|
||||
except socket.error, e:
|
||||
if e.errno == 111: # 111: Connection refused
|
||||
if timeout and time.time() > op_timeout: # timeout exceeded
|
||||
raise e
|
||||
time.sleep(1)
|
||||
else:
|
||||
raise e
|
||||
|
||||
def resolve_host(host_name):
|
||||
try:
|
||||
addrinfos = socket.getaddrinfo(host_name, None,
|
||||
|
@ -26,6 +26,7 @@ UPDATES_DIR="/usr/share/ipa/updates/"
|
||||
|
||||
import sys
|
||||
from ipaserver.install import installutils
|
||||
from ipaserver.install import service
|
||||
from ipaserver import ipaldap
|
||||
from ipapython import entity, ipautil
|
||||
from ipalib import util
|
||||
@ -48,6 +49,24 @@ class BadSyntax(Exception):
|
||||
def __str__(self):
|
||||
return repr(self.value)
|
||||
|
||||
class IPARestart(service.Service):
|
||||
"""
|
||||
Restart the 389 DS service prior to performing deletions.
|
||||
"""
|
||||
def __init__(self, live_run=True):
|
||||
"""
|
||||
This class is present to provide ldapupdate the means to
|
||||
restart 389 DS to apply updates prior to performing deletes.
|
||||
"""
|
||||
|
||||
service.Service.__init__(self, "dirsrv")
|
||||
self.live_run = live_run
|
||||
|
||||
def create_instance(self):
|
||||
self.step("stopping directory server", self.stop)
|
||||
self.step("starting directory server", self.start)
|
||||
self.start_creation("Restarting IPA to initialize updates before performing deletes:")
|
||||
|
||||
class LDAPUpdate:
|
||||
def __init__(self, dm_password, sub_dict={}, live_run=True,
|
||||
online=True, ldapi=False):
|
||||
@ -64,7 +83,6 @@ class LDAPUpdate:
|
||||
self.modified = False
|
||||
self.online = online
|
||||
self.ldapi = ldapi
|
||||
|
||||
self.pw_name = pwd.getpwuid(os.geteuid()).pw_name
|
||||
|
||||
if sub_dict.get("REALM"):
|
||||
@ -418,6 +436,54 @@ class LDAPUpdate:
|
||||
|
||||
return self.conn.getList(dn, scope, searchfilter, sattrs)
|
||||
|
||||
def __update_managed_entries(self):
|
||||
"""Update and move legacy Managed Entry Plugins."""
|
||||
|
||||
suffix = ipautil.realm_to_suffix(self.realm)
|
||||
searchfilter = '(objectclass=*)'
|
||||
definitions_managed_entries = []
|
||||
old_template_container = 'cn=etc,%s' % suffix
|
||||
old_definition_container = 'cn=Managed Entries,cn=plugins,cn=config'
|
||||
new = 'cn=Managed Entries,cn=etc,%s' % suffix
|
||||
sub = ['cn=Definitions,', 'cn=Templates,']
|
||||
new_managed_entries = []
|
||||
old_templates = []
|
||||
template = None
|
||||
try:
|
||||
definitions_managed_entries = self.conn.getList(old_definition_container, ldap.SCOPE_ONELEVEL, searchfilter,[])
|
||||
except errors.NotFound, e:
|
||||
return new_managed_entries
|
||||
for entry in definitions_managed_entries:
|
||||
new_definition = {}
|
||||
definition_managed_entry_updates = {}
|
||||
definitions_managed_entries
|
||||
old_definition = {'dn': entry.dn, 'deleteentry': ['dn: %s' % entry.dn]}
|
||||
old_template = entry.getValue('managedtemplate')
|
||||
entry.setValues('managedtemplate', entry.getValue('managedtemplate').replace(old_template_container, sub[1] + new))
|
||||
new_definition['dn'] = entry.dn.replace(old_definition_container, sub[0] + new)
|
||||
new_definition['default'] = str(entry).strip().replace(': ', ':').split('\n')[1:]
|
||||
definition_managed_entry_updates[new_definition['dn']] = new_definition
|
||||
definition_managed_entry_updates[old_definition['dn']] = old_definition
|
||||
old_templates.append(old_template)
|
||||
new_managed_entries.append(definition_managed_entry_updates)
|
||||
for old_template in old_templates:
|
||||
try:
|
||||
template = self.conn.getEntry(old_template, ldap.SCOPE_BASE, searchfilter,[])
|
||||
new_template = {}
|
||||
template_managed_entry_updates = {}
|
||||
old_template = {'dn': template.dn, 'deleteentry': ['dn: %s' % template.dn]}
|
||||
new_template['dn'] = template.dn.replace(old_template_container, sub[1] + new)
|
||||
new_template['default'] = str(template).strip().replace(': ', ':').split('\n')[1:]
|
||||
template_managed_entry_updates[new_template['dn']] = new_template
|
||||
template_managed_entry_updates[old_template['dn']] = old_template
|
||||
new_managed_entries.append(template_managed_entry_updates)
|
||||
except errors.NotFound, e:
|
||||
pass
|
||||
if len(new_managed_entries) > 0:
|
||||
new_managed_entries.sort(reverse=True)
|
||||
|
||||
return new_managed_entries
|
||||
|
||||
def __apply_updates(self, updates, entry):
|
||||
"""updates is a list of changes to apply
|
||||
entry is the thing to apply them to
|
||||
@ -431,7 +497,6 @@ class LDAPUpdate:
|
||||
for u in updates:
|
||||
# We already do syntax-parsing so this is safe
|
||||
(utype, k, values) = u.split(':',2)
|
||||
|
||||
values = self.__parse_values(values)
|
||||
|
||||
e = entry.getValues(k)
|
||||
@ -440,7 +505,6 @@ class LDAPUpdate:
|
||||
e = []
|
||||
else:
|
||||
e = [e]
|
||||
|
||||
for v in values:
|
||||
if utype == 'remove':
|
||||
logging.debug("remove: '%s' from %s, current value %s", v, k, e)
|
||||
@ -629,6 +693,18 @@ class LDAPUpdate:
|
||||
and child in the wrong order.
|
||||
"""
|
||||
dn = updates['dn']
|
||||
deletes = updates.get('deleteentry', [])
|
||||
for d in deletes:
|
||||
try:
|
||||
if self.live_run:
|
||||
self.conn.deleteEntry(dn)
|
||||
self.modified = True
|
||||
except errors.NotFound, e:
|
||||
logging.info("Deleting non-existent entry %s", e)
|
||||
self.modified = True
|
||||
except errors.DatabaseError, e:
|
||||
logging.error("Delete failed: %s", e)
|
||||
|
||||
updates = updates.get('updates', [])
|
||||
for u in updates:
|
||||
# We already do syntax-parsing so this is safe
|
||||
@ -659,13 +735,7 @@ class LDAPUpdate:
|
||||
f.sort()
|
||||
return f
|
||||
|
||||
def update(self, files):
|
||||
"""Execute the update. files is a list of the update files to use.
|
||||
|
||||
returns True if anything was changed, otherwise False
|
||||
"""
|
||||
|
||||
try:
|
||||
def create_connection(self):
|
||||
if self.online:
|
||||
if self.ldapi:
|
||||
self.conn = ipaldap.IPAdmin(ldapi=True, realm=self.realm)
|
||||
@ -689,6 +759,15 @@ class LDAPUpdate:
|
||||
raise RuntimeError('%s' % e.args[0].get('info', '').strip())
|
||||
else:
|
||||
raise RuntimeError("Offline updates are not supported.")
|
||||
|
||||
def update(self, files):
|
||||
"""Execute the update. files is a list of the update files to use.
|
||||
|
||||
returns True if anything was changed, otherwise False
|
||||
"""
|
||||
|
||||
try:
|
||||
self.create_connection()
|
||||
all_updates = {}
|
||||
dn_list = {}
|
||||
for f in files:
|
||||
@ -701,6 +780,20 @@ class LDAPUpdate:
|
||||
|
||||
(all_updates, dn_list) = self.parse_update_file(data, all_updates, dn_list)
|
||||
|
||||
# Process Managed Entry Updates
|
||||
managed_entries = self.__update_managed_entries()
|
||||
if managed_entries:
|
||||
managed_entry_dns = [[m[entry]['dn'] for entry in m] for m in managed_entries]
|
||||
l = len(dn_list.keys())
|
||||
|
||||
# Add Managed Entry DN's to the DN List
|
||||
for dn in managed_entry_dns:
|
||||
l+=1
|
||||
dn_list[l] = dn
|
||||
# Add Managed Entry Updates to All Updates List
|
||||
for managed_entry in managed_entries:
|
||||
all_updates.update(managed_entry)
|
||||
|
||||
# For adds and updates we want to apply updates from shortest
|
||||
# to greatest length of the DN. For deletes we want the reverse.
|
||||
sortedkeys = dn_list.keys()
|
||||
@ -709,6 +802,13 @@ class LDAPUpdate:
|
||||
for dn in dn_list[k]:
|
||||
self.__update_record(all_updates[dn])
|
||||
|
||||
# Restart 389 Directory Service
|
||||
socket_name = '/var/run/slapd-%s.socket' % self.realm.replace('.','-')
|
||||
iparestart = IPARestart()
|
||||
iparestart.create_instance()
|
||||
installutils.wait_for_open_socket(socket_name)
|
||||
self.create_connection()
|
||||
|
||||
sortedkeys.reverse()
|
||||
for k in sortedkeys:
|
||||
for dn in dn_list[k]:
|
||||
|
Loading…
Reference in New Issue
Block a user