summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xinstall/tools/ipa-csreplica-manage93
-rw-r--r--ipaserver/install/replication.py24
2 files changed, 83 insertions, 34 deletions
diff --git a/install/tools/ipa-csreplica-manage b/install/tools/ipa-csreplica-manage
index 55edd1a23..db368c6fa 100755
--- a/install/tools/ipa-csreplica-manage
+++ b/install/tools/ipa-csreplica-manage
@@ -34,7 +34,6 @@ from ipalib import api, errors, util
from ipapython.dn import DN
CACERT = "/etc/ipa/ca.crt"
-PORT = dogtag.install_constants.DS_PORT
# dict of command name and tuples of min/max num of args needed
commands = {
@@ -60,10 +59,48 @@ def convert_error(exc):
else:
return str(exc)
+
+def get_cs_replication_manager(realm, host, dirman_passwd):
+ """Get a CSReplicationManager for a remote host
+
+ Detects if the host has a merged database, connects to appropriate port.
+ """
+
+ # Try merged database port first. If it has the ipaca tree, return
+ # corresponding replication manager
+ # If we can't connect to it at all, we're not dealing with an IPA master
+ # anyway; let the exception propagate up
+ # Fall back to the old PKI-only DS port. Check that it has the ipaca tree
+ # (IPA with merged DB theoretically leaves port 7389 free for anyone).
+ # If it doesn't, raise exception.
+ ports = [
+ dogtag.Dogtag10Constants.DS_PORT,
+ dogtag.Dogtag9Constants.DS_PORT,
+ ]
+ for port in ports:
+ root_logger.debug('Looking for PKI DS on %s:%s' % (host, port))
+ replication_manager = CSReplicationManager(
+ realm, host, dirman_passwd, port)
+ if replication_manager.has_ipaca():
+ root_logger.debug('PKI DS found on %s:%s' % (host, port))
+ return replication_manager
+ else:
+ root_logger.debug('PKI tree not found on %s:%s' % (host, port))
+ sys.exit('Cannot reach PKI DS at %s on ports %s' % (host, ports))
+
+
class CSReplicationManager(replication.ReplicationManager):
+ """ReplicationManager specific to CA agreements
- def __init__(self, realm, hostname, dirman_passwd, port=PORT, starttls=True):
- super(CSReplicationManager, self).__init__(realm, hostname, dirman_passwd, port, starttls)
+ Note that in most cases we don't know if we're connecting to an old-style
+ separate PKI DS, or to a host with a merged DB.
+ Use the get_cs_replication_manager function to determine this and return
+ an appropriate CSReplicationManager.
+ """
+
+ def __init__(self, realm, hostname, dirman_passwd, port):
+ super(CSReplicationManager, self).__init__(
+ realm, hostname, dirman_passwd, port, starttls=True)
self.suffix = DN(('o', 'ipaca'))
self.hostnames = [] # set before calling or agreement_dn() will fail
@@ -106,17 +143,26 @@ class CSReplicationManager(replication.ReplicationManager):
raise errors.NotFound(reason='No agreement found for %s' % hostname)
- def delete_referral(self, hostname):
+ def delete_referral(self, hostname, port):
dn = DN(('cn', self.suffix), ('cn', 'mapping tree'), ('cn', 'config'))
- # TODO: should we detect proto/port somehow ?
+ # TODO: should we detect proto somehow ?
mod = [(ldap.MOD_DELETE, 'nsslapd-referral',
- 'ldap://%s/%s' % (ipautil.format_netloc(hostname, PORT), self.suffix))]
+ 'ldap://%s/%s' % (ipautil.format_netloc(hostname, port), self.suffix))]
try:
self.conn.modify_s(dn, mod)
except Exception, e:
root_logger.debug("Failed to remove referral value: %s" % convert_error(e))
+ def has_ipaca(self):
+ try:
+ entry = self.conn.getEntry(self.suffix, ldap.SCOPE_BASE)
+ except errors.NotFound:
+ return False
+ else:
+ return True
+
+
def parse_options():
from optparse import OptionParser
@@ -185,7 +231,7 @@ def list_replicas(realm, host, replica, dirman_passwd, verbose):
print '%s: %s' % (k, p[0])
return
- repl = CSReplicationManager(realm, replica, dirman_passwd, PORT, True)
+ repl = get_cs_replication_manager(realm, replica, dirman_passwd)
entries = repl.find_replication_agreements()
for entry in entries:
@@ -202,7 +248,7 @@ def del_link(realm, replica1, replica2, dirman_passwd, force=False):
repl2 = None
try:
- repl1 = CSReplicationManager(realm, replica1, dirman_passwd, PORT, True)
+ repl1 = get_cs_replication_manager(realm, replica1, dirman_passwd)
repl1.hostnames = [replica1, replica2]
@@ -221,12 +267,13 @@ def del_link(realm, replica1, replica2, dirman_passwd, force=False):
repl1.hostnames = [replica1, replica2]
except ldap.SERVER_DOWN, e:
- sys.exit("Unable to connect to %s: %s" % (ipautil.format_netloc(replica1, PORT), convert_error(e)))
+ sys.exit("Unable to connect to %s: %s" % (replica1, convert_error(e)))
except Exception, e:
sys.exit("Failed to get data from '%s': %s" % (replica1, convert_error(e)))
try:
- repl2 = CSReplicationManager(realm, replica2, dirman_passwd, PORT, True)
+ repl2 = get_cs_replication_manager(realm, replica2, dirman_passwd)
+
repl2.hostnames = [replica1, replica2]
repl_list = repl2.find_replication_agreements()
@@ -271,7 +318,7 @@ def del_link(realm, replica1, replica2, dirman_passwd, force=False):
failed = False
try:
repl2.delete_agreement(replica1, replica2_dn)
- repl2.delete_referral(replica1)
+ repl2.delete_referral(replica1, repl1.port)
except Exception, e:
print "Unable to remove agreement on %s: %s" % (replica2, convert_error(e))
failed = True
@@ -286,7 +333,7 @@ def del_link(realm, replica1, replica2, dirman_passwd, force=False):
print "Forcing removal on '%s'" % replica1
repl1.delete_agreement(replica2, replica1_dn)
- repl1.delete_referral(replica2)
+ repl1.delete_referral(replica2, repl2.port)
print "Deleted replication agreement from '%s' to '%s'" % (replica1, replica2)
@@ -298,8 +345,8 @@ def del_master(realm, hostname, options):
# 1. Connect to the local dogtag DS server
try:
- thisrepl = CSReplicationManager(realm, options.host,
- options.dirman_passwd)
+ thisrepl = get_cs_replication_manager(realm, options.host,
+ options.dirman_passwd)
except Exception, e:
sys.exit("Failed to connect to server %s: %s" % (options.host, convert_error(e)))
@@ -309,7 +356,8 @@ def del_master(realm, hostname, options):
# 3. Connect to the dogtag DS to be removed.
try:
- delrepl = CSReplicationManager(realm, hostname, options.dirman_passwd)
+ delrepl = get_cs_replication_manager(realm, hostname,
+ options.dirman_passwd)
except Exception, e:
if not options.force:
print "Unable to delete replica %s: %s" % (hostname, convert_error(e))
@@ -333,6 +381,7 @@ def del_master(realm, hostname, options):
sys.exit("There were issues removing a connection: %s" % convert_error(e))
def add_link(realm, replica1, replica2, dirman_passwd, options):
+ repl2 = get_cs_replication_manager(realm, replica2, dirman_passwd)
try:
conn = ipaldap.IPAdmin(replica2, 636, cacert=CACERT)
conn.do_simple_bind(bindpw=dirman_passwd)
@@ -349,7 +398,7 @@ def add_link(realm, replica1, replica2, dirman_passwd, options):
sys.exit("Failed to get data while trying to bind to '%s': %s" % (replica1, convert_error(e)))
try:
- repl1 = CSReplicationManager(realm, replica1, dirman_passwd, PORT, True)
+ repl1 = get_cs_replication_manager(realm, replica1, dirman_passwd)
entries = repl1.find_replication_agreements()
for e in entries:
if e.getValue('nsDS5ReplicaHost') == replica2:
@@ -359,11 +408,13 @@ def add_link(realm, replica1, replica2, dirman_passwd, options):
except ldap.NO_SUCH_OBJECT:
sys.exit("Cannot find replica '%s'" % replica1)
except ldap.SERVER_DOWN, e:
- sys.exit("Unable to connect to %s %s" % (ipautil.format_netloc(replica1, PORT), convert_error(e)))
+ sys.exit("Unable to connect to %s: %s" % (replica1, convert_error(e)))
except Exception, e:
sys.exit("Failed to get data from '%s' while trying to get current agreements: %s" % (replica1, convert_error(e)))
- repl1.setup_replication(replica2, PORT, 0, DN(('cn', 'Directory Manager')), dirman_passwd, True, True)
+ repl1.setup_replication(
+ replica2, repl2.port, 0, DN(('cn', 'Directory Manager')),
+ dirman_passwd, is_cs_replica=True, local_port=repl1.port)
print "Connected '%s' to '%s'" % (replica1, replica2)
def re_initialize(realm, options):
@@ -371,8 +422,8 @@ def re_initialize(realm, options):
if not options.fromhost:
sys.exit("re-initialize requires the option --from <host name>")
- repl = CSReplicationManager(realm, options.fromhost, options.dirman_passwd,
- PORT, True)
+ repl = get_cs_replication_manager(realm, options.fromhost,
+ options.dirman_passwd)
thishost = installutils.get_fqdn()
@@ -389,7 +440,7 @@ def re_initialize(realm, options):
def force_sync(realm, thishost, fromhost, dirman_passwd):
- repl = CSReplicationManager(realm, fromhost, dirman_passwd, PORT, True)
+ repl = get_cs_replication_manager(realm, fromhost, dirman_passwd)
try:
repl.force_sync(repl.conn, thishost)
except Exception, e:
diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py
index dfc3c7716..1c90173d2 100644
--- a/ipaserver/install/replication.py
+++ b/ipaserver/install/replication.py
@@ -128,8 +128,8 @@ class ReplicationManager(object):
# If we are passed a password we'll use it as the DM password
# otherwise we'll do a GSSAPI bind.
if starttls:
- self.conn = ipaldap.IPAdmin(hostname, port=port)
- ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, CACERT)
+ self.conn = ipaldap.IPAdmin(hostname, port=port, cacert=CACERT,
+ protocol='ldap')
self.conn.start_tls_s()
else:
self.conn = ipaldap.IPAdmin(hostname, port=port, cacert=CACERT)
@@ -815,17 +815,16 @@ class ReplicationManager(object):
self.setup_changelog(conn)
def setup_replication(self, r_hostname, r_port=389, r_sslport=636,
- r_binddn=None, r_bindpw=None, starttls=False,
- is_cs_replica=False):
+ r_binddn=None, r_bindpw=None,
+ is_cs_replica=False, local_port=None):
assert isinstance(r_binddn, DN)
+ if local_port is None:
+ local_port = r_port
# note - there appears to be a bug in python-ldap - it does not
# allow connections using two different CA certs
- if starttls:
- r_conn = ipaldap.IPAdmin(r_hostname, port=r_port)
- ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, CACERT)
- r_conn.start_tls_s()
- else:
- r_conn = ipaldap.IPAdmin(r_hostname, port=r_sslport, cacert=CACERT)
+ r_conn = ipaldap.IPAdmin(r_hostname, port=r_port, cacert=CACERT,
+ protocol='ldap')
+ r_conn.start_tls_s()
if r_bindpw:
r_conn.do_simple_bind(binddn=r_binddn, bindpw=r_bindpw)
@@ -843,7 +842,7 @@ class ReplicationManager(object):
self.repl_man_dn, self.repl_man_passwd)
if is_cs_replica:
- self.setup_agreement(r_conn, self.conn.host, port=r_port,
+ self.setup_agreement(r_conn, self.conn.host, port=local_port,
repl_man_dn=self.repl_man_dn,
repl_man_passwd=self.repl_man_passwd,
master=False)
@@ -852,7 +851,7 @@ class ReplicationManager(object):
repl_man_passwd=self.repl_man_passwd,
master=True)
else:
- self.setup_agreement(r_conn, self.conn.host, port=r_port,
+ self.setup_agreement(r_conn, self.conn.host, port=local_port,
repl_man_dn=self.repl_man_dn,
repl_man_passwd=self.repl_man_passwd)
self.setup_agreement(self.conn, r_hostname, port=r_port,
@@ -1207,4 +1206,3 @@ class ReplicationManager(object):
print "This may be safely interrupted with Ctrl+C"
self.conn.checkTask(dn, dowait=True)
-