summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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.