move config map and add unit tests

This commit is contained in:
Mike McLean 2025-02-06 12:05:25 -05:00 committed by Tomas Kopecek
parent 3e48c8597f
commit a7d7d9c1f5
2 changed files with 206 additions and 97 deletions

View file

@ -416,6 +416,104 @@ def error_reply(start_response, status, response, extra_headers=None):
return [response]
# Known configuration options, used by load_config
config_map = [
# option, type, default
['DBName', 'string', None],
['DBUser', 'string', None],
['DBHost', 'string', None],
['DBhost', 'string', None], # alias for backwards compatibility
['DBPort', 'integer', None],
['DBPass', 'string', None],
['DBConnectionString', 'string', None],
['KojiDir', 'string', None],
['ProxyPrincipals', 'string', ''],
['HostPrincipalFormat', 'string', None],
['AllowedKrbRealms', 'string', '*'],
# TODO: this option should be turned True in 1.34
['DisableURLSessions', 'boolean', False],
['DNUsernameComponent', 'string', 'CN'],
['ProxyDNs', 'string', ''],
['CheckClientIP', 'boolean', True],
['LoginCreatesUser', 'boolean', True],
['AllowProxyAuthType', 'boolean', False],
['KojiWebURL', 'string', 'http://localhost.localdomain/koji'],
['EmailDomain', 'string', None],
['NotifyOnSuccess', 'boolean', True],
['DisableNotifications', 'boolean', False],
['Plugins', 'string', ''],
['PluginPath', 'string', '/usr/lib/koji-hub-plugins'],
['KojiDebug', 'boolean', False],
['KojiTraceback', 'string', None],
['VerbosePolicy', 'boolean', False],
['LogLevel', 'string', 'WARNING'],
['LogFormat', 'string',
'%(asctime)s [%(levelname)s] m=%(method)s u=%(user_name)s p=%(process)s r=%(remoteaddr)s '
'%(name)s: %(message)s'],
['MissingPolicyOk', 'boolean', True],
['EnableMaven', 'boolean', False],
['EnableWin', 'boolean', False],
['RLIMIT_AS', 'string', None],
['RLIMIT_CORE', 'string', None],
['RLIMIT_CPU', 'string', None],
['RLIMIT_DATA', 'string', None],
['RLIMIT_FSIZE', 'string', None],
['RLIMIT_MEMLOCK', 'string', None],
['RLIMIT_NOFILE', 'string', None],
['RLIMIT_NPROC', 'string', None],
['RLIMIT_OFILE', 'string', None], # alias for RLIMIT_NOFILE
['RLIMIT_RSS', 'string', None],
['RLIMIT_STACK', 'string', None],
['MemoryWarnThreshold', 'integer', 5000],
['MaxRequestLength', 'integer', 4194304],
['LockOut', 'boolean', False],
['ServerOffline', 'boolean', False],
['OfflineMessage', 'string', None],
['MaxNameLengthInternal', 'integer', 256],
['RegexNameInternal', 'string', r'^[A-Za-z0-9/_.+-]+$'],
['RegexUserName', 'string', r'^[A-Za-z0-9/_.@-]+$'],
['RPMDefaultChecksums', 'string', 'md5 sha256'],
['SessionRenewalTimeout', 'integer', 1440],
# scheduler options
['MaxJobs', 'integer', 15],
['CapacityOvercommit', 'integer', 5],
['ReadyTimeout', 'integer', 180],
['AssignTimeout', 'integer', 300],
['SoftRefusalTimeout', 'integer', 900],
['HostTimeout', 'integer', 900],
['RunInterval', 'integer', 60],
# repo options
['MaxRepoTasks', 'integer', 10],
['MaxRepoTasksMaven', 'integer', 2],
['RepoRetries', 'integer', 3],
['RequestCleanTime', 'integer', 60 * 24], # in minutes
['AllowNewRepo', 'bool', True],
['RepoLag', 'int', 3600],
['RepoAutoLag', 'int', 7200],
['RepoLagWindow', 'int', 600],
['RepoQueueUser', 'str', 'kojira'],
['DebuginfoTags', 'str', ''],
['SourceTags', 'str', ''],
['SeparateSourceTags', 'str', ''],
]
def load_config(environ):
"""Load configuration options
@ -437,111 +535,19 @@ def load_config(environ):
cfdir = environ.get('koji.hub.ConfigDir', '/etc/koji-hub/hub.conf.d')
config = koji.read_config_files([cfdir, (cf, True)], raw=True)
cfgmap = [
# option, type, default
['DBName', 'string', None],
['DBUser', 'string', None],
['DBHost', 'string', None],
['DBhost', 'string', None], # alias for backwards compatibility
['DBPort', 'integer', None],
['DBPass', 'string', None],
['DBConnectionString', 'string', None],
['KojiDir', 'string', None],
['ProxyPrincipals', 'string', ''],
['HostPrincipalFormat', 'string', None],
['AllowedKrbRealms', 'string', '*'],
# TODO: this option should be turned True in 1.34
['DisableURLSessions', 'boolean', False],
['DNUsernameComponent', 'string', 'CN'],
['ProxyDNs', 'string', ''],
['CheckClientIP', 'boolean', True],
['LoginCreatesUser', 'boolean', True],
['AllowProxyAuthType', 'boolean', False],
['KojiWebURL', 'string', 'http://localhost.localdomain/koji'],
['EmailDomain', 'string', None],
['NotifyOnSuccess', 'boolean', True],
['DisableNotifications', 'boolean', False],
['Plugins', 'string', ''],
['PluginPath', 'string', '/usr/lib/koji-hub-plugins'],
['KojiDebug', 'boolean', False],
['KojiTraceback', 'string', None],
['VerbosePolicy', 'boolean', False],
['LogLevel', 'string', 'WARNING'],
['LogFormat', 'string',
'%(asctime)s [%(levelname)s] m=%(method)s u=%(user_name)s p=%(process)s r=%(remoteaddr)s '
'%(name)s: %(message)s'],
['MissingPolicyOk', 'boolean', True],
['EnableMaven', 'boolean', False],
['EnableWin', 'boolean', False],
['RLIMIT_AS', 'string', None],
['RLIMIT_CORE', 'string', None],
['RLIMIT_CPU', 'string', None],
['RLIMIT_DATA', 'string', None],
['RLIMIT_FSIZE', 'string', None],
['RLIMIT_MEMLOCK', 'string', None],
['RLIMIT_NOFILE', 'string', None],
['RLIMIT_NPROC', 'string', None],
['RLIMIT_OFILE', 'string', None], # alias for RLIMIT_NOFILE
['RLIMIT_RSS', 'string', None],
['RLIMIT_STACK', 'string', None],
['MemoryWarnThreshold', 'integer', 5000],
['MaxRequestLength', 'integer', 4194304],
['LockOut', 'boolean', False],
['ServerOffline', 'boolean', False],
['OfflineMessage', 'string', None],
['MaxNameLengthInternal', 'integer', 256],
['RegexNameInternal', 'string', r'^[A-Za-z0-9/_.+-]+$'],
['RegexUserName', 'string', r'^[A-Za-z0-9/_.@-]+$'],
['RPMDefaultChecksums', 'string', 'md5 sha256'],
['SessionRenewalTimeout', 'integer', 1440],
# scheduler options
['MaxJobs', 'integer', 15],
['CapacityOvercommit', 'integer', 5],
['ReadyTimeout', 'integer', 180],
['AssignTimeout', 'integer', 300],
['SoftRefusalTimeout', 'integer', 900],
['HostTimeout', 'integer', 900],
['RunInterval', 'integer', 60],
# repo options
['MaxRepoTasks', 'integer', 10],
['MaxRepoTasksMaven', 'integer', 2],
['RepoRetries', 'integer', 3],
['RequestCleanTime', 'integer', 60 * 24], # in minutes
['AllowNewRepo', 'bool', True],
['RepoLag', 'integer', 3600],
['RepoAutoLag', 'integer', 7200],
['RepoLagWindow', 'integer', 600],
['RepoQueueUser', 'str', 'kojira'],
['DebuginfoTags', 'str', ''],
['SourceTags', 'str', ''],
['SeparateSourceTags', 'str', ''],
]
opts = {}
for name, dtype, default in cfgmap:
for name, dtype, default in config_map:
key = ('hub', name)
if config and config.has_option(*key):
if dtype == 'integer':
opts[name] = config.getint(*key)
elif dtype == 'boolean':
opts[name] = config.getboolean(*key)
else:
elif dtype == 'string':
opts[name] = config.get(*key)
else:
# anything else is an error in the map definition
raise ValueError(f'Invalid data type {dtype} for {name} option')
continue
opts[name] = default
if opts['DBHost'] is None:

View file

@ -0,0 +1,103 @@
from unittest import mock
import configparser
import os
import shutil
import tempfile
import unittest
import koji
import kojihub
from kojihub import kojixmlrpc
class TestHubConfig(unittest.TestCase):
def setUp(self):
self.context = mock.patch('kojihub.kojihub.context').start()
self.tempdir = tempfile.mkdtemp()
self.environ = {
'koji.hub.ConfigFile': self.tempdir + '/hub.conf',
'koji.hub.ConfigDir': self.tempdir + '/hub.conf.d',
}
# make an empty .d dir
os.mkdir(self.tempdir + '/hub.conf.d')
self.write_config({})
def tearDown(self):
shutil.rmtree(self.tempdir)
mock.patch.stopall()
def write_config(self, data):
"""Write given values to test config file"""
cfg = configparser.RawConfigParser()
cfg.add_section('hub')
for key in data:
cfg.set('hub', key, data[key])
with open(self.tempdir + '/hub.conf', 'wt') as fp:
cfg.write(fp)
def write_config_string(self, config):
with open(self.tempdir + '/hub.conf', 'wt') as fp:
fp.write(config)
def test_defaults(self):
# blank config should get us all default opts
opts = kojixmlrpc.load_config(self.environ)
for name, dtype, default in kojixmlrpc.config_map:
self.assertIn(name, opts)
value = opts[name]
self.assertEqual(value, default)
def test_values(self):
config_data = {
'CheckClientIP': False,
'DBHost': 'localhost',
'DBPort': 1234,
}
self.write_config(config_data)
opts = kojixmlrpc.load_config(self.environ)
for key in config_data:
self.assertEqual(config_data[key], opts[key])
def test_kojidir(self):
config_data = {
'KojiDir': self.tempdir,
}
self.write_config(config_data)
opts = kojixmlrpc.load_config(self.environ)
self.assertEqual(config_data['KojiDir'], opts['KojiDir'])
self.assertEqual(config_data['KojiDir'], koji.BASEDIR)
self.assertEqual(config_data['KojiDir'], koji.pathinfo.topdir)
def test_invalid_dtype(self):
bad_row = ['BadOpt', 'badtype', None]
self.write_config({'BadOpt': '1234'})
with mock.patch('kojihub.kojixmlrpc.config_map', new=kojixmlrpc.config_map + [bad_row]):
with self.assertRaises(ValueError) as ex:
kojixmlrpc.load_config(self.environ)
expected = 'Invalid data type badtype for BadOpt option'
self.assertEqual(str(ex.exception), expected)
def test_policy(self):
config = '''
[policy]
channel =
has req_channel :: req
is_child_task :: parent
method newRepo :: use createrepo
all :: use default
'''
self.write_config_string(config)
kojixmlrpc.load_config(self.environ)
# the end