[Freeipa-devel] [PATCH 3/3] Get list of service from LDAP only at startup

Simo Sorce simo at redhat.com
Tue Oct 30 16:19:29 UTC 2012


From: Simo Sorce <ssorce at redhat.com>

We check (possibly different) data from LDAP only at (re)start.
This way we always shutdown exactly the services we started even if the list
changed in the meanwhile (we avoid leaving a service running even if it was
removed from LDAP as the admin decided it should not be started in future).

This should also fix a problematic deadlock with systemd when we try to read
the list of service from LDAP at shutdown.
---
 freeipa.spec.in                |    2 +
 init/systemd/ipa.conf.tmpfiles |    1 +
 install/tools/ipactl           |  199 ++++++++++++++++++++++++++++------------
 3 files changed, 143 insertions(+), 59 deletions(-)

diff --git a/freeipa.spec.in b/freeipa.spec.in
index af76118fd0294fa4d8934b747c254b891ae7f2cb..397d60b1d2a22b1d1eb26b8f567f381da526f282 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -447,6 +447,7 @@ install -m 0644 init/systemd/ipa.conf.tmpfiles %{buildroot}%{_sysconfdir}/tmpfil
 
 mkdir -p %{buildroot}%{_localstatedir}/run/
 install -d -m 0700 %{buildroot}%{_localstatedir}/run/ipa_memcached/
+install -d -m 0700 %{buildroot}%{_localstatedir}/run/ipa/
 
 mkdir -p %{buildroot}%{_libdir}/krb5/plugins/libkrb5
 touch %{buildroot}%{_libdir}/krb5/plugins/libkrb5/winbind_krb5_locator.so
@@ -624,6 +625,7 @@ fi
 %{_sysconfdir}/cron.d/ipa-compliance
 %config(noreplace) %{_sysconfdir}/sysconfig/ipa_memcached
 %dir %attr(0700,apache,apache) %{_localstatedir}/run/ipa_memcached/
+%dir %attr(0700,root,root) %{_localstatedir}/run/ipa/
 %if 0%{?fedora} >= 15
 %config %{_sysconfdir}/tmpfiles.d/ipa.conf
 %endif
diff --git a/init/systemd/ipa.conf.tmpfiles b/init/systemd/ipa.conf.tmpfiles
index e4b679a55d68a6b83991ac72dd520c32b2a0de50..1e7a896ed8df00c97f2d092504e2a65960bb341d 100644
--- a/init/systemd/ipa.conf.tmpfiles
+++ b/init/systemd/ipa.conf.tmpfiles
@@ -1 +1,2 @@
 d /var/run/ipa_memcached 0700 apache apache
+d /var/run/ipa 0700 root root
diff --git a/install/tools/ipactl b/install/tools/ipactl
index d4b2c0878f2b62fd12198f76bef01ef70e9f3de1..9b151ab9f9bd10423d5145a1fcf028b6ddb65096 100755
--- a/install/tools/ipactl
+++ b/install/tools/ipactl
@@ -34,6 +34,7 @@ try:
     import ldap.sasl
     import ldapurl
     import socket
+    import json
 except ImportError:
     print >> sys.stderr, """\
 There was a problem importing one of the required Python modules. The
@@ -162,11 +163,30 @@ def get_config(dirsrv):
         for p in entry[1]['ipaConfigString']:
             if p.startswith('startOrder '):
                 order = p.split()[1]
-        svc_list.append((order, name))
+        svc_list.append([order, name])
+
+    ordered_list = []
+    for (order, svc) in sorted(svc_list):
+        ordered_list.append(service.SERVICE_LIST[svc][0])
+    return ordered_list
+
+def get_config_from_file():
+
+    svc_list = []
+
+    try:
+        f = open(ipaservices.get_svc_list_file(), 'r')
+        svc_list = json.load(f)
+    except Exception, e:
+        raise IpactlError("Unknown error when retrieving list of services from file: " + str(e))
 
     return svc_list
 
 def ipa_start(options):
+
+    if os.path.isfile(ipaservices.get_svc_list_file()):
+        raise IpactlError("IPA service already started!")
+
     dirsrv = ipaservices.knownservices.dirsrv
     try:
         print "Starting Directory Service"
@@ -174,7 +194,7 @@ def ipa_start(options):
     except Exception, e:
         raise IpactlError("Failed to start Directory Service: " + str(e))
 
-    svc_list = []
+    ldap_list = []
     try:
         svc_list = get_config(dirsrv)
     except Exception, e:
@@ -191,21 +211,19 @@ def ipa_start(options):
             raise IpactlError()
 
     if len(svc_list) == 0:
-        # no service to stop
+        # no service to start
         return
 
-    for (order, svc) in sorted(svc_list):
-        svc_name = service.SERVICE_LIST[svc][0]
-        svchandle = ipaservices.service(svc_name)
+    for svc in svc_list:
+        svchandle = ipaservices.service(svc)
         try:
             print "Starting %s Service" % svc
-            svchandle.start(capture_output=get_capture_output(svc_name, options.debug))
+            svchandle.start(capture_output=get_capture_output(svc, options.debug))
         except:
             emit_err("Failed to start %s Service" % svc)
             emit_err("Shutting down")
-            for (order, svc) in sorted(svc_list):
-                svc_name = service.SERVICE_LIST[svc][0]
-                svc_off = ipaservices.service(svc_name)
+            for svc in svc_list:
+                svc_off = ipaservices.service(svc)
                 try:
                     svc_off.stop(capture_output=False)
                 except:
@@ -220,11 +238,10 @@ def ipa_stop(options):
     dirsrv = ipaservices.knownservices.dirsrv
     svc_list = []
     try:
-        svc_list = get_config(dirsrv)
+        svc_list = get_config_from_file()
     except Exception, e:
-        # ok if dirsrv died this may fail, so let's try to quickly restart it
-        # and see if we can get anything. If not throw our hands up and just
-        # exit
+        # Issue reading the file ? Let's try to get data from LDAP as a
+        # fallback
         try:
             dirsrv.start(capture_output=False)
             svc_list = get_config(dirsrv)
@@ -241,9 +258,8 @@ def ipa_stop(options):
         # no service to stop
         return
 
-    for (order, svc) in sorted(svc_list, reverse=True):
-        svc_name = service.SERVICE_LIST[svc][0]
-        svchandle = ipaservices.service(svc_name)
+    for svc in reversed(svc_list):
+        svchandle = ipaservices.service(svc)
         try:
             print "Stopping %s Service" % svc
             svchandle.stop(capture_output=False)
@@ -256,58 +272,132 @@ def ipa_stop(options):
     except:
         raise IpactlError("Failed to stop Directory Service")
 
+    # remove file with list of started services
+    os.unlink(ipaservices.SVC_LIST_FILE)
+
 
 def ipa_restart(options):
     dirsrv = ipaservices.knownservices.dirsrv
+    new_svc_list = []
+    try:
+        new_svc_list = get_config(dirsrv)
+    except Exception, e:
+        emit_err("Failed to read data from Directory Service: " + str(e))
+        emit_err("Shutting down")
+        try:
+            dirsrv.stop(capture_output=False)
+        except:
+            pass
+        if isinstance(e, IpactlError):
+            # do not display any other error message
+            raise IpactlError(rval=e.rval)
+        else:
+            raise IpactlError()
+
+    old_svc_list = []
+    try:
+        old_svc_list = get_config_from_file()
+    except Exception, e:
+        emit_err("Failed to get service list from file: " + str(e))
+        # fallback to what's in LDAP
+        old_svc_list = new_svc_list
+
+    # match service to start/stop
+    svc_list = []
+    for s in new_svc_list:
+        if s in old_svc_list:
+            svc_list.append(s)
+
+    #remove commons
+    for s in svc_list:
+        if s in old_svc_list:
+            old_svc_list.remove(s)
+    for s in svc_list:
+        if s in new_svc_list:
+            new_svc_list.remove(s)
+
+    if len(old_svc_list) != 0:
+        # we need to definitely stop some services
+        for svc in reversed(old_svc_list):
+            svchandle = ipaservices.service(svc)
+            try:
+                print "Stopping %s Service" % svc
+                svchandle.stop(capture_output=False)
+            except:
+                emit_err("Failed to stop %s Service" % svc)
+
     try:
         print "Restarting Directory Service"
         dirsrv.restart(capture_output=get_capture_output('dirsrv', options.debug))
     except Exception, e:
-        raise IpactlError("Failed to restart Directory Service: " + str(e))
-
-    svc_list = []
-    try:
-        svc_list = get_config(dirsrv)
-    except Exception, e:
-        emit_err("Failed to read data from Directory Service: " + str(e))
+        emit_err("Failed to restart Directory Service: " + str(e))
         emit_err("Shutting down")
+        for svc in reversed(svc_list):
+            svc_off = ipaservices.service(svc)
+            try:
+                svc_off.stop(capture_output=False)
+            except:
+                pass
         try:
             dirsrv.stop(capture_output=False)
         except:
             pass
-        if isinstance(e, IpactlError):
-            # do not display any other error message
-            raise IpactlError(rval=e.rval)
-        else:
-            raise IpactlError()
+        raise IpactlError("Aborting ipactl")
 
-    if len(svc_list) == 0:
-        # no service to stop
-        return
+    if len(svc_list) != 0:
+        # there are services to restart
 
-    for (order, svc) in sorted(svc_list):
-        svc_name = service.SERVICE_LIST[svc][0]
-        svchandle = ipaservices.service(svc_name)
-        try:
-            print "Restarting %s Service" % svc
-            svchandle.restart(capture_output=get_capture_output(svc_name, options.debug))
-        except:
-            emit_err("Failed to restart %s Service" % svc)
-            emit_err("Shutting down")
-            for (order, svc) in sorted(svc_list):
-                svc_name = service.SERVICE_LIST[svc][0]
-                svc_off = ipaservices.service(svc_name)
+        for svc in svc_list:
+            svchandle = ipaservices.service(svc)
+            try:
+                print "Restarting %s Service" % svc
+                svchandle.restart(capture_output=get_capture_output(svc, options.debug))
+            except:
+                emit_err("Failed to restart %s Service" % svc)
+                emit_err("Shutting down")
+                for svc in reversed(svc_list):
+                    svc_off = ipaservices.service(svc)
+                    try:
+                        svc_off.stop(capture_output=False)
+                    except:
+                        pass
                 try:
-                    svc_off.stop(capture_output=False)
+                    dirsrv.stop(capture_output=False)
                 except:
                     pass
+                raise IpactlError("Aborting ipactl")
+
+    if len(new_svc_list) != 0:
+        # we still need to start some services
+        for svc in new_svc_list:
+            svchandle = ipaservices.service(svc)
             try:
-                dirsrv.stop(capture_output=False)
+                print "Starting %s Service" % svc
+                svchandle.start(capture_output=get_capture_output(svc, options.debug))
             except:
-                pass
-            raise IpactlError("Aborting ipactl")
+                emit_err("Failed to start %s Service" % svc)
+                emit_err("Shutting down")
+                for svc in reversed(svc_list):
+                    svc_off = ipaservices.service(svc)
+                    try:
+                        svc_off.stop(capture_output=False)
+                    except:
+                        pass
+                try:
+                    dirsrv.stop(capture_output=False)
+                except:
+                    pass
+                raise IpactlError("Aborting ipactl")
 
 def ipa_status(options):
+
+    try:
+        svc_list = get_config_from_file()
+    except IpactlError, e:
+        raise e
+    except Exception, e:
+        raise IpactlError("Failed to get list of services to probe status: " + str(e))
+
     dirsrv = ipaservices.knownservices.dirsrv
     try:
         if dirsrv.is_running():
@@ -317,20 +407,11 @@ def ipa_status(options):
     except:
         raise IpactlError("Failed to get Directory Service status")
 
-    svc_list = []
-    try:
-        svc_list = get_config(dirsrv)
-    except IpactlError, e:
-        raise e
-    except Exception, e:
-        raise IpactlError("Failed to get list of services to probe status: " + str(e))
-
     if len(svc_list) == 0:
         return
 
-    for (order, svc) in sorted(svc_list):
-        svc_name = service.SERVICE_LIST[svc][0]
-        svchandle = ipaservices.service(svc_name)
+    for svc in svc_list:
+        svchandle = ipaservices.service(svc)
         try:
             if svchandle.is_running():
                 print "%s Service: RUNNING" % svc
-- 
1.7.1




More information about the Freeipa-devel mailing list