mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Remove common entries when deleting a master.
Fixes: https://fedorahosted.org/freeipa/ticket/550
This commit is contained in:
@@ -23,6 +23,11 @@ changetype: modify
|
||||
add: aci
|
||||
aci: (targetfilter = "(objectClass=ipaGuiConfig)")(targetattr != "aci")(version 3.0;acl "Admins can change GUI config"; allow (read, search, compare, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)
|
||||
|
||||
dn: cn=ipa,cn=etc,$SUFFIX
|
||||
changetype: modify
|
||||
add: aci
|
||||
aci: (targetfilter = "(|(objectClass=ipaConfigObject)(dnahostname=*))")(version 3.0;acl "Admins can change GUI config"; allow (delete) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)
|
||||
|
||||
dn: cn=accounts,$SUFFIX
|
||||
changetype: modify
|
||||
add: aci
|
||||
|
||||
@@ -76,16 +76,6 @@ def get_suffix():
|
||||
suffix = l.normalize_dn(util.realm_to_suffix(get_realm_name()))
|
||||
return suffix
|
||||
|
||||
def get_host_name():
|
||||
hostname = installutils.get_fqdn()
|
||||
try:
|
||||
installutils.verify_fqdn(hostname)
|
||||
except RuntimeError, e:
|
||||
logging.error(str(e))
|
||||
sys.exit(1)
|
||||
|
||||
return hostname
|
||||
|
||||
def test_connection(host):
|
||||
"""
|
||||
Make a GSSAPI connection to the remote LDAP server to test out credentials.
|
||||
@@ -114,41 +104,55 @@ def list_masters(replman, verbose):
|
||||
print " last init ended: %s" % str(ipautil.parse_generalized_time(entry.nsds5replicalastinitend))
|
||||
print " last update status: %s" % entry.nsds5replicalastupdatestatus
|
||||
print " last update ended: %s" % str(ipautil.parse_generalized_time(entry.nsds5replicalastupdateend))
|
||||
|
||||
|
||||
def del_master(replman, hostname, force=False):
|
||||
has_repl_agreement = True
|
||||
try:
|
||||
t = replman.get_agreement_type(hostname)
|
||||
except ldap.NO_SUCH_OBJECT:
|
||||
print "No replication agreement found for '%s'" % hostname
|
||||
return
|
||||
if force:
|
||||
has_repl_agreement = False
|
||||
else:
|
||||
return
|
||||
except errors.NotFound:
|
||||
print "No replication agreement found for '%s'" % hostname
|
||||
return
|
||||
if force:
|
||||
has_repl_agreement = False
|
||||
else:
|
||||
return
|
||||
|
||||
# Delete the remote agreement first
|
||||
if t == replication.IPA_REPLICA:
|
||||
failed = False
|
||||
try:
|
||||
other_replman = replication.ReplicationManager(hostname, replman.dirman_passwd)
|
||||
other_replman.suffix = get_suffix()
|
||||
other_replman.delete_agreement(replman.conn.host)
|
||||
except ldap.LDAPError, e:
|
||||
desc = e.args[0]['desc'].strip()
|
||||
info = e.args[0].get('info', '').strip()
|
||||
print "Unable to remove agreement on %s: %s: %s" % (hostname, desc, info)
|
||||
failed = True
|
||||
except Exception, e:
|
||||
print "Unable to remove agreement on %s: %s" % (hostname, str(e))
|
||||
failed = True
|
||||
if has_repl_agreement:
|
||||
# Delete the remote agreement first
|
||||
if t == replication.IPA_REPLICA:
|
||||
failed = False
|
||||
try:
|
||||
other_replman = replication.ReplicationManager(hostname, replman.dirman_passwd)
|
||||
other_replman.suffix = get_suffix()
|
||||
other_replman.delete_agreement(replman.conn.host)
|
||||
except ldap.LDAPError, e:
|
||||
desc = e.args[0]['desc'].strip()
|
||||
info = e.args[0].get('info', '').strip()
|
||||
print "Unable to remove agreement on %s: %s: %s" % (hostname, desc, info)
|
||||
failed = True
|
||||
except Exception, e:
|
||||
print "Unable to remove agreement on %s: %s" % (hostname, str(e))
|
||||
failed = True
|
||||
|
||||
if failed:
|
||||
if force:
|
||||
print "Forcing removal on local server"
|
||||
else:
|
||||
return
|
||||
if failed:
|
||||
if force:
|
||||
print "Forcing removal on local server"
|
||||
else:
|
||||
return
|
||||
|
||||
# Delete the local agreement
|
||||
replman.delete_agreement(hostname)
|
||||
# Delete the local agreement
|
||||
replman.delete_agreement(hostname)
|
||||
|
||||
try:
|
||||
replman.replica_cleanup(hostname, get_realm_name(), force=True)
|
||||
except Exception, e:
|
||||
print "Failed to cleanup %s entries: %s" % (hostname, str(e))
|
||||
print "You may need to manually remove them from the tree"
|
||||
|
||||
def add_master(replman, hostname, options):
|
||||
other_args = {}
|
||||
@@ -210,13 +214,13 @@ def synch_master(replman, hostname):
|
||||
|
||||
def main():
|
||||
options, args = parse_options()
|
||||
|
||||
|
||||
dirman_passwd = None
|
||||
|
||||
if options.host:
|
||||
host = options.host
|
||||
else:
|
||||
host = get_host_name()
|
||||
host = installutils.get_fqdn()
|
||||
|
||||
if options.dirman_passwd:
|
||||
dirman_passwd = options.dirman_passwd
|
||||
|
||||
@@ -573,3 +573,76 @@ class ReplicationManager:
|
||||
return WINSYNC
|
||||
|
||||
return IPA_REPLICA
|
||||
|
||||
def replica_cleanup(self, replica, realm, force=False):
|
||||
|
||||
err = None
|
||||
|
||||
if replica == self.hostname:
|
||||
raise RuntimeError("Can't cleanup self")
|
||||
|
||||
if not self.suffix or self.suffix == "":
|
||||
self.suffix = util.realm_to_suffix(realm)
|
||||
self.suffix = ipaldap.IPAdmin.normalizeDN(self.suffix)
|
||||
|
||||
# delete master kerberos key and all its svc principals
|
||||
try:
|
||||
filter='(krbprincipalname=*/%s@%s)' % (replica, realm)
|
||||
entries = self.conn.search_s(self.suffix, ldap.SCOPE_SUBTREE,
|
||||
filterstr=filter)
|
||||
if len(entries) != 0:
|
||||
dnset = self.conn.get_dns_sorted_by_length(entries,
|
||||
reverse=True)
|
||||
for dns in dnset:
|
||||
for dn in dns:
|
||||
self.conn.deleteEntry(dn)
|
||||
except ldap.NO_SUCH_OBJECT:
|
||||
pass
|
||||
except errors.NotFound:
|
||||
pass
|
||||
except Exception, e:
|
||||
if not force:
|
||||
raise e
|
||||
else:
|
||||
err = e
|
||||
|
||||
# delete master entry with all active services
|
||||
try:
|
||||
dn = 'cn=%s,cn=masters,cn=ipa,cn=etc,%s' % (replica, self.suffix)
|
||||
entries = self.conn.search_s(dn, ldap.SCOPE_SUBTREE)
|
||||
if len(entries) != 0:
|
||||
dnset = self.conn.get_dns_sorted_by_length(entries,
|
||||
reverse=True)
|
||||
for dns in dnset:
|
||||
for dn in dns:
|
||||
self.conn.deleteEntry(dn)
|
||||
except ldap.NO_SUCH_OBJECT:
|
||||
pass
|
||||
except errors.NotFound:
|
||||
pass
|
||||
except Exception, e:
|
||||
if not force:
|
||||
raise e
|
||||
elif not err:
|
||||
err = e
|
||||
|
||||
try:
|
||||
basedn = 'cn=etc,%s' % self.suffix
|
||||
filter = '(dnaHostname=%s)' % replica
|
||||
entries = self.conn.search_s(basedn, ldap.SCOPE_SUBTREE,
|
||||
filterstr=filter)
|
||||
if len(entries) != 0:
|
||||
for e in entries:
|
||||
self.conn.deleteEntry(e.dn)
|
||||
except ldap.NO_SUCH_OBJECT:
|
||||
pass
|
||||
except errors.NotFound:
|
||||
pass
|
||||
except Exception, e:
|
||||
if force and err:
|
||||
raise err
|
||||
else:
|
||||
raise e
|
||||
|
||||
if err:
|
||||
raise err
|
||||
|
||||
@@ -640,6 +640,35 @@ class IPAdmin(SimpleLDAPObject):
|
||||
return ",".join(ary)
|
||||
normalizeDN = staticmethod(normalizeDN)
|
||||
|
||||
def get_dns_sorted_by_length(self, entries, reverse=False):
|
||||
"""
|
||||
Sorts a list of entries [(dn, entry_attrs)] based on their DN.
|
||||
Entries within the same node are not sorted in any meaningful way.
|
||||
If Reverse is set to True, leaf entries are returned first. This is
|
||||
useful to perform recursive deletes where you need to delete entries
|
||||
starting from the leafs and go up to delete nodes only when all its
|
||||
leafs are removed.
|
||||
|
||||
Returns a "sorted" dict keyed by dn lengths and corresponding list
|
||||
of DNs.
|
||||
{'1': [dn1, dn2, dn3], '2': [dn4, dn5], ..}
|
||||
"""
|
||||
|
||||
res = dict()
|
||||
|
||||
for e in entries:
|
||||
sdn = ldap.dn.str2dn(e.dn)
|
||||
l = len(sdn)
|
||||
if not l in res:
|
||||
res[l] = []
|
||||
res[l].append(e.dn)
|
||||
|
||||
keys = res.keys()
|
||||
keys.sort(reverse=reverse)
|
||||
|
||||
return map(res.get, keys)
|
||||
|
||||
|
||||
def notfound(args):
|
||||
"""Return a string suitable for displaying as an error when a
|
||||
search returns no results.
|
||||
|
||||
@@ -506,9 +506,10 @@ class ldap2(CrudBackend, Encoder):
|
||||
scope=_ldap.SCOPE_SUBTREE, time_limit=None, size_limit=None,
|
||||
normalize=True):
|
||||
"""
|
||||
Return a list of entries [(dn, entry_attrs)] matching specified
|
||||
search parameters followed by truncated flag. If the truncated flag is
|
||||
True, search hit a server limit and its results are incomplete.
|
||||
Return a list of entries and indication of whteher the results where
|
||||
truncated ([(dn, entry_attrs)], truncated) matching specified search
|
||||
parameters followed by truncated flag. If the truncated flag is True,
|
||||
search hit a server limit and its results are incomplete.
|
||||
|
||||
Keyword arguments:
|
||||
attrs_list -- list of attributes to return, all if None (default None)
|
||||
|
||||
Reference in New Issue
Block a user