summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Vobornik <pvoborni@redhat.com>2015-06-26 18:09:19 +0200
committerTomas Babej <tbabej@redhat.com>2015-07-03 08:47:23 +0200
commit6be7d41ba16367aad8be26e0cd071846533c1783 (patch)
tree2c76a01e661eb0c25625f481cd6652e8a562e038
parent76eea85701af80dc972c47e14aecc7a688b9c846 (diff)
downloadfreeipa-6be7d41ba16367aad8be26e0cd071846533c1783.tar.gz
freeipa-6be7d41ba16367aad8be26e0cd071846533c1783.tar.xz
freeipa-6be7d41ba16367aad8be26e0cd071846533c1783.zip
ipa-replica-manage del: relax segment deletement check if topology is disconnected
https://fedorahosted.org/freeipa/ticket/5072 Reviewed-By: David Kupka <dkupka@redhat.com>
-rwxr-xr-xinstall/tools/ipa-replica-manage38
-rw-r--r--ipapython/graph.py11
2 files changed, 43 insertions, 6 deletions
diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage
index 2239eb0b8..5ba855270 100755
--- a/install/tools/ipa-replica-manage
+++ b/install/tools/ipa-replica-manage
@@ -569,7 +569,8 @@ def check_last_link_managed(api, masters, hostname, force):
"""
Check if 'hostname' is safe to delete.
- :returns: list of errors after future deletion
+ :returns: tuple with lists of current and future errors in topology
+ (current_errors, new_errors)
"""
segments = api.Command.topologysegment_find(u'realm', sizelimit=0).get('result')
@@ -584,7 +585,11 @@ def check_last_link_managed(api, masters, hostname, force):
print_connect_errors(orig_errors)
# after removal
- graph.remove_vertex(hostname)
+ try:
+ graph.remove_vertex(hostname)
+ except ValueError:
+ pass # ignore already deleted master, continue to clean
+
new_errors = get_topology_connection_errors(graph)
if new_errors:
print "WARNING: Topology after removal of %s will be disconnected." % hostname
@@ -599,7 +604,7 @@ def check_last_link_managed(api, masters, hostname, force):
else:
print "Forcing removal of %s" % hostname
- return new_errors
+ return (orig_errors, new_errors)
def print_connect_errors(errors):
for error in errors:
@@ -715,7 +720,7 @@ def del_master_managed(realm, hostname, options):
masters = api.Command.server_find('', sizelimit=0)['result']
# 3. Check topology
- check_last_link_managed(api, masters, hostname, options.force)
+ topo_errors = check_last_link_managed(api, masters, hostname, options.force)
# 4. Check that we are not leaving the installation without CA and/or DNS
# And pick new CA master.
@@ -741,11 +746,36 @@ def del_master_managed(realm, hostname, options):
# 7. Clean RUV for the deleted master
# Wait for topology plugin to delete segments
i = 0
+ m_cns = [m['cn'][0] for m in masters] # masters before removal
while True:
left = api.Command.topologysegment_find(
u'realm', iparepltoposegmentleftnode=hostname_u, sizelimit=0)['result']
right = api.Command.topologysegment_find(
u'realm', iparepltoposegmentrightnode=hostname_u, sizelimit=0)['result']
+
+ # If the server was already deleted, we can expect that all removals
+ # had been done in previous run and dangling segments were not deleted.
+ if hostname not in m_cns:
+ print "Skipping replication agreement deletion check"
+ break
+
+ # Relax check if topology was or is disconnected. Disconnected topology
+ # can contain segments with already deleted servers. Check only if
+ # segments of servers, which can contact this server, and the deleted
+ # server were removed.
+ # This code should handle a case where there was a topology with
+ # a central node(B): A <-> B <-> C, where A is current server.
+ # After removal of B, topology will be disconnected and removal of
+ # segment B <-> C won't be replicated back to server A, therefore
+ # presence of the segment has to be ignored.
+ if topo_errors[0] or topo_errors[1]:
+ # use errors after deletion because we don't care if some server
+ # can't contact the deleted one
+ cant_contact_me = [e[0] for e in topo_errors[1] if options.host in e[2]]
+ can_contact_me = set(m_cns) - set(cant_contact_me)
+ left = [s for s in left if s['iparepltoposegmentrightnode'][0] in can_contact_me]
+ right = [s for s in right if s['iparepltoposegmentleftnode'][0] in can_contact_me]
+
if not left and not right:
print "Agreements deleted"
break
diff --git a/ipapython/graph.py b/ipapython/graph.py
index 20b612548..e27249466 100644
--- a/ipapython/graph.py
+++ b/ipapython/graph.py
@@ -29,11 +29,18 @@ class Graph():
self._adj[tail].append(head)
def remove_edge(self, tail, head):
- self.edges.remove((tail, head))
+ try:
+ self.edges.remove((tail, head))
+ except KeyError:
+ raise ValueError(
+ "graph does not contain edge: (%s, %s)" % (tail, head))
self._adj[tail].remove(head)
def remove_vertex(self, vertex):
- self.vertices.remove(vertex)
+ try:
+ self.vertices.remove(vertex)
+ except KeyError:
+ raise ValueError("graph does not contain vertex: %s" % vertex)
# delete _adjacencies
del self._adj[vertex]