summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Crittenden <rcritten@redhat.com>2012-09-14 15:03:12 -0400
committerMartin Kosek <mkosek@redhat.com>2012-09-17 17:57:27 +0200
commitf695f79748ffd0782990ec752ed140648347d632 (patch)
treeffe0527394005c92776d66736494e3362cc29442
parentc9c55a2845fd8471bc609a23f5a32d252f7df04c (diff)
downloadfreeipa-f695f79748ffd0782990ec752ed140648347d632.tar.gz
freeipa-f695f79748ffd0782990ec752ed140648347d632.tar.xz
freeipa-f695f79748ffd0782990ec752ed140648347d632.zip
When deleting a master, try to prevent orphaning other servers.
If you have a replication topology like A <-> B <-> C and you try to delete server B that will leave A and C orphaned. It may also prevent re-installation of a new master on B because the cn=masters entry for it probably still exists on at least one of the other masters. Check on each master that it connects to to ensure that it isn't the last link, and fail if it is. If any of the masters are not up then warn that this could be a bad thing but let the user continue if they want. Add a new option to the del command, --cleanup, which runs the replica_cleanup() routine to completely clean up references to a master. https://fedorahosted.org/freeipa/ticket/2797
-rwxr-xr-xinstall/tools/ipa-replica-manage85
-rw-r--r--install/tools/man/ipa-replica-manage.114
2 files changed, 98 insertions, 1 deletions
diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage
index dcd44f3c7..897d11768 100755
--- a/install/tools/ipa-replica-manage
+++ b/install/tools/ipa-replica-manage
@@ -72,6 +72,8 @@ def parse_options():
help="provide additional information")
parser.add_option("-f", "--force", dest="force", action="store_true", default=False,
help="ignore some types of errors")
+ parser.add_option("-c", "--cleanup", dest="cleanup", action="store_true", default=False,
+ help="DANGER: clean up references to a ghost master")
parser.add_option("--binddn", dest="binddn", default=None, type="dn",
help="Bind DN to use with remote server")
parser.add_option("--bindpw", dest="bindpw", default=None,
@@ -463,9 +465,53 @@ def list_clean_ruv(realm, host, dirman_passwd, verbose):
print str(dn)
print entry.getValue('nstasklog')
+def check_last_link(delrepl, realm, dirman_passwd, force):
+ """
+ We don't want to orphan a server when deleting another one. If you have
+ a topology that looks like this:
+
+ A B
+ | |
+ | |
+ | |
+ C---- D
+
+ If we try to delete host D it will orphan host B.
+
+ What we need to do is if the master being deleted has only a single
+ agreement, connect to that master and make sure it has agreements with
+ more than just this master.
+
+ @delrepl: a ReplicationManager object of the master being deleted
+
+ returns: hostname of orphaned server or None
+ """
+ replica_names = delrepl.find_ipa_replication_agreements()
+
+ orphaned = []
+ # Connect to each remote server and see what agreements it has
+ for replica in replica_names:
+ try:
+ repl = replication.ReplicationManager(realm, replica, dirman_passwd)
+ except ldap.SERVER_DOWN, e:
+ print "Unable to validate that '%s' will not be orphaned." % replica
+
+ if not force and not ipautil.user_input("Continue to delete?", False):
+ sys.exit("Aborted")
+ continue
+ names = repl.find_ipa_replication_agreements()
+ if len(names) == 1 and names[0] == delrepl.hostname:
+ orphaned.append(replica)
+
+ if len(orphaned):
+ return ', '.join(orphaned)
+ else:
+ return None
+
def del_master(realm, hostname, options):
force_del = False
+ delrepl = None
# 1. Connect to the local server
try:
@@ -478,7 +524,21 @@ def del_master(realm, hostname, options):
# 2. Ensure we have an agreement with the master
agreement = thisrepl.get_replication_agreement(hostname)
if agreement is None:
- sys.exit("'%s' has no replication agreement for '%s'" % (options.host, hostname))
+ if options.cleanup:
+ """
+ We have no agreement with the current master, so this is a
+ candidate for cleanup. This is VERY dangerous to do because it
+ removes that master from the list of masters. If the master
+ were to try to come back online it wouldn't work at all.
+ """
+ print "Cleaning a master is irreversible."
+ print "This should not normally be require, so use cautiously."
+ if not ipautil.user_input("Continue to clean master?", False):
+ sys.exit("Cleanup aborted")
+ thisrepl.replica_cleanup(hostname, realm, force=True)
+ sys.exit(0)
+ else:
+ sys.exit("'%s' has no replication agreement for '%s'" % (options.host, hostname))
# 3. If an IPA agreement connect to the master to be removed.
repltype = thisrepl.get_agreement_type(hostname)
@@ -516,6 +576,29 @@ def del_master(realm, hostname, options):
if not ipautil.user_input("Continue to delete?", False):
sys.exit("Deletion aborted")
+ # Check for orphans if the remote server is up.
+ if delrepl and not winsync:
+ masters_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), ipautil.realm_to_suffix(realm))
+ try:
+ masters = delrepl.conn.getList(masters_dn, ldap.SCOPE_ONELEVEL)
+ except Exception, e:
+ masters = []
+ print "Failed to read masters data from '%s': %s" % (delrepl.hostname, convert_error(e))
+ print "Skipping calculation to determine if one or more masters would be orphaned."
+ if not options.force:
+ sys.exit(1)
+
+ # This only applies if we have more than 2 IPA servers, otherwise
+ # there is no chance of an orphan.
+ if len(masters) > 2:
+ orphaned_server = check_last_link(delrepl, realm, options.dirman_passwd, options.force)
+ if orphaned_server is not None:
+ print "Deleting this server will orphan '%s'. " % orphaned_server
+ print "You will need to reconfigure your replication topology to delete this server."
+ sys.exit(1)
+ else:
+ print "Skipping calculation to determine if one or more masters would be orphaned."
+
# Save the RID value before we start deleting
if repltype == replication.IPA_REPLICA:
rid = get_rid_by_host(realm, options.host, hostname, options.dirman_passwd)
diff --git a/install/tools/man/ipa-replica-manage.1 b/install/tools/man/ipa-replica-manage.1
index 98d70c6fd..b750f8fc9 100644
--- a/install/tools/man/ipa-replica-manage.1
+++ b/install/tools/man/ipa-replica-manage.1
@@ -65,6 +65,14 @@ Each IPA master server has a unique replication ID. This ID is used by 389\-ds\-
When a master is removed, all other masters need to remove its replication ID from the list of masters. Normally this occurs automatically when a master is deleted with ipa\-replica\-manage. If one or more masters was down or unreachable when ipa\-replica\-manage was executed then this replica ID may still exist. The clean\-ruv command may be used to clean up an unused replication ID.
.TP
\fBNOTE\fR: clean\-ruv is \fBVERY DANGEROUS\fR. Execution against the wrong replication ID can result in inconsistent data on that master. The master should be re\-initialized from another if this happens.
+.TP
+The replication topology is examined when a master is deleted and will attempt to prevent a master from being orphaned. For example, if your topology is A <\-> B <\-> C and you attempt to delete master B it will fail because that would leave masters and A and C orphaned.
+.TP
+The list of masters is stored in cn=masters,cn=ipa,cn=etc,dc=example,dc=com. This should be cleaned up automatically when a master is deleted. If it occurs that you have deleted the master and all the agreements but these entries still exist then you will not be able to re\-install IPA on it, the installation will fail with:
+.TP
+An IPA master host cannot be deleted or disabled using standard commands (host\-del, for example).
+.TP
+An orphaned master may be cleaned up using the del directive with the \-\-cleanup option. This will remove the entries from cn=masters,cn=ipa,cn=etc that otherwise prevent host\-del from working, its dna profile, s4u2proxy configuration, service principals and remove it from the default DUA profile defaultServerList.
.SH "OPTIONS"
.TP
\fB\-H\fR \fIHOST\fR, \fB\-\-host\fR=\fIHOST\fR
@@ -81,6 +89,9 @@ Provide additional information
\fB\-f\fR, \fB\-\-force\fR
Ignore some types of errors, don't prompt when deleting a master
.TP
+\fB\-c\fR, \fB\-\-cleanup\fR
+When deleting a master with the --force flag, remove leftover references to an already deleted master.
+.TP
\fB\-\-binddn\fR=\fIADMIN_DN\fR
Bind DN to use with remote server (default is cn=Directory Manager) \- Be careful to quote this value on the command line
.TP
@@ -135,6 +146,9 @@ List the replication IDs in use:
# ipa\-replica\-manage list\-ruv
srv1.example.com:389: 7
srv2.example.com:389: 4
+.TP
+Remove references to an orphaned and deleted master:
+ # ipa\-replica\-manage del \-\-force \-\-cleanup master.example.com
.SH "WINSYNC"
Creating a Windows AD Synchronization agreement is similar to creating an IPA replication agreement, there are just a couple of extra steps.