From 4c1928f377b15801b053269351611e7ea1ceaa38 Mon Sep 17 00:00:00 2001 From: Yu Ming Zhu Date: Oct 15 2019 07:14:16 +0000 Subject: extract read_config_files util for config parsing --- diff --git a/builder/kojid b/builder/kojid index dfb743c..aa35c7d 100755 --- a/builder/kojid +++ b/builder/kojid @@ -47,7 +47,6 @@ import time import traceback import xml.dom.minidom import zipfile -from six.moves.configparser import RawConfigParser from fnmatch import fnmatch from gzip import GzipFile from optparse import OptionParser, SUPPRESS_HELP @@ -6109,8 +6108,7 @@ def get_options(): assert False # pragma: no cover # load local config - config = RawConfigParser() - config.read(options.configFile) + config = koji.read_config_files(options.configFile) for x in config.sections(): if x != 'kojid': quit('invalid section found in config file: %s' % x) diff --git a/cli/koji_cli/commands.py b/cli/koji_cli/commands.py index e95b0cb..72926ef 100644 --- a/cli/koji_cli/commands.py +++ b/cli/koji_cli/commands.py @@ -5944,10 +5944,8 @@ def handle_image_build(options, session, args): (task_options, args) = parser.parse_args(args) if task_options.config: - if not os.path.exists(task_options.config): - parser.error(_("%s not found!" % task_options.config)) section = 'image-build' - config = koji.read_config_files(task_options.config) + config = koji.read_config_files(task_options.config, strict=True) if not config.has_section(section): parser.error(_("single section called [%s] is required" % section)) # pluck out the positional arguments first diff --git a/hub/kojixmlrpc.py b/hub/kojixmlrpc.py index 34f1087..9c081aa 100644 --- a/hub/kojixmlrpc.py +++ b/hub/kojixmlrpc.py @@ -20,7 +20,6 @@ from __future__ import absolute_import from __future__ import division -from six.moves.configparser import RawConfigParser import datetime import inspect import logging @@ -399,17 +398,8 @@ def load_config(environ): #get our config file(s) cf = environ.get('koji.hub.ConfigFile', '/etc/koji-hub/hub.conf') cfdir = environ.get('koji.hub.ConfigDir', '/etc/koji-hub/hub.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(configs) - else: - config = None + config = koji.read_config_files([cfdir, cf], raw=True, strict=True) + cfgmap = [ #option, type, default ['DBName', 'string', None], diff --git a/koji/__init__.py b/koji/__init__.py index c591247..c141cbc 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -1685,7 +1685,8 @@ def config_directory_contents(dir_name): if not name.endswith('.conf'): continue config_full_name = os.path.join(dir_name, name) - configs.append(config_full_name) + if os.path.isfile(config_full_name): + configs.append(config_full_name) return configs @@ -1727,60 +1728,50 @@ def read_config(profile_name, user_config=None): #note: later config files override earlier ones + strict = False # /etc/koji.conf.d - configs = config_directory_contents('/etc/koji.conf.d') + configs = ['/etc/koji.conf.d'] # /etc/koji.conf - if os.access('/etc/koji.conf', os.F_OK): - configs.append('/etc/koji.conf') + configs.append('/etc/koji.conf') # User specific configuration if user_config: # Config file specified on command line - fn = os.path.expanduser(user_config) - if os.path.isdir(fn): - # Specified config is a directory - contents = config_directory_contents(fn) - if not contents: - raise ConfigurationError("No config files found in directory: %s" % fn) - configs.extend(contents) - else: - # Specified config is a file - if not os.access(fn, os.F_OK): - raise ConfigurationError("No such file: %s" % fn) - configs.append(fn) + # The existence will be checked + configs.append(os.path.expanduser(user_config)) + strict = True else: - # User config - user_config_dir = os.path.expanduser("~/.koji/config.d") - configs.extend(config_directory_contents(user_config_dir)) - fn = os.path.expanduser("~/.koji/config") - if os.access(fn, os.F_OK): - configs.append(fn) + # User config dir + configs.append(os.path.expanduser("~/.koji/config.d")) + # User config file + configs.append(os.path.expanduser("~/.koji/config")) + + config = read_config_files(configs, strict=strict) # Load the configs in a particular order got_conf = False - for configFile in configs: - config = read_config_files(configFile) - if config.has_section(profile_name): - got_conf = True - for name, value in config.items(profile_name): - #note the config_defaults dictionary also serves to indicate which - #options *can* be set via the config file. Such options should - #not have a default value set in the option parser. - if name in result: - if name in ('anon_retry', 'offline_retry', 'use_fast_upload', - 'krb_rdns', 'debug', 'debug', 'debug_xmlrpc', 'krb_canon_host'): - result[name] = config.getboolean(profile_name, name) - elif name in ('max_retries', 'retry_interval', - 'offline_retry_interval', 'poll_interval', - 'timeout', 'auth_timeout', - 'upload_blocksize', 'pyver'): - try: - result[name] = int(value) - except ValueError: - raise ConfigurationError("value for %s config option must be a valid integer" % name) - else: - result[name] = value + if config.has_section(profile_name): + got_conf = True + for name, value in config.items(profile_name): + #note the config_defaults dictionary also serves to indicate which + #options *can* be set via the config file. Such options should + #not have a default value set in the option parser. + if name in result: + if name in ('anon_retry', 'offline_retry', + 'use_fast_upload', 'krb_rdns', 'debug', + 'debug_xmlrpc', 'krb_canon_host'): + result[name] = config.getboolean(profile_name, name) + elif name in ('max_retries', 'retry_interval', + 'offline_retry_interval', 'poll_interval', + 'timeout', 'auth_timeout', + 'upload_blocksize', 'pyver'): + try: + result[name] = int(value) + except ValueError: + raise ConfigurationError("value for %s config option must be a valid integer" % name) + else: + result[name] = value # Check if the specified profile had a config specified if configs and not got_conf: @@ -1853,17 +1844,20 @@ def get_profile_module(profile_name, config=None): return mod -def read_config_files(config_files, raw=False): +def read_config_files(config_files, default=None, raw=False, strict=False): """Use parser to read config file(s) - :param config_files: config file(s) to read (required). + :param config_files: config file(s) to read (required). Config file could + be file or directory, and order is preserved :type config_files: str or list + :param str default: default config file which is loaded before + config_files. If specified, it must be readable. :param bool raw: enable 'raw' parsing (no interpolation). Default: False + :param bool strict: enable reading check for each item in config_files. + Default: False :return: object of parser which contains parsed content """ - if not isinstance(config_files, (list, tuple)): - config_files = [config_files] if raw: parser = six.moves.configparser.RawConfigParser elif six.PY2: @@ -1873,12 +1867,33 @@ def read_config_files(config_files, raw=False): # deprecated alias parser = six.moves.configparser.ConfigParser config = parser() - for config_file in config_files: - with open(config_file, 'r') as f: + if default: + with open(default, 'r') as f: if six.PY2: config.readfp(f) else: config.read_file(f) + if not isinstance(config_files, (list, tuple)): + config_files = [config_files] + cfgs = [] + # append dir contents + for config_file in config_files: + if os.path.isdir(config_file): + fns = config_directory_contents(config_file) + if fns: + cfgs.extend(fns) + else: + logging.debug("No config files found in directory: %s" + % config_file) + else: + cfgs.append(config_file) + # checking access if strict is True + if strict: + for cf in cfgs: + if not os.path.isfile(cf) or not os.access(cf, os.F_OK): + raise ConfigurationError("Config file %s can't be opened." + % cf) + config.read(cfgs) return config diff --git a/plugins/builder/runroot.py b/plugins/builder/runroot.py index c667089..5490d96 100644 --- a/plugins/builder/runroot.py +++ b/plugins/builder/runroot.py @@ -49,8 +49,7 @@ class RunRootTask(koji.tasks.BaseTaskHandler): return res def _read_config(self): - cp = six.moves.configparser.SafeConfigParser() - cp.read(CONFIG_FILE) + cp = koji.read_config_files(CONFIG_FILE) self.config = { 'default_mounts': [], 'safe_roots': [], diff --git a/plugins/builder/save_failed_tree.py b/plugins/builder/save_failed_tree.py index 7c579a7..f449088 100644 --- a/plugins/builder/save_failed_tree.py +++ b/plugins/builder/save_failed_tree.py @@ -3,7 +3,6 @@ import fnmatch import os import sys import tarfile -import six.moves.configparser import koji import koji.tasks as tasks @@ -28,8 +27,7 @@ def omit_paths3(tarinfo): def read_config(): global config - cp = six.moves.configparser.SafeConfigParser() - cp.read(CONFIG_FILE) + cp = koji.read_config_files(CONFIG_FILE) config = { 'path_filters': [], 'volume': None, diff --git a/plugins/hub/protonmsg.py b/plugins/hub/protonmsg.py index 4953529..8a1953c 100644 --- a/plugins/hub/protonmsg.py +++ b/plugins/hub/protonmsg.py @@ -269,7 +269,7 @@ def send_queued_msgs(cbtype, *args, **kws): log = logging.getLogger('koji.plugin.protonmsg') global CONFIG if not CONFIG: - CONFIG = koji.read_config_files(CONFIG_FILE) + CONFIG = koji.read_config_files(CONFIG_FILE, strict=True) urls = CONFIG.get('broker', 'urls').split() test_mode = False if CONFIG.has_option('broker', 'test_mode'): diff --git a/plugins/hub/rpm2maven.py b/plugins/hub/rpm2maven.py index 5cedce9..397707f 100644 --- a/plugins/hub/rpm2maven.py +++ b/plugins/hub/rpm2maven.py @@ -11,16 +11,15 @@ from koji.context import context from koji.plugin import callback from koji.util import joinpath from koji.util import rmtree -import six.moves.configparser import fnmatch import os -import shutil import subprocess CONFIG_FILE = '/etc/koji-hub/plugins/rpm2maven.conf' config = None + @callback('postImport') def maven_import(cbtype, *args, **kws): global config @@ -33,8 +32,7 @@ def maven_import(cbtype, *args, **kws): filepath = kws['filepath'] if not config: - config = six.moves.configparser.SafeConfigParser() - config.read(CONFIG_FILE) + config = koji.read_config_files(CONFIG_FILE, strict=True) name_patterns = config.get('patterns', 'rpm_names').split() for pattern in name_patterns: if fnmatch.fnmatch(rpminfo['name'], pattern): @@ -53,6 +51,7 @@ def maven_import(cbtype, *args, **kws): if os.path.exists(tmpdir): rmtree(tmpdir) + def expand_rpm(filepath, tmpdir): devnull = open('/dev/null', 'r+') rpm2cpio = subprocess.Popen(['/usr/bin/rpm2cpio', filepath], @@ -70,6 +69,7 @@ def expand_rpm(filepath, tmpdir): (filepath, rpm2cpio.wait(), cpio.wait())) devnull.close() + def scan_and_import(buildinfo, rpminfo, tmpdir): global config path_patterns = config.get('patterns', 'artifact_paths').split() diff --git a/plugins/hub/save_failed_tree.py b/plugins/hub/save_failed_tree.py index 103bb95..12c0f47 100644 --- a/plugins/hub/save_failed_tree.py +++ b/plugins/hub/save_failed_tree.py @@ -1,6 +1,5 @@ from __future__ import absolute_import import sys -import six.moves.configparser import koji from koji.context import context from koji.plugin import export @@ -29,8 +28,7 @@ def saveFailedTree(buildrootID, full=False, **opts): # read configuration only once if config is None: - config = six.moves.configparser.SafeConfigParser() - config.read(CONFIG_FILE) + config = koji.read_config_files(CONFIG_FILE, strict=True) allowed_methods = config.get('permissions', 'allowed_methods').split() if len(allowed_methods) == 1 and allowed_methods[0] == '*': allowed_methods = '*' diff --git a/tests/test_cli/data/image-build-config-empty.conf b/tests/test_cli/data/image-build-config-empty.conf new file mode 100644 index 0000000..8d3bc94 --- /dev/null +++ b/tests/test_cli/data/image-build-config-empty.conf @@ -0,0 +1 @@ +# empty config file \ No newline at end of file diff --git a/tests/test_cli/test_image_build.py b/tests/test_cli/test_image_build.py index 15f240a..f9211ca 100644 --- a/tests/test_cli/test_image_build.py +++ b/tests/test_cli/test_image_build.py @@ -12,7 +12,10 @@ import koji from koji_cli.commands import handle_image_build, _build_image_oz from . import utils -ConfigParser = six.moves.configparser.ConfigParser +if six.PY2: + ConfigParser = six.moves.configparser.SafeConfigParser +else: + ConfigParser = six.moves.configparser.ConfigParser TASK_OPTIONS = { "background": None, @@ -240,28 +243,32 @@ class TestImageBuild(utils.CliTestCase): """Test handle_image_build argument with --config cases""" # Case 1, config file not exist case - self.assert_system_exit( - handle_image_build, - self.options, - self.session, - ['--config', '/nonexistent-file-755684354'], - stderr=self.format_error_message('/nonexistent-file-755684354 not found!'), - activate_session=None) + with self.assertRaises(koji.ConfigurationError) as cm: + handle_image_build(self.options, + self.session, + ['--config', '/nonexistent-file-755684354']) + self.assertEqual(cm.exception.args[0], + "Config file /nonexistent-file-755684354 can't be opened.") - # Case 2, no image-build section in config file + # Case 2, no image-build section in config file expected = "single section called [%s] is required" % "image-build" self.configparser.return_value = ConfigParser() + self.assert_system_exit( handle_image_build, self.options, self.session, - ['--config', '/dev/null'], + ['--config', + os.path.join(os.path.dirname(__file__), + 'data/image-build-config-empty.conf')], stderr=self.format_error_message(expected), activate_session=None) - config_file = os.path.join(os.path.dirname(__file__), 'data/image-build-config.conf') + config_file = os.path.join(os.path.dirname(__file__), + 'data/image-build-config.conf') + # Case 3, normal handle_image_build( self.options, self.session, diff --git a/tests/test_lib/test_utils.py b/tests/test_lib/test_utils.py index 7ded48a..4cde1da 100644 --- a/tests/test_lib/test_utils.py +++ b/tests/test_lib/test_utils.py @@ -184,49 +184,131 @@ class MiscFunctionTestCase(unittest.TestCase): class ConfigFileTestCase(unittest.TestCase): """Test config file reading functions""" - @mock_open() - @mock.patch("six.moves.configparser.ConfigParser", spec=True) - @mock.patch("six.moves.configparser.RawConfigParser", spec=True) - @mock.patch("six.moves.configparser.SafeConfigParser", spec=True) - def test_read_config_files(self, scp_clz, rcp_clz, cp_clz, open_mock): + def setUp(self): + self.manager = mock.MagicMock() + self.manager.logging = mock.patch('koji.logging').start() + self.manager.isdir = mock.patch("os.path.isdir").start() + self.manager.isfile = mock.patch("os.path.isfile").start() + self.manager.access = mock.patch("os.access", return_value=True).start() + self.manager.open = mock_open().start() + self.manager.cp_clz = mock.patch("six.moves.configparser.ConfigParser", + spec=True).start() + self.manager.scp_clz = mock.patch("six.moves.configparser.SafeConfigParser", + spec=True).start() + self.manager.rcp_clz = mock.patch("six.moves.configparser.RawConfigParser", + spec=True).start() + self.mocks = [self.manager.logging, + self.manager.isdir, + self.manager.isfile, + self.manager.access, + self.manager.open, + self.manager.cp_clz, + self.manager.scp_clz, + self.manager.rcp_clz] + + def reset_mock(self): + for m in self.mocks: + m.reset_mock() + + def tearDown(self): + mock.patch.stopall() + + def test_read_config_files(self): files = 'test1.conf' - conf = koji.read_config_files(files) - open_mock.assert_called_once_with(files, 'r') + default = 'default.conf' + self.manager.isdir.return_value = False + conf = koji.read_config_files(files, default=default) + self.manager.isdir.assert_called_once_with(files) + self.manager.open.assert_called_once_with(default, 'r') if six.PY2: self.assertTrue(isinstance(conf, six.moves.configparser.SafeConfigParser.__class__)) - scp_clz.assert_called_once() - scp_clz.return_value.readfp.assert_called_once() + self.manager.scp_clz.assert_called_once() + self.manager.scp_clz.return_value.readfp.assert_called_once() + self.manager.scp_clz.return_value.read.assert_called_once_with([files]) else: self.assertTrue(isinstance(conf, six.moves.configparser.ConfigParser.__class__)) - cp_clz.assert_called_once() - cp_clz.return_value.read_file.assert_called_once() + self.manager.cp_clz.assert_called_once() + self.manager.cp_clz.return_value.read_file.assert_called_once() + self.manager.cp_clz.return_value.read.assert_called_once_with([files]) - open_mock.reset_mock() - cp_clz.reset_mock() - scp_clz.reset_mock() + # no default + self.reset_mock() + koji.read_config_files(files) + self.manager.open.assert_not_called() + + # list as config_files + self.reset_mock() files = ['test1.conf', 'test2.conf'] koji.read_config_files(files) - open_mock.assert_has_calls([call('test1.conf', 'r'), - call('test2.conf', 'r')], - any_order=True) + self.manager.open.assert_not_called() + if six.PY2: - scp_clz.assert_called_once() - self.assertEqual(scp_clz.return_value.readfp.call_count, 2) + parser_clz = self.manager.scp_clz else: - cp_clz.assert_called_once() - self.assertEqual(cp_clz.return_value.read_file.call_count, 2) + parser_clz = self.manager.cp_clz + parser_clz.assert_called_once() + parser_clz.return_value.read.assert_called_once_with(files) - open_mock.reset_mock() - cp_clz.reset_mock() - scp_clz.reset_mock() + # raw + self.reset_mock() conf = koji.read_config_files(files, raw=True) self.assertTrue(isinstance(conf, six.moves.configparser.RawConfigParser.__class__)) - cp_clz.assert_not_called() - scp_clz.assert_not_called() - rcp_clz.assert_called_once() + self.manager.cp_clz.assert_not_called() + self.manager.scp_clz.assert_not_called() + self.manager.rcp_clz.assert_called_once() + + # strict + # case1, not a file + self.reset_mock() + self.manager.isfile.side_effect = [True, False] + with self.assertRaises(koji.ConfigurationError) as cm: + koji.read_config_files(files, strict=True) + self.assertEqual(cm.exception.args[0], + "Config file test2.conf can't be opened.") + self.manager.open.assert_not_called() + + # case2, inaccessible + self.reset_mock() + self.manager.isfile.side_effect = None + self.manager.isfile.return_value = True + self.manager.access.side_effect = [True, False] + with self.assertRaises(koji.ConfigurationError) as cm: + koji.read_config_files(files, strict=True) + self.assertEqual(cm.exception.args[0], + "Config file test2.conf can't be opened.") + self.manager.open.assert_not_called() + + # directories + self.reset_mock() + files = ['test1.conf', 'testdir1', 'test2.conf', 'testdir2'] + self.manager.isdir.side_effect = [False, True, False, True] + self.manager.isfile.side_effect = lambda f: False \ + if f == 'test1-4.dir.conf' else True + self.manager.access.side_effect = None + self.manager.access.return_value = True + with mock.patch("os.listdir", side_effect=[['test1-2.conf', + 'test1-1.conf', + 'test1-3.txt', + 'test1-4.dir.conf'], + []]) as listdir_mock: + conf = koji.read_config_files(files) + listdir_mock.assert_has_calls([call('testdir1'), call('testdir2')]) + if six.PY2: + parser_clz = self.manager.scp_clz + else: + parser_clz = self.manager.cp_clz + parser_clz.assert_called_once() + parser_clz.return_value.read.assert_called_once_with( + ['test1.conf', + 'testdir1/test1-1.conf', + 'testdir1/test1-2.conf', + 'testdir1/test1-4.dir.conf', + 'test2.conf']) + self.manager.logging.debug.assert_called_once_with( + "No config files found in directory: testdir2") class MavenUtilTestCase(unittest.TestCase): diff --git a/util/koji-gc b/util/koji-gc index 29e250a..ee28e16 100755 --- a/util/koji-gc +++ b/util/koji-gc @@ -110,63 +110,51 @@ def get_options(): defaults = parser.get_default_values() - config = six.moves.configparser.ConfigParser() - cf = getattr(options, 'config_file', None) - if cf: - if not os.access(cf, os.F_OK): - parser.error(_("No such file: %s") % cf) - assert False # pragma: no cover - else: - cf = '/etc/koji-gc/koji-gc.conf' - if not os.access(cf, os.F_OK): - cf = None - if not cf: - print("no config file") - config = None - else: - config.read(cf) - # List of values read from config file to update default parser values - cfgmap = [ - # name, alias, type - ['keytab', None, 'string'], - ['principal', None, 'string'], - ['krbservice', None, 'string'], - ['krb_rdns', None, 'boolean'], - ['krb_canon_host', None, 'boolean'], + cf = getattr(options, 'config_file', '/etc/koji-gc/koji-gc.conf') + config = koji.read_config_files(cf) + + # List of values read from config file to update default parser values + cfgmap = [ + # name, alias, type + ['keytab', None, 'string'], + ['principal', None, 'string'], + ['krbservice', None, 'string'], + ['krb_rdns', None, 'boolean'], + ['krb_canon_host', None, 'boolean'], ['krb_server_realm', None, 'string'], - ['runas', None, 'string'], - ['user', None, 'string'], - ['password', None, 'string'], - ['noauth', None, 'boolean'], - ['cert', None, 'string'], - ['ca', None, 'string'], # FIXME: remove in next major release - ['serverca', None, 'string'], - ['server', None, 'string'], - ['weburl', None, 'string'], - ['smtp_host', None, 'string'], - ['from_addr', None, 'string'], - ['email_template', None, 'string'], - ['email_domain', None, 'string'], - ['mail', None, 'boolean'], - ['delay', None, 'string'], - ['unprotected_keys', None, 'string'], - ['grace_period', None, 'string'], - ['trashcan_tag', None, 'string'], - ['no_ssl_verify', None, 'boolean'], - ['timeout', None, 'integer'], - ] - for name, alias, type in cfgmap: - if alias is None: - alias = ('main', name) - if config.has_option(*alias): - if options.debug: - print("Using option %s from config file" % (alias,)) - if type == 'integer': - setattr(defaults, name, config.getint(*alias)) - elif type == 'boolean': - setattr(defaults, name, config.getboolean(*alias)) - else: - setattr(defaults, name, config.get(*alias)) + ['runas', None, 'string'], + ['user', None, 'string'], + ['password', None, 'string'], + ['noauth', None, 'boolean'], + ['cert', None, 'string'], + ['ca', None, 'string'], # FIXME: remove in next major release + ['serverca', None, 'string'], + ['server', None, 'string'], + ['weburl', None, 'string'], + ['smtp_host', None, 'string'], + ['from_addr', None, 'string'], + ['email_template', None, 'string'], + ['email_domain', None, 'string'], + ['mail', None, 'boolean'], + ['delay', None, 'string'], + ['unprotected_keys', None, 'string'], + ['grace_period', None, 'string'], + ['trashcan_tag', None, 'string'], + ['no_ssl_verify', None, 'boolean'], + ['timeout', None, 'integer'], + ] + for name, alias, type in cfgmap: + if alias is None: + alias = ('main', name) + if config.has_option(*alias): + if options.debug: + print("Using option %s from config file" % (alias,)) + if type == 'integer': + setattr(defaults, name, config.getint(*alias)) + elif type == 'boolean': + setattr(defaults, name, config.getboolean(*alias)) + else: + setattr(defaults, name, config.get(*alias)) #parse again with defaults (options, args) = parser.parse_args(values=defaults) options.config = config @@ -190,8 +178,8 @@ def get_options(): #parse key aliases options.key_aliases = {} try: - if config and config.has_option('main', 'key_aliases'): - for line in config.get('main','key_aliases').splitlines(): + if config.has_option('main', 'key_aliases'): + for line in config.get('main', 'key_aliases').splitlines(): parts = line.split() if len(parts) < 2: continue diff --git a/util/koji-shadow b/util/koji-shadow index c603c50..3b3afb3 100755 --- a/util/koji-shadow +++ b/util/koji-shadow @@ -31,7 +31,6 @@ except ImportError: # pragma: no cover krbV = None import koji from koji.util import to_list -import six.moves.configparser import fnmatch import optparse import os @@ -156,56 +155,44 @@ def get_options(): (options, args) = parser.parse_args() defaults = parser.get_default_values() - config = six.moves.configparser.ConfigParser() - cf = getattr(options, 'config_file', None) - if cf: - if not os.access(cf, os.F_OK): - parser.error(_("No such file: %s") % cf) - assert False # pragma: no cover - else: - cf = '/etc/koji-shadow/koji-shadow.conf' - if not os.access(cf, os.F_OK): - cf = None - if not cf: - log("no config file") - config = None - else: - config.read(cf) - #allow config file to update defaults - for opt in parser.option_list: - if not opt.dest: - continue - name = opt.dest - alias = ('main', name) - if config.has_option(*alias): - log("Using option %s from config file" % (alias,)) - if opt.action in ('store_true', 'store_false'): - setattr(defaults, name, config.getboolean(*alias)) - elif opt.action != 'store': - pass - elif opt.type in ('int', 'long'): - setattr(defaults, name, config.getint(*alias)) - elif opt.type in ('float'): - setattr(defaults, name, config.getfloat(*alias)) - else: - log(config.get(*alias)) - setattr(defaults, name, config.get(*alias)) - #config file options without a cmdline equivalent - otheropts = [ - #name, type, default - ['keytab', None, 'string'], - ['principal', None, 'string'], - ['runas', None, 'string'], - ['user', None, 'string'], - ['password', None, 'string'], - ['noauth', None, 'boolean'], - ['server', None, 'string'], - ['remote', None, 'string'], - ['max_jobs', None, 'int'], - ['serverca', None, 'string'], - ['auth_cert', None, 'string'], - ['arches', None, 'string'], - ] + cf = getattr(options, 'config_file', '/etc/koji-shadow/koji-shadow.conf') + config = koji.read_config_files(cf) + + #allow config file to update defaults + for opt in parser.option_list: + if not opt.dest: + continue + name = opt.dest + alias = ('main', name) + if config.has_option(*alias): + log("Using option %s from config file" % (alias,)) + if opt.action in ('store_true', 'store_false'): + setattr(defaults, name, config.getboolean(*alias)) + elif opt.action != 'store': + pass + elif opt.type in ('int', 'long'): + setattr(defaults, name, config.getint(*alias)) + elif opt.type in ('float'): + setattr(defaults, name, config.getfloat(*alias)) + else: + log(config.get(*alias)) + setattr(defaults, name, config.get(*alias)) + #config file options without a cmdline equivalent + otheropts = [ + #name, type, default + ['keytab', None, 'string'], + ['principal', None, 'string'], + ['runas', None, 'string'], + ['user', None, 'string'], + ['password', None, 'string'], + ['noauth', None, 'boolean'], + ['server', None, 'string'], + ['remote', None, 'string'], + ['max_jobs', None, 'int'], + ['serverca', None, 'string'], + ['auth_cert', None, 'string'], + ['arches', None, 'string'], + ] #parse again with updated defaults diff --git a/util/kojira b/util/kojira index cb85eef..8a0d6a2 100755 --- a/util/kojira +++ b/util/kojira @@ -27,7 +27,6 @@ import os import koji from koji.util import rmtree, parseStatus, to_list from optparse import OptionParser -from six.moves.configparser import ConfigParser import errno import json import logging @@ -901,8 +900,7 @@ def get_options(): parser.add_option("--logfile", help="Specify logfile") (options, args) = parser.parse_args() - config = ConfigParser() - config.read(options.configFile) + config = koji.read_config_files(options.configFile) section = 'kojira' for x in config.sections(): if x != section: diff --git a/vm/kojikamid.py b/vm/kojikamid.py index 6a41aa5..b3df301 100755 --- a/vm/kojikamid.py +++ b/vm/kojikamid.py @@ -28,7 +28,7 @@ from __future__ import absolute_import from optparse import OptionParser -from six.moves.configparser import ConfigParser +from six.moves.configparser import ConfigParser, SafeConfigParser import os import subprocess import sys @@ -212,7 +212,10 @@ class WindowsBuild(object): elif len(specfiles) > 1: raise BuildError('Multiple .ini files found') - conf = ConfigParser() + if six.PY2: + conf = SafeConfigParser() + else: + conf = ConfigParser() conf.read(os.path.join(self.spec_dir, specfiles[0])) # [naming] section diff --git a/vm/kojivmd b/vm/kojivmd index 80c20b5..24ca674 100755 --- a/vm/kojivmd +++ b/vm/kojivmd @@ -46,7 +46,6 @@ import base64 import pwd import requests import fnmatch -from six.moves.configparser import ConfigParser from contextlib import closing from optparse import OptionParser try: @@ -102,8 +101,7 @@ def get_options(): assert False # pragma: no cover # load local config - config = ConfigParser() - config.read(options.configFile) + config = koji.read_config_files(options.configFile) for x in config.sections(): if x != 'kojivmd': quit('invalid section found in config file: %s' % x) diff --git a/www/kojiweb/wsgi_publisher.py b/www/kojiweb/wsgi_publisher.py index 68373f1..b5cc959 100644 --- a/www/kojiweb/wsgi_publisher.py +++ b/www/kojiweb/wsgi_publisher.py @@ -30,7 +30,6 @@ import pprint import sys import traceback -from six.moves.configparser import RawConfigParser from koji.server import ServerError, ServerRedirect from koji.util import dslice, to_list import six @@ -132,22 +131,12 @@ class Dispatcher(object): """ cf = environ.get('koji.web.ConfigFile', '/etc/kojiweb/web.conf') 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(configs) - else: - raise koji.GenericError("Configuration missing") + config = koji.read_config_files([cfdir, cf], strict=True) opts = {} for name, dtype, default in self.cfgmap: key = ('web', name) - if config and config.has_option(*key): + if config.has_option(*key): if dtype == 'integer': opts[name] = config.getint(*key) elif dtype == 'boolean':