From 54b26270186422607ef52b9b408326744b2d86d1 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mon, 28 Feb 2011 17:35:44 -0500 Subject: Store list of non-master replicas in DIT and provide way to list them Fixes: https://fedorahosted.org/freeipa/ticket/1007 --- install/share/bootstrap-template.ldif | 6 ++ install/tools/ipa-replica-manage | 110 +++++++++++++++++++-------- install/updates/21-replicas_container.update | 9 +++ install/updates/Makefile.am | 1 + ipaserver/install/replication.py | 12 +++ 5 files changed, 108 insertions(+), 30 deletions(-) create mode 100644 install/updates/21-replicas_container.update diff --git a/install/share/bootstrap-template.ldif b/install/share/bootstrap-template.ldif index b941d5f8..0a81b63f 100644 --- a/install/share/bootstrap-template.ldif +++ b/install/share/bootstrap-template.ldif @@ -143,6 +143,12 @@ objectClass: nsContainer objectClass: top cn: masters +dn: cn=replicas,cn=ipa,cn=etc,$SUFFIX +changetype: add +objectClass: nsContainer +objectClass: top +cn: replicas + dn: cn=dna,cn=ipa,cn=etc,$SUFFIX changetype: add objectClass: nsContainer diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage index 931b1392..87c994aa 100755 --- a/install/tools/ipa-replica-manage +++ b/install/tools/ipa-replica-manage @@ -117,42 +117,77 @@ def test_connection(realm, host): except ldap.LOCAL_ERROR: return False -def list_masters(realm, host, replica, dirman_passwd, verbose): +def list_replicas(realm, host, replica, dirman_passwd, verbose): - if replica: - try: - repl = replication.ReplicationManager(realm, replica, dirman_passwd) - except Exception, e: - print "Failed to get data from '%s': %s" % (replica, str(e)) - return + is_replica = False + winsync_peer = None + peers = {} - entries = repl.find_replication_agreements() + try: + conn = ipaldap.IPAdmin(host, 636, cacert=CACERT) + if dirman_passwd: + conn.do_simple_bind(bindpw=dirman_passwd) + else: + conn.do_sasl_gssapi_bind() - for entry in entries: - print entry.nsds5replicahost + dn = 'cn=masters,cn=ipa,cn=etc,%s' % util.realm_to_suffix(realm) + entries = conn.search_s(dn, ldap.SCOPE_ONELEVEL) - if verbose: - print " last init status: %s" % entry.nsds5replicalastinitstatus - print " last init ended: %s" % str(ipautil.parse_generalized_time(entry.nsds5replicalastinitend)) - print " last update status: %s" % entry.nsds5replicalastupdatestatus - print " last update ended: %s" % str(ipautil.parse_generalized_time(entry.nsds5replicalastupdateend)) - else: - try: - conn = ipaldap.IPAdmin(host, 636, cacert=CACERT) - if dirman_passwd: - conn.do_simple_bind(bindpw=dirman_passwd) - else: - conn.do_sasl_gssapi_bind() + for ent in entries: + peers[ent.cn] = ['master', ''] - dn = 'cn=masters,cn=ipa,cn=etc,%s' % util.realm_to_suffix(realm) - entries = conn.search_s(dn, ldap.SCOPE_ONELEVEL) + dn = 'cn=replicas,cn=ipa,cn=etc,%s' % util.realm_to_suffix(realm) + entries = conn.search_s(dn, ldap.SCOPE_ONELEVEL) - for ent in entries: - print ent.cn + for ent in entries: + peers[ent.cn] = ent.ipaconfigstring.split(':') - except Exception, e: - print "Failed to get data from '%s': %s" % (host, str(e)) - return + except Exception, e: + print "Failed to get data from '%s': %s" % (host, str(e)) + return + + + if not replica: + for k, p in peers.iteritems(): + print '%s: %s' % (k, p[0]) + return + + # ok we are being ask for info about a specific replica + for k, p in peers.iteritems(): + if replica == k: + is_replica = True + if p[0] == 'winsync': + winsync_peer = p[1] + + if not is_replica: + print "Cannot find %s in public server list" % replica + return + + try: + if winsync_peer: + repl = replication.ReplicationManager(realm, winsync_peer, + dirman_passwd) + cn, dn = repl.agreement_dn(replica) + entries = repl.conn.search_s(dn, ldap.SCOPE_BASE, + "(objectclass=nsDSWindowsReplicationAgreement)") + ent_type = 'winsync' + else: + repl = replication.ReplicationManager(realm, replica, + dirman_passwd) + entries = repl.find_replication_agreements() + ent_type = 'replica' + except Exception, e: + print "Failed to get data from '%s': %s" % (replica, str(e)) + return + + for entry in entries: + print '%s: %s' % (entry.nsds5replicahost, ent_type) + + if verbose: + print " last init status: %s" % entry.nsds5replicalastinitstatus + print " last init ended: %s" % str(ipautil.parse_generalized_time(entry.nsds5replicalastinitend)) + print " last update status: %s" % entry.nsds5replicalastupdatestatus + print " last update ended: %s" % str(ipautil.parse_generalized_time(entry.nsds5replicalastupdateend)) def del_link(realm, replica1, replica2, dirman_passwd, force=False): @@ -228,6 +263,21 @@ def del_link(realm, replica1, replica2, dirman_passwd, force=False): repl1.delete_agreement(replica2) repl1.delete_referral(replica2) + if type1 == replication.WINSYNC: + try: + dn = 'cn=%s,cn=replicas,cn=ipa,cn=etc,%s' % (replica2, + util.realm_to_suffix(realm)) + entries = repl1.conn.search_s(dn, ldap.SCOPE_SUBTREE) + if len(entries) != 0: + dnset = repl1.conn.get_dns_sorted_by_length(entries, + reverse=True) + for dns in dnset: + for dn in dns: + repl1.conn.deleteEntry(dn) + except Exception, e: + print "Error deleting winsync replica shared info: %s" % str(e) + + def del_master(realm, hostname, options): force_del = False @@ -390,7 +440,7 @@ def main(): replica = None if len(args) == 2: replica = args[1] - list_masters(realm, host, replica, dirman_passwd, options.verbose) + list_replicas(realm, host, replica, dirman_passwd, options.verbose) elif args[0] == "del": del_master(realm, args[1], options) elif args[0] == "re-initialize": diff --git a/install/updates/21-replicas_container.update b/install/updates/21-replicas_container.update new file mode 100644 index 00000000..44b14f82 --- /dev/null +++ b/install/updates/21-replicas_container.update @@ -0,0 +1,9 @@ +# +# Add replicas container if not available +# + +dn: cn=replicas,cn=ipa,cn=etc,$SUFFIX +add:objectClass: top +add:objectClass: nsContainer +add:cn: replicas + diff --git a/install/updates/Makefile.am b/install/updates/Makefile.am index 5b45c6ef..947ccd11 100644 --- a/install/updates/Makefile.am +++ b/install/updates/Makefile.am @@ -10,6 +10,7 @@ app_DATA = \ 20-nss_ldap.update \ 20-replication.update \ 20-winsync_index.update \ + 21-replicas_container.update \ 40-delegation.update \ 50-lockout-policy.update \ 45-roles.update \ diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py index c9afc5d4..091a4de0 100644 --- a/ipaserver/install/replication.py +++ b/ipaserver/install/replication.py @@ -673,6 +673,18 @@ class ReplicationManager: self.wait_for_repl_update(self.conn, dn, 30) logging.info("Agreement is ready, starting replication . . .") + # Add winsync replica to the public DIT + dn = 'cn=%s,cn=replicas,cn=ipa,cn=etc,%s' % (ad_dc_name, self.suffix) + entry = ipaldap.Entry(dn) + entry.setValues("objectclass", ["nsContainer", "ipaConfigObject"]) + entry.setValues("cn", ad_dc_name) + entry.setValues("ipaConfigString", "winsync:%s" % self.hostname) + + try: + self.conn.add_s(entry) + except Exception, e: + logging.info("Failed to create public entry for winsync replica") + #Finally start replication ret = self.start_replication(self.conn, ad_dc_name) if ret != 0: -- cgit