summaryrefslogtreecommitdiffstats
path: root/ipaserver
diff options
context:
space:
mode:
authorSimo Sorce <ssorce@redhat.com>2011-01-10 10:57:43 -0500
committerSimo Sorce <ssorce@redhat.com>2011-01-14 14:06:56 -0500
commit2255479ef0e69bc966f9027f21faf7b14635227c (patch)
tree5141c49f408020b8469371791253ce8bb52cd80d /ipaserver
parenta68b2d2aa37e748c2d00b70bd7d1ea114a4488be (diff)
downloadfreeipa-2255479ef0e69bc966f9027f21faf7b14635227c.tar.gz
freeipa-2255479ef0e69bc966f9027f21faf7b14635227c.tar.xz
freeipa-2255479ef0e69bc966f9027f21faf7b14635227c.zip
Refactor some replication code
This simplifies or rationalizes some code in order to make it easier to change it to fix bug #690
Diffstat (limited to 'ipaserver')
-rw-r--r--ipaserver/install/dsinstance.py14
-rw-r--r--ipaserver/install/replication.py177
2 files changed, 97 insertions, 94 deletions
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 73bc8b0c1..284bf2429 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -287,14 +287,12 @@ class DsInstance(service.Service):
def __setup_replica(self):
- try:
- repl = replication.ReplicationManager(self.fqdn, self.dm_password)
- ret = repl.setup_replication(self.master_fqdn, self.realm_name)
- except Exception, e:
- logging.debug("Connection error: %s" % e)
- raise RuntimeError("Unable to connect to LDAP server %s." % self.fqdn)
- if ret != 0:
- raise RuntimeError("Failed to start replication")
+ repl = replication.ReplicationManager(self.realm_name,
+ self.fqdn,
+ self.dm_password)
+ repl.setup_replication(self.master_fqdn,
+ "cn=Directory Manager",
+ self.dm_password)
def __enable(self):
self.backup_state("enabled", self.is_enabled())
diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py
index cf24f5bfd..3e467a9e7 100644
--- a/ipaserver/install/replication.py
+++ b/ipaserver/install/replication.py
@@ -56,9 +56,11 @@ def check_replication_plugin():
class ReplicationManager:
"""Manage replication agreements between DS servers, and sync
agreements with Windows servers"""
- def __init__(self, hostname, dirman_passwd):
+ def __init__(self, realm, hostname, dirman_passwd):
self.hostname = hostname
self.dirman_passwd = dirman_passwd
+ tmp = util.realm_to_suffix(realm)
+ self.suffix = ipaldap.IPAdmin.normalizeDN(tmp)
# If we are passed a password we'll use it as the DM password
# otherwise we'll do a GSSAPI bind.
@@ -74,7 +76,6 @@ class ReplicationManager:
# at runtime if you really want
self.repl_man_dn = "cn=replication manager,cn=config"
self.repl_man_cn = "replication manager"
- self.suffix = ""
def _get_replica_id(self, conn, master_conn):
"""
@@ -157,25 +158,25 @@ class ReplicationManager:
return res
- def add_replication_manager(self, conn, passwd=None):
+ def add_replication_manager(self, conn, dn, pw):
"""
- Create a pseudo user to use for replication. If no password
- is provided the directory manager password will be used.
+ Create a pseudo user to use for replication.
"""
- if passwd:
- self.repl_man_passwd = passwd
+ edn = ldap.dn.str2dn(dn)
+ rdn_attr = edn[0][0][0]
+ rdn_val = edn[0][0][1]
- ent = ipaldap.Entry(self.repl_man_dn)
+ ent = ipaldap.Entry(dn)
ent.setValues("objectclass", "top", "person")
- ent.setValues("cn", self.repl_man_cn)
- ent.setValues("userpassword", self.repl_man_passwd)
+ ent.setValues(rdn_attr, rdn_val)
+ ent.setValues("userpassword", pw)
ent.setValues("sn", "replication manager pseudo user")
try:
conn.add_s(ent)
except ldap.ALREADY_EXISTS:
- # should we set the password here?
+ conn.modify_s(dn, [(ldap.MOD_REPLACE, "userpassword", pw)])
pass
def delete_replication_manager(self, conn, dn="cn=replication manager,cn=config"):
@@ -193,7 +194,7 @@ class ReplicationManager:
def replica_dn(self):
return 'cn=replica, cn="%s", cn=mapping tree, cn=config' % self.suffix
- def local_replica_config(self, conn, replica_id):
+ def replica_config(self, conn, replica_id, replica_binddn):
dn = self.replica_dn()
try:
@@ -212,7 +213,7 @@ class ReplicationManager:
entry.setValues('nsds5replicaid', str(replica_id))
entry.setValues('nsds5replicatype', replica_type)
entry.setValues('nsds5flags', "1")
- entry.setValues('nsds5replicabinddn', [self.repl_man_dn])
+ entry.setValues('nsds5replicabinddn', [replica_binddn])
entry.setValues('nsds5replicalegacyconsumer', "off")
conn.add_s(entry)
@@ -338,22 +339,18 @@ class ReplicationManager:
except ldap.TYPE_OR_VALUE_EXISTS:
logging.debug("passsync aci already exists in suffix %s on %s" % (self.suffix, conn.host))
- def setup_winsync_agmt(self, entry, **kargs):
+ def setup_winsync_agmt(self, entry, win_subtree=None):
+ if win_subtree is None:
+ win_subtree = WIN_USER_CONTAINER + "," + self.suffix
+ ds_subtree = IPA_USER_CONTAINER + "," + self.suffix
+ windomain = '.'.join(ldap.explode_dn(self.suffix, 1))
+
entry.setValues("objectclass", "nsDSWindowsReplicationAgreement")
- entry.setValues("nsds7WindowsReplicaSubtree",
- kargs.get("win_subtree",
- WIN_USER_CONTAINER + "," + self.suffix))
- entry.setValues("nsds7DirectoryReplicaSubtree",
- kargs.get("ds_subtree",
- IPA_USER_CONTAINER + "," + self.suffix))
+ entry.setValues("nsds7WindowsReplicaSubtree", win_subtree)
+ entry.setValues("nsds7DirectoryReplicaSubtree", ds_subtree)
# for now, just sync users and ignore groups
- entry.setValues("nsds7NewWinUserSyncEnabled", kargs.get('newwinusers', 'true'))
- entry.setValues("nsds7NewWinGroupSyncEnabled", kargs.get('newwingroups', 'false'))
- windomain = ''
- if kargs.has_key('windomain'):
- windomain = kargs['windomain']
- else:
- windomain = '.'.join(ldap.explode_dn(self.suffix, 1))
+ entry.setValues("nsds7NewWinUserSyncEnabled", 'true')
+ entry.setValues("nsds7NewWinGroupSyncEnabled", 'false')
entry.setValues("nsds7WindowsDomain", windomain)
def agreement_dn(self, hostname, port=PORT):
@@ -362,7 +359,9 @@ class ReplicationManager:
return (cn, dn)
- def setup_agreement(self, a, b, **kargs):
+ def setup_agreement(self, a, b,
+ repl_man_dn=None, repl_man_passwd=None,
+ iswinsync=False, win_subtree=None):
cn, dn = self.agreement_dn(b.host)
try:
a.getEntry(dn, ldap.SCOPE_BASE)
@@ -370,10 +369,11 @@ class ReplicationManager:
except errors.NotFound:
pass
- iswinsync = kargs.get("winsync", False)
- repl_man_dn = kargs.get("binddn", self.repl_man_dn)
- repl_man_passwd = kargs.get("bindpw", self.repl_man_passwd)
- port = kargs.get("port", PORT)
+ port = PORT
+ if repl_man_dn is None:
+ repl_man_dn = self.repl_man_dn
+ if repl_man_passwd is None:
+ repl_man_passwd = self.repl_man_passwd
# List of attributes that need to be excluded from replication.
excludes = ('memberof', 'entryusn',
@@ -397,7 +397,7 @@ class ReplicationManager:
'(objectclass=*) $ EXCLUDE %s' % " ".join(excludes))
entry.setValues('description', "me to %s%d" % (b.host, port))
if iswinsync:
- self.setup_winsync_agmt(entry, **kargs)
+ self.setup_winsync_agmt(entry, win_subtree)
a.add_s(entry)
@@ -517,61 +517,70 @@ class ReplicationManager:
return self.wait_for_repl_init(other_conn, dn)
- def basic_replication_setup(self, conn, replica_id):
- self.add_replication_manager(conn)
- self.local_replica_config(conn, replica_id)
+ def basic_replication_setup(self, conn, replica_id, repldn, replpw):
+ self.add_replication_manager(conn, repldn, replpw)
+ self.replica_config(conn, replica_id, repldn)
self.setup_changelog(conn)
- def setup_replication(self, other_hostname, realm_name, **kargs):
- """
- NOTES:
- - the directory manager password needs to be the same on
- both directories. Or use the optional binddn and bindpw
- """
- iswinsync = kargs.get("winsync", False)
- oth_port = kargs.get("port", PORT)
- oth_cacert = kargs.get("cacert", CACERT)
- oth_binddn = kargs.get("binddn", DIRMAN_CN)
- oth_bindpw = kargs.get("bindpw", self.dirman_passwd)
+ def setup_replication(self, r_hostname, r_binddn=None, r_bindpw=None):
# note - there appears to be a bug in python-ldap - it does not
# allow connections using two different CA certs
- other_conn = ipaldap.IPAdmin(other_hostname, port=oth_port, cacert=oth_cacert)
+ r_conn = ipaldap.IPAdmin(r_hostname, port=PORT, cacert=CACERT)
+ if r_bindpw:
+ r_conn.do_simple_bind(binddn=r_binddn, bindpw=r_bindpw)
+ else:
+ r_conn.sasl_interactive_bind_s('', SASL_AUTH)
+
+ #Setup the first half
+ l_id = self._get_replica_id(self.conn, r_conn)
+ self.basic_replication_setup(self.conn, l_id,
+ self.repl_man_dn, self.repl_man_passwd)
+
+ # Now setup the other half
+ r_id = self._get_replica_id(r_conn, r_conn)
+ self.basic_replication_setup(r_conn, r_id,
+ self.repl_man_dn, self.repl_man_passwd)
+
+ self.setup_agreement(r_conn, self.conn)
+ self.setup_agreement(self.conn, r_conn)
+
+ #Finally start replication
+ ret = self.start_replication(r_conn)
+ if ret != 0:
+ raise RuntimeError("Failed to start replication")
+
+ def setup_winsync_replication(self,
+ ad_dc_name, ad_binddn, ad_pwd,
+ passsync_pw, ad_subtree,
+ cacert=CACERT):
try:
- if oth_bindpw:
- other_conn.do_simple_bind(binddn=oth_binddn, bindpw=oth_bindpw)
- else:
- other_conn.sasl_interactive_bind_s('', SASL_AUTH)
+ # Validate AD connection
+ ad_conn = ipaldap.IPAdmin(ad_dc_name, port=636, cacert=cacert)
+ ad_conn.do_simple_bind(binddn=ad_binddn, bindpw=ad_pwd)
except Exception, e:
- if iswinsync:
- logging.info("Could not validate connection to remote server %s:%d - continuing" %
- (other_hostname, oth_port))
- logging.info("The error was: %s" % e)
- else:
- raise e
-
- self.suffix = ipaldap.IPAdmin.normalizeDN(util.realm_to_suffix(realm_name))
-
- if not iswinsync:
- local_id = self._get_replica_id(self.conn, other_conn)
- else:
- # there is no other side to get a replica ID from
- local_id = self._get_replica_id(self.conn, self.conn)
- self.basic_replication_setup(self.conn, local_id)
-
- if not iswinsync:
- other_id = self._get_replica_id(other_conn, other_conn)
- self.basic_replication_setup(other_conn, other_id)
- self.setup_agreement(other_conn, self.conn)
- self.setup_agreement(self.conn, other_conn)
- return self.start_replication(other_conn)
- else:
- self.add_passsync_user(self.conn, kargs.get("passsync"))
- self.setup_agreement(self.conn, other_conn, **kargs)
- logging.info("Added new sync agreement, waiting for it to become ready . . .")
- cn, dn = self.agreement_dn(other_hostname)
- self.wait_for_repl_update(self.conn, dn, 30)
- logging.info("Agreement is ready, starting replication . . .")
- return self.start_replication(self.conn, other_conn)
+ logging.info("Failed to connect to AD server %s" % ad_dc_name)
+ logging.info("The error was: %s" % e)
+ logging.info("Continuning ...")
+
+ # Setup the only half.
+ # there is no other side to get a replica ID from
+ # So we generate one locally
+ replica_id = self._get_replica_id(self.conn, self.conn)
+ self.basic_replication_setup(self.conn, replica_id)
+
+ #now add a passync user allowed to access the AD server
+ self.add_passsync_user(self.conn, passsync_pw)
+ self.setup_agreement(self.conn, ad_conn,
+ repl_man_dn=ad_binddn, repl_man_passwd=ad_pwd,
+ iswinsync=True, win_subtree=ad_subtree)
+ logging.info("Added new sync agreement, waiting for it to become ready . . .")
+ cn, dn = self.agreement_dn(ad_dc_name)
+ self.wait_for_repl_update(self.conn, dn, 30)
+ logging.info("Agreement is ready, starting replication . . .")
+
+ #Finally start replication
+ return self.start_replication(self.conn, ad_conn,
+ self.repl_man_dn, self.repl_man_passwd)
def initialize_replication(self, dn, conn):
mod = [(ldap.MOD_ADD, 'nsds5BeginReplicaRefresh', 'start')]
@@ -618,10 +627,6 @@ class ReplicationManager:
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)