summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--install/share/default-aci.ldif5
-rwxr-xr-xinstall/tools/ipa-replica-manage78
-rw-r--r--ipaserver/install/replication.py73
-rw-r--r--ipaserver/ipaldap.py29
-rw-r--r--ipaserver/plugins/ldap2.py7
5 files changed, 152 insertions, 40 deletions
diff --git a/install/share/default-aci.ldif b/install/share/default-aci.ldif
index d0dfa23d7..159cb07bd 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 33c68c8f5..135b346bc 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 f3e007c6e..fbe4d2f76 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 f7e0f3dd4..b1f9f40c4 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 89c499f02..06a940773 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)