When ipa-client-install is run without --server option, it tries to
search SRV records for IPA/LDAP server hostname, but it returns only
the first record found and when the LDAP server on that hostname is
not available, the whole client installation fails.

Get all LDAP SRV records instead and fallback to next hostname when
the current one is not available.

https://fedorahosted.org/freeipa/ticket/3388
From 600b03a759f06a8bdcbf73c2d15ec4c5608a0015 Mon Sep 17 00:00:00 2001
From: Martin Kosek <mko...@redhat.com>
Date: Mon, 4 Feb 2013 15:00:14 +0100
Subject: [PATCH] Add LDAP server fallback to client installer

When ipa-client-install is run without --server option, it tries to
search SRV records for IPA/LDAP server hostname, but it returns only
the first record found and when the LDAP server on that hostname is
not available, the whole client installation fails.

Get all LDAP SRV records instead and fallback to next hostname when
the current one is not available.

https://fedorahosted.org/freeipa/ticket/3388
---
 ipa-client/ipaclient/ipadiscovery.py | 67 +++++++++++++++++++++---------------
 1 file changed, 40 insertions(+), 27 deletions(-)

diff --git a/ipa-client/ipaclient/ipadiscovery.py b/ipa-client/ipaclient/ipadiscovery.py
index 18b77a684505a61b4958cde678fc58b66c6632fd..f94e62d9f20d85b50eb95d5b0135cbce8916602c 100644
--- a/ipa-client/ipaclient/ipadiscovery.py
+++ b/ipa-client/ipaclient/ipadiscovery.py
@@ -58,6 +58,7 @@ class IPADiscovery(object):
     def __init__(self):
         self.realm = None
         self.domain = None
+        self.servers = None
         self.server = None
         self.basedn = None
 
@@ -129,9 +130,9 @@ class IPADiscovery(object):
                 break
             tried.add(domain)
 
-            server = self.ipadns_search_srv(domain, '_ldap._tcp', 389)
-            if server:
-                return (server[0], domain)
+            servers = self.ipadns_search_srv(domain, '_ldap._tcp', 389, break_on_first=False)
+            if servers:
+                return (servers, domain)
             else:
                 p = domain.find(".")
                 if p == -1: #no ldap server found and last component of the domain already tested
@@ -177,9 +178,9 @@ class IPADiscovery(object):
                 domains = [(domain, 'domain of the hostname')] + domains
                 tried = set()
                 for domain, reason in domains:
-                    server, domain = self.check_domain(domain, tried, reason)
-                    if server:
-                        self.server = server
+                    servers, domain = self.check_domain(domain, tried, reason)
+                    if servers:
+                        self.servers = servers
                         self.domain = domain
                         self.server_source = self.domain_source = (
                             'Discovered LDAP SRV records from %s (%s)' %
@@ -190,14 +191,15 @@ class IPADiscovery(object):
                     return NO_LDAP_SERVER
             else:
                 root_logger.debug("Search for LDAP SRV record in %s", domain)
-                server = self.ipadns_search_srv(domain, '_ldap._tcp', 389)
-                if server:
-                    self.server = server[0]
+                servers = self.ipadns_search_srv(domain, '_ldap._tcp', 389,
+                            break_on_first=False)
+                if servers:
+                    self.servers = servers
                     self.domain = domain
                     self.server_source = self.domain_source = (
                         'Discovered LDAP SRV records from %s' % domain)
                 else:
-                    self.server = None
+                    self.servers = None
                     root_logger.debug('No LDAP server found')
                     return NO_LDAP_SERVER
 
@@ -205,7 +207,7 @@ class IPADiscovery(object):
 
             root_logger.debug("Server and domain forced")
             self.domain = domain
-            self.server = server
+            self.servers = [server]
             self.domain_source = self.server_source = 'Forced'
 
         #search for kerberos
@@ -220,23 +222,34 @@ class IPADiscovery(object):
             'Discovered Kerberos DNS records from %s' % self.domain)
 
         root_logger.debug("[LDAP server check]")
-        root_logger.debug('Verifying that %s (realm %s) is an IPA server',
-            self.server, self.realm)
+        root_logger.debug('Search for valid IPA server in %s (realm %s)',
+            self.servers, self.realm)
         # We may have received multiple servers corresponding to the domain
         # Iterate through all of those to check if it is IPA LDAP server
         ldapret = [NOT_IPA_SERVER]
         ldapaccess = True
-        if self.server:
+        if self.servers:
             # check ldap now
-            ldapret = self.ipacheckldap(self.server, self.realm, ca_cert_path=ca_cert_path)
+            for server in self.servers:
+                root_logger.error("Test if %s is an IPA server", server)
+                ldapret = self.ipacheckldap(server, self.realm, ca_cert_path=ca_cert_path)
 
-            if ldapret[0] == 0:
-                self.server = ldapret[1]
-                self.realm = ldapret[2]
-                self.server_source = self.realm_source = (
-                    'Discovered from LDAP DNS records in %s' % self.server)
-            elif ldapret[0] == NO_ACCESS_TO_LDAP or ldapret[0] == NO_TLS_LDAP:
-                ldapaccess = False
+                if ldapret[0] == 0:
+                    self.server = ldapret[1]
+                    self.realm = ldapret[2]
+                    self.server_source = self.realm_source = (
+                        'Discovered from LDAP DNS records in %s' % self.server)
+                    break
+                elif ldapret[0] == NO_ACCESS_TO_LDAP or ldapret[0] == NO_TLS_LDAP:
+                    self.server = server
+                    ldapaccess = False
+                    self.server_soure = (
+                        'Discovered from LDAP DNS records in %s (no LDAP access)',
+                        self.server)
+                    break
+                else:
+                    root_logger.debug(
+                        "Server %s is not available, try next", server)
 
         # If one of LDAP servers checked rejects access (maybe anonymous
         # bind is disabled), assume realm and basedn generated off domain.
@@ -258,8 +271,8 @@ class IPADiscovery(object):
             root_logger.debug("Generated basedn from realm: %s" % self.basedn)
 
         root_logger.debug(
-            "Discovery result: %s; server=%s, domain=%s, kdc=%s, basedn=%s",
-            error_names.get(ldapret[0], ldapret[0]),
+            "Discovery result: %s; servers=%s, server=%s, domain=%s, kdc=%s, basedn=%s",
+            error_names.get(ldapret[0], ldapret[0]), self.servers,
             self.server, self.domain, self.kdc, self.basedn)
 
         return ldapret[0]
@@ -339,11 +352,11 @@ class IPADiscovery(object):
 
         except LDAPError, err:
             if isinstance(err, ldap.TIMEOUT):
-                root_logger.error("LDAP Error: timeout")
+                root_logger.debug("LDAP Error: timeout")
                 return [NO_LDAP_SERVER]
 
             if isinstance(err, ldap.INAPPROPRIATE_AUTH):
-                root_logger.debug("LDAP Error: Anonymous acces not allowed")
+                root_logger.debug("LDAP Error: Anonymous access not allowed")
                 return [NO_ACCESS_TO_LDAP]
 
             # We should only get UNWILLING_TO_PERFORM if the remote LDAP server
@@ -352,7 +365,7 @@ class IPADiscovery(object):
                 root_logger.debug("LDAP server returned UNWILLING_TO_PERFORM. This likely means that minssf is enabled")
                 return [NO_TLS_LDAP]
 
-            root_logger.error("LDAP Error: %s: %s" %
+            root_logger.debug("LDAP Error: %s: %s" %
                (err.args[0]['desc'], err.args[0].get('info', '')))
             return [UNKNOWN_ERROR]
 
-- 
1.8.1

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to