On Fri, 10 Dec 2010 12:43:59 +0100
Jakub Hrozek <jhro...@redhat.com> wrote:

> Other comments:
> Since the ipactl script is written in Python and /sbin/service ipa
> $action is called in %preun and %postun we also need to add
> Requires(preun): python and Requires(postun): python.

Added

> Also, I noticed (unrelated to this patch) that we are missing the
> pre/post Requires on chkconfig and initscripts.

Added as well

> Why do we still use chkconfig --add and --del for ipa_kpasswd instead
> of using enabling it in KrbInstance.__enable()?
> 
> What are the second elements in the SERVICE_LIST[service_name] tuples?
> 
> Otherwise looks good and works fine.

New patch attached.

Simo.

-- 
Simo Sorce * Red Hat, Inc * New York
>From 5954680f6ef2a9f2c2db8cc17d47e68bebd94989 Mon Sep 17 00:00:00 2001
From: Simo Sorce <sso...@redhat.com>
Date: Sat, 4 Dec 2010 15:42:14 -0500
Subject: [PATCH 2/2] Introduce ipa control script that reads configuration off ldap

This replace the former ipactl script, as well as replace the current way ipa
components are started.

Instead of enabling each service in the system init scripts, enable only the
ipa script, and then let it start all components based on the configuration
read from the LDAP tree.

resolves: https://fedorahosted.org/freeipa/ticket/294
---
 install/tools/ipa-server-install  |    4 +
 install/tools/ipactl              |  314 ++++++++++++++++++++++++-------------
 ipa.init                          |   45 ++++++
 ipa.spec.in                       |   16 ++-
 ipaserver/install/bindinstance.py |    5 +-
 ipaserver/install/cainstance.py   |   14 +-
 ipaserver/install/dsinstance.py   |    5 +-
 ipaserver/install/httpinstance.py |    5 +-
 ipaserver/install/krbinstance.py  |   10 +-
 ipaserver/install/service.py      |   51 ++++++-
 10 files changed, 340 insertions(+), 129 deletions(-)
 create mode 100755 ipa.init

diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install
index 32c9e898768e629405ad33f0a27d29270c586790..67c1a004e914771ee2c9242479e650911dd8cf6f 100755
--- a/install/tools/ipa-server-install
+++ b/install/tools/ipa-server-install
@@ -842,6 +842,10 @@ def main():
     except Exception, e:
         sys.exit("Configuration of client side components failed!\nipa-client-install returned: " + str(e))
 
+
+    #Everything installed properly, activate ipa service.
+    service.chkconfig_on('ipa')
+
     print "=============================================================================="
     print "Setup complete"
     print ""
diff --git a/install/tools/ipactl b/install/tools/ipactl
index 596f07ff4ccc2586c8e16fae4a4f48ed0a34a8cf..6c4db9bf45e3101a4a9dd2835609adb0620e4cdc 100755
--- a/install/tools/ipactl
+++ b/install/tools/ipactl
@@ -1,6 +1,7 @@
-#!/bin/sh
+#!/usr/bin/env python
+# Authors: Simo Sorce <sso...@redhat.com>
 #
-# Copyright (C) 2008  Red Hat
+# Copyright (C) 2008-2010  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or
@@ -16,108 +17,207 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 #
-#
-# IPA control to start/stop the various services required for IPA in the
-# proper order
-# 
-
-# Set IFS so we can do space-embedded lists of services
-IFS=";"
-
-# start and stop are basically a reverse of each other
-services_stop="ipa_kpasswd;httpd;krb5kdc;dirsrv;ntpd;named;pki-cad pki-ca"
-services_start="dirsrv;ntpd;krb5kdc;named;ipa_kpasswd;httpd;pki-cad pki-ca"
-
-function is_running() {
-    # $1 = service to check on
-    # $2 = optional instance to check on, for dirsrv and pki-cad
-
-    # Returns
-    #  0 - running
-    #  1 - pid but dead service
-    #  2 - dead but locked subsys
-    #  3 - stopped
-    #  4 - no such service
-    if [ "$#" = 2 ] ; then
-        /sbin/service $1 status $2 > /dev/null 2>&1
-    else
-        out=`/sbin/service $1 status 2>&1`
-    fi
-    case "$?" in
-        0)
-            return 0;;
-        1)
-            x=`echo $out | grep -c exists`
-            if [ $x -eq 1 ] ; then
-                return 1
-            else
-                return 4
-            fi
-            ;;
-        2)
-            return 2;;
-        3)
-            return 3;;
-    esac
-}
-
-function start() {
-    for service in $services_start ; do
-        is_running $service
-        case "$?" in
-            0)  # running
-                ;;
-            4)  # no such service
-                ;;
-            *)  # otherwise not running
-                /sbin/service $service start
-                ;;
-        esac
-    done
-}
-
-function stop() {
-    for service in $services_stop ; do
-        is_running $service
-        case "$?" in
-            0)  # running
-                /sbin/service $service stop
-                ;;
-            *)  # otherwise not running or doesn't exist
-                ;;
-        esac
-    done
-}
-
-function status() {
-    for service in $services_start ; do
-        is_running $service
-        case "$?" in
-            4)
-                ;;
-            *)
-                /sbin/service $service status
-                ;;
-        esac
-    done
-}
-
-case "$1" in
-restart)
-    stop
-    start
-    ;;
-start)
-    start
-    ;;
-stop)
-    stop
-    ;;
-status)
-    status
-    ;;
-*)
-    echo "Usage: ipactl {start|stop|restart|status}"
-    exit 1
-    ;;
-esac
+
+import sys
+try:
+    from ipaserver.install import service
+    from ipapython import config
+    from ipalib import api, errors
+    import logging
+    import ldap
+    import socket
+    import syslog
+except ImportError:
+    print >> sys.stderr, """\
+There was a problem importing one of the required Python modules. The
+error was:
+
+    %s
+""" % sys.exc_value
+    sys.exit(1)
+
+def parse_options():
+    usage = "%prog start|stop|restart|status\n"
+    parser = config.IPAOptionParser(usage=usage,
+                                    formatter=config.IPAFormatter())
+
+    parser.add_option("-d", "--debug", action="store_true", dest="debug",
+                      help="Display debugging information")
+
+    options, args = parser.parse_args()
+    safe_options = parser.get_safe_opts(options)
+
+    return safe_options, options, args
+
+def emit_err(err):
+    syslog.syslog(syslog.LOG_ERR, err)
+    print err
+
+def get_config():
+    base = "cn=%s,cn=masters,cn=ipa,cn=etc,%s" % (socket.gethostname(),
+                                                  api.env.basedn)
+    srcfilter = '(ipaConfigString=enabledService)'
+    attrs = ['cn', 'ipaConfigString']
+
+    try:
+        con = ldap.initialize(api.env.ldap_uri)
+        con.simple_bind()
+        res = con.search_st(base,
+                            ldap.SCOPE_SUBTREE,
+                            filterstr=srcfilter,
+                            attrlist=attrs,
+                            timeout=10)
+    except e:
+        print "Error retrieving list of services %s" % e
+        print "Is IPA installed ?"
+        return
+
+    svc_list = []
+
+    for entry in res:
+        name = entry[1]['cn'][0]
+        for p in entry[1]['ipaConfigString']:
+            if p.startswith('startOrder '):
+                order = p.split()[1]
+        svc_list.append((order, name))
+
+    return svc_list
+
+def ipa_start():
+
+    try:
+        print "Starting Directory Service"
+        service.start('dirsrv')
+    except:
+        emit_err("Failed to start Directory Service")
+        return
+
+    svc_list = get_config()
+
+    for (order, svc) in sorted(svc_list):
+        svc_name = service.SERVICE_LIST[svc][0]
+        try:
+            print "Starting %s Service" % svc
+            service.start(svc_name)
+        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]
+                try:
+                    service.stop(svc_name)
+                except:
+                    pass
+            try:
+                service.stop('dirsrv')
+            except:
+                pass
+            return
+
+def ipa_stop():
+
+    svc_list = get_config()
+
+    for (order, svc) in sorted(svc_list, reverse=True):
+        svc_name = service.SERVICE_LIST[svc][0]
+        try:
+            print "Stopping %s Service" % svc
+            service.stop(svc_name)
+        except:
+            emit_err("Failed to stop %s Service" % svc)
+
+    try:
+        print "Stopping Directory Service"
+        service.stop('dirsrv')
+    except:
+        emit_err("Failed to stop Directory Service")
+        return
+
+
+def ipa_restart():
+    try:
+        print "Restarting Directory Service"
+        service.restart('dirsrv')
+    except:
+        emit_err("Failed to restart Directory Service")
+        return
+
+    svc_list = get_config()
+
+    for (order, svc) in sorted(svc_list):
+        svc_name = service.SERVICE_LIST[svc][0]
+        try:
+            print "Restarting %s Service" % svc
+            service.restart(svc_name)
+        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]
+                try:
+                    service.stop(svc_name)
+                except:
+                    pass
+            try:
+                service.stop('dirsrv')
+            except:
+                pass
+            return
+
+def ipa_status():
+    try:
+        if service.is_running('dirsrv'):
+            print "Directory Service: RUNNING"
+        else:
+            print "Directory Service: STOPPED"
+    except:
+        print "Failed to get Directory Service status"
+        return
+
+    svc_list = get_config()
+
+    for (order, svc) in sorted(svc_list):
+        svc_name = service.SERVICE_LIST[svc][0]
+        try:
+            if service.is_running(svc_name):
+                print "%s Service: RUNNING" % svc
+            else:
+                print "%s Service: STOPPED" % svc
+        except:
+            print "Failed to get %s Service status" % svc
+
+def main():
+
+    safe_options, options, args = parse_options()
+
+    if len(args) != 1:
+        sys.exit("You must specify one action")
+    elif args[0] != "start" and args[0] != "stop" and args[0] != "restart" and args[0] != "status":
+        sys.exit("Unrecognized action [" + args[0] + "]")
+
+    api.bootstrap(context='cli', debug=options.debug)
+    api.finalize()
+
+    syslog.openlog('ipa', syslog.LOG_NDELAY, syslog.LOG_DAEMON)
+
+    if args[0].lower() == "start":
+        ipa_start()
+    elif args[0].lower() == "stop":
+        ipa_stop()
+    elif args[0].lower() == "restart":
+        ipa_restart()
+    elif args[0].lower() == "status":
+        ipa_status()
+
+    syslog.closelog()
+
+try:
+    if __name__ == "__main__":
+        sys.exit(main())
+except RuntimeError, e:
+    print "%s" % e
+    sys.exit(1)
+except SystemExit, e:
+    sys.exit(e)
+except KeyboardInterrupt, e:
+    sys.exit(1)
diff --git a/ipa.init b/ipa.init
new file mode 100755
index 0000000000000000000000000000000000000000..92c9f49185b3032f7dfda9d740546c4c882f9c76
--- /dev/null
+++ b/ipa.init
@@ -0,0 +1,45 @@
+#!/bin/sh
+#
+# ipa    This starts and stops ipa
+#
+# chkconfig:   - 21 79
+# description: IPA Server
+# processname: /usr/sbin/ns-slapd
+# configdir:   /etc/ipa/
+# piddir:      /var/run/dirsrv
+#
+
+# Source function library.
+if [ -f /etc/rc.d/init.d/functions ] ; then
+. /etc/rc.d/init.d/functions
+fi
+# Source networking configuration.
+if [ -f /etc/sysconfig/network ] ; then
+. /etc/sysconfig/network
+fi
+
+# Check that networking is up.
+if [ "${NETWORKING}" = "no" ]
+then
+    echo "Networking is down"
+    exit 0
+fi
+
+# Lockfile
+if [ -d "/var/lock/subsys" ] ; then
+    lockfile="/var/lock/subsys/dirsrv"
+else
+    lockfile="/var/lock/dirsrv/lock"
+fi
+
+case "$1" in
+    start|stop|restart|status)
+        /usr/sbin/ipactl $1
+        ;;
+    condrestart)
+        [ ! -f $lockfile ] || /usr/sbin/ipactl restart
+        ;;
+    *)
+        echo "Usage: $0 {start|stop|status|restart|condrestart}"
+        exit 2
+esac
diff --git a/ipa.spec.in b/ipa.spec.in
index 2597dad85d2f4b3ab8b876fe0adec27b41651a70..f808e415852046595ec6ca35f1ed3b12b1fc0814 100644
--- a/ipa.spec.in
+++ b/ipa.spec.in
@@ -94,6 +94,8 @@ Requires(post): selinux-policy-base
 Requires: slapi-nis >= 0.15
 Requires: pki-ca >= 1.3.6
 Requires: pki-silent >= 1.3.4
+Requires(preun):  python initscripts chkconfig
+Requires(postun): python initscripts chkconfig
 
 %description server
 IPA is an integrated solution to provide centrally managed Identity (machine,
@@ -280,7 +282,9 @@ ln -s ../../../..%{_sysconfdir}/ipa/html/unauthorized.html \
 mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/httpd/conf.d/
 /bin/touch $RPM_BUILD_ROOT%{_sysconfdir}/httpd/conf.d/ipa.conf
 /bin/touch $RPM_BUILD_ROOT%{_sysconfdir}/httpd/conf.d/ipa-rewrite.conf
+install -m755 ipa.init $RPM_BUILD_ROOT%{_initrddir}/ipa
 %endif
+
 mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/ipa/
 /bin/touch $RPM_BUILD_ROOT%{_sysconfdir}/ipa/default.conf
 mkdir -p %{buildroot}/%{_localstatedir}/lib/ipa-client/sysrestore
@@ -296,6 +300,7 @@ rm -rf %{buildroot}
 %if ! %{ONLY_CLIENT}
 %post server
 if [ $1 = 1 ]; then
+    /sbin/chkconfig --add ipa
     /sbin/chkconfig --add ipa_kpasswd
 fi
 if [ -e /usr/share/ipa/serial ]; then
@@ -305,15 +310,14 @@ fi
 
 %preun server
 if [ $1 = 0 ]; then
+    /sbin/chkconfig --del ipa
     /sbin/chkconfig --del ipa_kpasswd
-    /sbin/service ipa_kpasswd stop >/dev/null 2>&1 || :
+    /sbin/service ipa stop >/dev/null 2>&1 || :
 fi
 
 %postun server
 if [ "$1" -ge "1" ]; then
-    /sbin/service ipa_kpasswd condrestart >/dev/null 2>&1 || :
-    /sbin/service httpd condrestart >/dev/null 2>&1 || :
-    /sbin/service dirsrv condrestart >/dev/null 2>&1 || :
+    /sbin/service ipa condrestart >/dev/null 2>&1 || :
 fi
 
 %pre server-selinux
@@ -373,6 +377,7 @@ fi
 %{_sbindir}/ipa_kpasswd
 %{_sbindir}/ipactl
 %{_sbindir}/ipa-upgradeconfig
+%attr(755,root,root) %{_initrddir}/ipa
 %attr(755,root,root) %{_initrddir}/ipa_kpasswd
 %{python_sitelib}/ipaserver/*
 %dir %{_usr}/share/ipa
@@ -503,6 +508,9 @@ fi
 %endif
 
 %changelog
+* Tue Dec  7 2010 Simo Sorce <sso...@redhat.com> - 1.99-33
+- Add ipa init script
+
 * Fri Nov 19 2010 Rob Crittenden <rcrit...@redhat.com> - 1.99-32
 - Set minimum level of 389-ds-base to 1.2.7 for enhanced memberof plugin
 
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index a10b854649c0f45163e377bd190151d6c24a2f1f..30ce41138c2567603ab890304c626f778fc2225f 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -275,7 +275,10 @@ class BindInstance(service.Service):
 
     def __enable(self):
         self.backup_state("enabled", self.is_running())
-        self.chkconfig_on()
+        # We do not let the system start IPA components on its own,
+        # Instead we reply on the IPA init script to start only enabled
+        # components as found in our LDAP configuration tree
+        self.ldap_enable('DNS', self.fqdn, self.dm_password, self.suffix)
 
     def __setup_sub_dict(self):
         if self.forwarders:
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 5f13b721fd23689c4e19d7764d318cef4142641b..4a645bc84f22b86edac17f5f13150692edb8311f 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -242,7 +242,6 @@ class CADSInstance(service.Service):
 
         self.step("creating directory server user", self.__create_ds_user)
         self.step("creating directory server instance", self.__create_instance)
-        self.step("configuring directory to start on boot", self.__enable)
         self.step("restarting directory server", self.__restart_instance)
 
         self.start_creation("Configuring directory server for the CA", 30)
@@ -255,13 +254,6 @@ class CADSInstance(service.Service):
                              SERVER_ROOT=server_root, DOMAIN=self.domain,
                              TIME=int(time.time()), DSPORT=self.ds_port)
 
-    def __enable(self):
-        name = self.service_name
-        self.service_name="dirsrv"
-        self.backup_state("enabled", self.is_enabled())
-        self.chkconfig_on()
-        self.service_name = name
-
     def __create_ds_user(self):
         user_exists = True
         try:
@@ -483,7 +475,11 @@ class CAInstance(service.Service):
 
     def __enable(self):
         self.backup_state("enabled", self.is_enabled())
-        self.chkconfig_on()
+        # We do not let the system start IPA components on its own,
+        # Instead we reply on the IPA init script to start only enabled
+        # components as found in our LDAP configuration tree
+        suffix = util.realm_to_suffix(self.realm)
+        self.ldap_enable('CA', self.fqdn, self.dm_password, suffix)
 
     def __create_ca_user(self):
         user_exists = True
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 03066984e0a0277bca9378cabdfb2fc229a355f3..6fdc479ca5631c776b6787b1fdcfc6806d437993 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -295,7 +295,10 @@ class DsInstance(service.Service):
 
     def __enable(self):
         self.backup_state("enabled", self.is_enabled())
-        self.chkconfig_on()
+        # At the end of the installation ipa-server-install will enable the
+        # 'ipa' service wich takes care of starting/stopping dirsrv
+        # self.chkconfig_on()
+        self.chkconfig_off()
 
     def __setup_sub_dict(self):
         server_root = find_server_root()
diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py
index f55995b197d4d3968f576f940854a0c1d8a6ad63..73930825fa02e1e714af9d725f29711dc2c6b102 100644
--- a/ipaserver/install/httpinstance.py
+++ b/ipaserver/install/httpinstance.py
@@ -91,7 +91,10 @@ class HTTPInstance(service.Service):
 
     def __enable(self):
         self.backup_state("enabled", self.is_running())
-        self.chkconfig_on()
+        # We do not let the system start IPA components on its own,
+        # Instead we reply on the IPA init script to start only enabled
+        # components as found in our LDAP configuration tree
+        self.ldap_enable('HTTP', self.fqdn, self.dm_password, self.suffix)
 
     def __selinux_config(self):
         selinux=0
diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py
index 8c22e6f41bc0e4266cc6cb12ce0b38b84585c283..516c7eac5b4709f51b8b25753e649f91165a0f56 100644
--- a/ipaserver/install/krbinstance.py
+++ b/ipaserver/install/krbinstance.py
@@ -203,8 +203,7 @@ class KrbInstance(service.Service):
         self.start_creation("Configuring Kerberos KDC", 30)
 
         self.kpasswd = KpasswdInstance()
-
-        self.kpasswd.create_instance()
+        self.kpasswd.create_instance('KPASSWD', self.fqdn, self.admin_password, self.suffix)
 
     def create_replica(self, ds_user, realm_name, host_name,
                        domain_name, admin_password,
@@ -233,7 +232,7 @@ class KrbInstance(service.Service):
         self.start_creation("Configuring Kerberos KDC", 30)
 
         self.kpasswd = KpasswdInstance()
-        self.kpasswd.create_instance()
+        self.kpasswd.create_instance('KPASSWD', self.fqdn, self.admin_password, self.suffix)
 
     def __copy_ldap_passwd(self, filename):
         self.fstore.backup_file("/var/kerberos/krb5kdc/ldappwd")
@@ -258,7 +257,10 @@ class KrbInstance(service.Service):
 
     def __enable(self):
         self.backup_state("enabled", self.is_enabled())
-        self.chkconfig_on()
+        # We do not let the system start IPA components on its own,
+        # Instead we reply on the IPA init script to start only enabled
+        # components as found in our LDAP configuration tree
+        self.ldap_enable('KDC', self.fqdn, self.admin_password, self.suffix)
 
     def __start_instance(self):
         try:
diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py
index 43437306ee63d4527a8fed0d4051a68e466e646a..41b5455d308833005fe81239b3cdacd1d15a113f 100644
--- a/ipaserver/install/service.py
+++ b/ipaserver/install/service.py
@@ -29,6 +29,13 @@ import base64
 import time
 import datetime
 
+SERVICE_LIST = {
+    'KDC':('krb5kdc', 10),
+    'KPASSWD':('ipa_kpasswd', 20),
+    'DNS':('named', 30),
+    'HTTP':('httpd', 40),
+    'CA':('pki_cad', 50)
+}
 
 def stop(service_name, instance_name=""):
     ipautil.run(["/sbin/service", service_name, "stop", instance_name])
@@ -263,8 +270,44 @@ class Service:
 
         self.steps = []
 
+    def __get_conn(self, dm_password):
+        try:
+            conn = ipaldap.IPAdmin("127.0.0.1")
+            conn.simple_bind_s("cn=directory manager", dm_password)
+        except Exception, e:
+            logging.critical("Could not connect to the Directory Server on %s: %s" % (self.fqdn, str(e)))
+            raise e
+
+        return conn
+
+    def ldap_enable(self, name, fqdn, dm_password, ldap_suffix):
+        self.chkconfig_off()
+        conn = self.__get_conn(dm_password)
+
+        entry_name = "cn=%s,cn=%s,%s,%s" % (name, fqdn,
+                                            "cn=masters,cn=ipa,cn=etc",
+                                            ldap_suffix)
+        order = SERVICE_LIST[name][1]
+        entry = ipaldap.Entry(entry_name)
+        entry.setValues("objectclass",
+                        "nsContainer", "ipaConfigObject")
+        entry.setValues("cn", name)
+        entry.setValues("ipaconfigstring",
+                        "enabledService", "startOrder " + str(order))
+
+        try:
+            conn.add_s(entry)
+        except ldap.ALREADY_EXISTS:
+            logging.critical("failed to add %s Service startup entry" % name)
+            raise e
+
 class SimpleServiceInstance(Service):
-    def create_instance(self):
+    def create_instance(self, gensvc_name=None, fqdn=None, dm_password=None, ldap_suffix=None):
+        self.gensvc_name = gensvc_name
+        self.fqdn = fqdn
+        self.dm_password = dm_password
+        self.suffix = ldap_suffix
+
         self.step("starting %s " % self.service_name, self.__start)
         self.step("configuring %s to start on boot" % self.service_name, self.__enable)
         self.start_creation("Configuring %s" % self.service_name)
@@ -276,7 +319,11 @@ class SimpleServiceInstance(Service):
     def __enable(self):
         self.chkconfig_add()
         self.backup_state("enabled", self.is_enabled())
-        self.chkconfig_on()
+        if self.gensvc_name == None:
+            self.chkconfig_on()
+        else:
+            self.ldap_enable(self.gensvc_name, self.fqdn,
+                             self.dm_password, self.suffix)
 
     def uninstall(self):
         if self.is_configured():
-- 
1.7.3.2

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

Reply via email to