I'm not sure why this didn't always fail but in the client installer we were creating a connection before calling kinit. I re-arranged this in and beefed up the client logging.

While testing this I periodically ran into an NSS shutdown error where the ping() connection hadn't closed before the host_mod to add the SSH keys was run.

This stores dbdir in the connection so we can check to see if the same database is being used so NSSConnection can skip the nss_init().

I tested client installs using: ipa-client-install --enable-dns-updates --ssh-trust-dns

This same error was reported when installing a replica with --setup-dns.

rob
>From 54cc50f0ac261961c5e570145aee9c93866ea3ec Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcrit...@redhat.com>
Date: Sat, 3 Mar 2012 19:50:21 -0500
Subject: [PATCH] Do kinit in client before connecting to backend

The client installer was failing because a backend connection could be
created before a kinit was done.

Allow multiple simultaneous connections. This could fail with an NSS
shutdown error when the second connection was created (objects still
in use). If all connections currently use the same database then there
is no need to initialize, let it be skipped.

Add additional logging to client installer.

https://fedorahosted.org/freeipa/ticket/2478
---
 ipa-client/ipa-install/ipa-client-install |    5 +++-
 ipalib/rpc.py                             |   33 +++++++++++++++++++++++++---
 ipapython/nsslib.py                       |   13 +++++++++-
 3 files changed, 44 insertions(+), 7 deletions(-)

diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install
index 67c299966cbfc0ac52585ed079173f64878b4f05..aec39c783c7cd9c5824ac786dbf02aa9bf8f59af 100755
--- a/ipa-client/ipa-install/ipa-client-install
+++ b/ipa-client/ipa-install/ipa-client-install
@@ -177,6 +177,7 @@ def nssldap_exists():
 def emit_quiet(quiet, message):
     if not quiet:
         print message
+    root_logger.debug(message)
 
 def uninstall(options, env, quiet=False):
 
@@ -1031,6 +1032,7 @@ def update_ssh_keys(server, hostname, ssh_dir, create_sshfp):
     except StandardError, e:
         root_logger.warning("host_mod: %s" % str(e))
         print >>sys.stderr, "Failed to upload host SSH public keys."
+        root_logger.debug('Failed to upload host SSH public keys.')
         return
 
     if create_sshfp:
@@ -1324,7 +1326,6 @@ def install(options, env, fstore, statestore):
     if 'config_loaded' not in api.env:
         print >>sys.stderr, "Failed to initialize IPA API."
         return CLIENT_INSTALL_ERROR
-    api.Backend.xmlclient.connect()
 
     # Always back up sssd.conf. It gets updated by authconfig --enablekrb5.
     fstore.backup_file("/etc/sssd/sssd.conf")
@@ -1348,6 +1349,7 @@ def install(options, env, fstore, statestore):
     os.environ['KRB5CCNAME'] = CCACHE_FILE
     try:
         ipautil.run(['/usr/bin/kinit', '-k', '-t', '/etc/krb5.keytab', 'host/%s' % hostname])
+        api.Backend.xmlclient.connect()
     except CalledProcessError, e:
         print >>sys.stderr, "Failed to obtain host TGT."
 
@@ -1476,6 +1478,7 @@ def install(options, env, fstore, statestore):
     configure_ssh(fstore, ipaservices.knownservices.sshd.get_config_dir(), options)
 
     print "Client configuration complete."
+    root_logger.debug('Client configuration complete.')
 
     return 0
 
diff --git a/ipalib/rpc.py b/ipalib/rpc.py
index d8fee56395e7f286fa5daf86f0dc80aa242955fc..7998156b5334a5774822e4b8c1853516e1e035e7 100644
--- a/ipalib/rpc.py
+++ b/ipalib/rpc.py
@@ -42,7 +42,7 @@ import kerberos
 from ipalib.backend import Connectible
 from ipalib.errors import public_errors, PublicError, UnknownError, NetworkError, KerberosError, XMLRPCMarshallError
 from ipalib import errors
-from ipalib.request import context
+from ipalib.request import context, Connection
 from ipapython import ipautil, dnsclient
 import httplib
 import socket
@@ -215,16 +215,41 @@ class LanguageAwareTransport(Transport):
 class SSLTransport(LanguageAwareTransport):
     """Handles an HTTPS transaction to an XML-RPC server."""
 
+    def __nss_initialized(self, dbdir):
+        """
+        If there is another connections open it may have already
+        initialized NSS. This is likely to lead to an NSS shutdown
+        failure.  One way to mitigate this is to tell NSS to not
+        initialize if it has already been done in another open connection.
+
+        Returns True if another connection is using the same db.
+        """
+        init = False
+        for value in context.__dict__.values():
+            if isinstance(value, Connection):
+                if isinstance(value.conn._ServerProxy__transport,
+                  KerbTransport) or \
+                  isinstance(value.conn._ServerProxy__transport,
+                  DelegatedKerbTransport):
+                    if (value.conn._ServerProxy__transport.dbdir == dbdir):
+                        init = True
+        return init
+
     def make_connection(self, host):
         host, self._extra_headers, x509 = self.get_host_info(host)
-        host, self._extra_headers, x509 = self.get_host_info(host)
         # Python 2.7 changed the internal class used in xmlrpclib from
         # HTTP to HTTPConnection. We need to use the proper subclass
+
+        # If we an existing connection exists using the same NSS database
+        # there is no need to re-initialize. Pass thsi into the NSS
+        # connection creator.
+        self.dbdir='/etc/pki/nssdb'
+        no_init = self.__nss_initialized(self.dbdir)
         (major, minor, micro, releaselevel, serial) = sys.version_info
         if major == 2 and minor < 7:
-            conn = NSSHTTPS(host, 443, dbdir="/etc/pki/nssdb")
+            conn = NSSHTTPS(host, 443, dbdir=self.dbdir, no_init=no_init)
         else:
-            conn = NSSConnection(host, 443, dbdir="/etc/pki/nssdb")
+            conn = NSSConnection(host, 443, dbdir=self.dbdir, no_init=no_init)
         conn.connect()
         return conn
 
diff --git a/ipapython/nsslib.py b/ipapython/nsslib.py
index 2255519321a6a44e4a0d33574df303b4edd03d57..cc6ab1de04e96d82f0a2a4299045a62047c2b680 100644
--- a/ipapython/nsslib.py
+++ b/ipapython/nsslib.py
@@ -190,7 +190,16 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback):
     default_port = httplib.HTTPSConnection.default_port
 
     def __init__(self, host, port=None, strict=None,
-                 dbdir=None, family=socket.AF_UNSPEC):
+                 dbdir=None, family=socket.AF_UNSPEC, no_init=False):
+        """
+        :param host: the server to connect to
+        :param port: the port to use (default is set in HTTPConnection)
+        :param dbdir: the NSS database directory
+        :param family: network family to use (default AF_UNSPEC)
+        :param no_init: do not initialize the NSS database. This requires
+                        that the database has already been initialized or
+                        the request will fail.
+        """
         httplib.HTTPConnection.__init__(self, host, port, strict)
         NSSAddressFamilyFallback.__init__(self, family)
 
@@ -198,7 +207,7 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback):
             raise RuntimeError("dbdir is required")
 
         root_logger.debug('%s init %s', self.__class__.__name__, host)
-        if nss.nss_is_initialized():
+        if not no_init and nss.nss_is_initialized():
             # close any open NSS database and use the new one
             ssl.clear_session_cache()
             try:
-- 
1.7.6.5

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

Reply via email to