diff options
author | Simo Sorce <ssorce@redhat.com> | 2010-12-10 09:48:06 -0500 |
---|---|---|
committer | Simo Sorce <ssorce@redhat.com> | 2010-12-21 17:28:13 -0500 |
commit | 1cf67fe8503981b8aca985043bc5a8cd2799a365 (patch) | |
tree | b36aa7612450d407d9737b5d3600d3b987b1c800 | |
parent | 5884fdf0f864d67fe7ee48d29f3c023882bc2891 (diff) | |
download | freeipa-1cf67fe8503981b8aca985043bc5a8cd2799a365.tar.gz freeipa-1cf67fe8503981b8aca985043bc5a8cd2799a365.tar.xz freeipa-1cf67fe8503981b8aca985043bc5a8cd2799a365.zip |
Remove common entries when deleting a master.
Fixes: https://fedorahosted.org/freeipa/ticket/550
-rw-r--r-- | install/share/default-aci.ldif | 5 | ||||
-rwxr-xr-x | install/tools/ipa-replica-manage | 78 | ||||
-rw-r--r-- | ipaserver/install/replication.py | 73 | ||||
-rw-r--r-- | ipaserver/ipaldap.py | 29 | ||||
-rw-r--r-- | ipaserver/plugins/ldap2.py | 7 |
5 files changed, 152 insertions, 40 deletions
diff --git a/install/share/default-aci.ldif b/install/share/default-aci.ldif index d0dfa23d..159cb07b 100644 --- a/install/share/default-aci.ldif +++ b/install/share/default-aci.ldif @@ -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 diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage index 33c68c8f..135b346b 100755 --- a/install/tools/ipa-replica-manage +++ b/install/tools/ipa-replica-manage @@ -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 diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py index f3e007c6..fbe4d2f7 100644 --- a/ipaserver/install/replication.py +++ b/ipaserver/install/replication.py @@ -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 diff --git a/ipaserver/ipaldap.py b/ipaserver/ipaldap.py index f7e0f3dd..b1f9f40c 100644 --- a/ipaserver/ipaldap.py +++ b/ipaserver/ipaldap.py @@ -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. diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py index 89c499f0..06a94077 100644 --- a/ipaserver/plugins/ldap2.py +++ b/ipaserver/plugins/ldap2.py @@ -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) |