>From 8d3166f13f1b977104afafb9d730efb7dd7fc8dd Mon Sep 17 00:00:00 2001
From: Mike McLean <mikem@redhat.com>
Date: Tue, 20 Jan 2015 16:13:12 -0500
Subject: [PATCH] Support conf.d in kojihub and kojiweb

---
 cli/koji                      | 22 +++-------------------
 hub/kojixmlrpc.py             | 26 ++++++++++++++++++--------
 koji/__init__.py              | 16 ++++++++++++++++
 www/kojiweb/wsgi_publisher.py | 25 ++++++++++++++++++-------
 4 files changed, 55 insertions(+), 34 deletions(-)

diff --git a/cli/koji b/cli/koji
index 6eba62b..f0f5f51 100755
--- a/cli/koji
+++ b/cli/koji
@@ -115,22 +115,6 @@ def arg_filter(arg):
     return arg
 
 
-def config_directory_contents(dir_name):
-    configs = []
-    try:
-        conf_dir_contents = os.listdir(dir_name)
-    except OSError, exception:
-        if exception.errno != errno.ENOENT:
-            raise
-    else:
-        for name in sorted(conf_dir_contents):
-            if not name.endswith('.conf'):
-                continue
-            config_full_name = os.path.join(dir_name, name)
-            configs.append(config_full_name)
-    return configs
-
-
 def get_options():
     """process options from command line and config file"""
 
@@ -225,13 +209,13 @@ def get_options():
         'authtype': None
         }
     #note: later config files override earlier ones
-    configs = config_directory_contents('/etc/koji.conf.d')
+    configs = koji.config_directory_contents('/etc/koji.conf.d')
     if os.access('/etc/koji.conf', os.F_OK):
         configs.append('/etc/koji.conf')
     if options.configFile:
         fn = os.path.expanduser(options.configFile)
         if os.path.isdir(fn):
-            contents = config_directory_contents(fn)
+            contents = koji.config_directory_contents(fn)
             if not contents:
                 parser.error("No config files found in directory: %s" % fn)
             configs.extend(contents)
@@ -241,7 +225,7 @@ def get_options():
             configs.append(fn)
     else:
         user_config_dir = os.path.expanduser("~/.koji/config.d")
-        configs.extend(config_directory_contents(user_config_dir))
+        configs.extend(koji.config_directory_contents(user_config_dir))
         fn = os.path.expanduser("~/.koji/config")
         if os.access(fn, os.F_OK):
             configs.append(fn)
diff --git a/hub/kojixmlrpc.py b/hub/kojixmlrpc.py
index 048bc8a..e7dd0df 100644
--- a/hub/kojixmlrpc.py
+++ b/hub/kojixmlrpc.py
@@ -382,20 +382,30 @@ def load_config(environ):
           will disappear in a future version of Koji
     """
     logger = logging.getLogger("koji")
-    #get our config file
+    #get our config file(s)
     if 'modpy.opts' in environ:
         modpy_opts = environ.get('modpy.opts')
         cf = modpy_opts.get('ConfigFile', None)
+        cfdir =  modpy_opts.get('ConfigDir', None)
+        # to aid in the transition from PythonOptions to hub.conf, we only load
+        # the configfile if it is explicitly configured
+        if not cf and not cfdir:
+            logger.warn('Warning: configuring Koji via PythonOptions is deprecated. Use hub.conf')
     else:
         cf = environ.get('koji.hub.ConfigFile', '/etc/koji-hub/hub.conf')
+        cfdir = environ.get('koji.hub.ConfigDir', '/etc/koji-hub/hub.conf.d')
         modpy_opts = {}
-    if cf:
-        # to aid in the transition from PythonOptions to hub.conf, we only load
-        # the configfile if it is explicitly configured
+    if cfdir:
+        configs = koji.config_directory_contents(cfdir)
+    else:
+        configs = []
+    if cf and os.path.isfile(cf):
+        configs.append(cf)
+    if configs:
         config = RawConfigParser()
-        config.read(cf)
+        config.read(configs)
     else:
-        logger.warn('Warning: configuring Koji via PythonOptions is deprecated. Use hub.conf')
+        config = None
     cfgmap = [
         #option, type, default
         ['DBName', 'string', None],
@@ -456,7 +466,7 @@ def load_config(environ):
     ]
     opts = {}
     for name, dtype, default in cfgmap:
-        if cf:
+        if config:
             key = ('hub', name)
             if config.has_option(*key):
                 if dtype == 'integer':
@@ -481,7 +491,7 @@ def load_config(environ):
         opts['DBHost'] = opts['DBhost']
     # load policies
     # (only from config file)
-    if cf and config.has_section('policy'):
+    if config and config.has_section('policy'):
         #for the moment, we simply transfer the policy conf to opts
         opts['policy'] = dict(config.items('policy'))
     else:
diff --git a/koji/__init__.py b/koji/__init__.py
index a1fae97..d133ed1 100644
--- a/koji/__init__.py
+++ b/koji/__init__.py
@@ -1436,6 +1436,22 @@ def openRemoteFile(relpath, topurl=None, topdir=None):
     return fo
 
 
+def config_directory_contents(dir_name):
+    configs = []
+    try:
+        conf_dir_contents = os.listdir(dir_name)
+    except OSError, exception:
+        if exception.errno != errno.ENOENT:
+            raise
+    else:
+        for name in sorted(conf_dir_contents):
+            if not name.endswith('.conf'):
+                continue
+            config_full_name = os.path.join(dir_name, name)
+            configs.append(config_full_name)
+    return configs
+
+
 class PathInfo(object):
     # ASCII numbers and upper- and lower-case letter for use in tmpdir()
     ASCII_CHARS = [chr(i) for i in range(48, 58) + range(65, 91) + range(97, 123)]
diff --git a/www/kojiweb/wsgi_publisher.py b/www/kojiweb/wsgi_publisher.py
index 4c0aee1..4f58b8e 100644
--- a/www/kojiweb/wsgi_publisher.py
+++ b/www/kojiweb/wsgi_publisher.py
@@ -118,21 +118,32 @@ class Dispatcher(object):
         modpy_opts = environ.get('modpy.opts', {})
         if 'modpy.opts' in environ:
             cf = modpy_opts.get('koji.web.ConfigFile', None)
+            cfdir =  modpy_opts.get('koji.web.ConfigDir', None)
             # to aid in the transition from PythonOptions to web.conf, we do
             # not check the config file by default, it must be configured
+            if not cf and not cfdir:
+                self.logger.warn('Warning: configuring Koji via PythonOptions is deprecated. Use web.conf')
         else:
             cf = environ.get('koji.web.ConfigFile', '/etc/kojiweb/web.conf')
-        if cf:
-            if not os.path.isfile(cf):
-                raise koji.GenericError, "Configuration missing: %s" % cf
+            cfdir = environ.get('koji.web.ConfigDir', '/etc/kojiweb/web.conf.d')
+        if cfdir:
+            configs = koji.config_directory_contents(cfdir)
+        else:
+            configs = []
+        if cf and os.path.isfile(cf):
+            configs.append(cf)
+        if configs:
             config = RawConfigParser()
-            config.read(cf)
+            config.read(configs)
+        elif modpy_opts:
+            # presumably we are configured by modpy options
+            config = None
         else:
-            #can only happen under mod_python
-            self.logger.warn('Warning: configuring Koji via PythonOptions is deprecated. Use web.conf')
+            raise koji.GenericError, "Configuration missing"
+
         opts = {}
         for name, dtype, default in self.cfgmap:
-            if cf:
+            if config:
                 key = ('web', name)
                 if config.has_option(*key):
                     if dtype == 'integer':
-- 
1.9.3

