1
0
Fork 0

Removing dependency on python-configobj.

Resolves: rhbz#1936386

Signed-off-by: Jan Zerdik <jzerdik@redhat.com>
This commit is contained in:
Jan Zerdik 2021-07-30 11:48:59 +02:00
parent 7ba8d5d694
commit 063277a05b
16 changed files with 286 additions and 117 deletions

View file

@ -29,7 +29,7 @@
# Limitation:
# Each profile can be specified only once, because there cannot be
# multiple sections in the configuration file with the same name
# (ConfigObj limitation).
# (ConfigParser limitation).
# If there is a need to specify the profile multiple times, unique
# suffix like ',ANYSTRING' can be used. Everything after the last ','
# is stripped by the parser, e.g.:

View file

@ -46,6 +46,8 @@ class LoaderTestCase(unittest.TestCase):
f.write('file_path=${i:PROFILE_DIR}/whatever\n')
f.write('script=random_name.sh\n')
f.write('[test_unit]\ntest_option=hello world\n')
f.write('devices=/dev/${variable1},/dev/${variable2}\n')
f.write('[variables]\nvariable1=net\nvariable2=cpu')
def setUp(self):
locator = profiles.Locator([self._profiles_dir])
@ -105,6 +107,11 @@ class LoaderTestCase(unittest.TestCase):
self.assertEqual(config['test_unit']['test_option'],\
'hello world')
def test_variables(self):
config = self._loader.load(['dummy4'])
self.assertEqual(config.units['test_unit'].devices,\
'/dev/net,/dev/cpu')
@classmethod
def tearDownClass(cls):
shutil.rmtree(cls._test_dir)

View file

@ -30,7 +30,10 @@ class LocatorTestCase(unittest.TestCase):
conf_name = os.path.join(profile_dir, "tuned.conf")
os.mkdir(profile_dir)
with open(conf_name, "w") as conf_file:
pass
if profile_name != "custom":
conf_file.write("[main]\nsummary=this is " + profile_name + "\n")
else:
conf_file.write("summary=this is " + profile_name + "\n")
def test_init(self):
Locator([])
@ -65,3 +68,16 @@ class LocatorTestCase(unittest.TestCase):
self.assertEqual(balanced, os.path.join(self._tmp_load_dirs[0], "balanced", "tuned.conf"))
known = locator.get_known_names()
self.assertListEqual(known, ["balanced", "powersafe"])
def test_get_known_names_summary(self):
self.assertEqual(("balanced", "this is balanced"), sorted(self.locator.get_known_names_summary())[0])
def test_get_profile_attrs(self):
attrs = self.locator.get_profile_attrs("balanced", ["summary", "wrong_attr"], ["this is default", "this is wrong attr"])
self.assertEqual([True, "balanced", "this is balanced", "this is wrong attr"], attrs)
attrs = self.locator.get_profile_attrs("custom", ["summary"], ["wrongly writen profile"])
self.assertEqual([True, "custom", "wrongly writen profile"], attrs)
attrs = self.locator.get_profile_attrs("different", ["summary"], ["non existing profile"])
self.assertEqual([False, "", "", ""], attrs)

View file

@ -0,0 +1,32 @@
import unittest
import tempfile
import shutil
from tuned.profiles import variables, profile
class VariablesTestCase(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.test_dir = tempfile.mkdtemp()
with open(cls.test_dir + "/variables", 'w') as f:
f.write("variable1=var1\n")
def test_from_file(self):
v = variables.Variables()
v.add_from_file(self.test_dir + "/variables")
self.assertEqual("This is var1", v.expand("This is ${variable1}"))
def test_from_unit(self):
mock_unit = {
"include": self.test_dir + "/variables",
"variable2": "var2"
}
v = variables.Variables()
v.add_from_cfg(mock_unit)
self.assertEqual("This is var1 and this is var2", v.expand("This is ${variable1} and this is ${variable2}"))
@classmethod
def tearDownClass(cls):
shutil.rmtree(cls.test_dir)

View file

@ -12,7 +12,8 @@ class GlobalConfigTestCase(unittest.TestCase):
cls.test_dir = tempfile.mkdtemp()
with open(cls.test_dir + '/test_config','w') as f:
f.write('test_option = hello\ntest_bool = 1\ntest_size = 12MB\n'\
+ 'false_bool=0\n')
+ 'false_bool=0\n'\
+ consts.CFG_LOG_FILE_COUNT + " = " + str(consts.CFG_DEF_LOG_FILE_COUNT) + "1\n")
cls._global_config = global_config.GlobalConfig(\
cls.test_dir + '/test_config')
@ -28,10 +29,18 @@ class GlobalConfigTestCase(unittest.TestCase):
self.assertEqual(self._global_config.get_size('test_size'),\
12*1024*1024)
self._global_config.set('test_size','bad_value')
self._global_config.set('test_size', 'bad_value')
self.assertIsNone(self._global_config.get_size('test_size'))
def test_default(self):
daemon = self._global_config.get(consts.CFG_DAEMON)
self.assertEqual(daemon, consts.CFG_DEF_DAEMON)
log_file_count = self._global_config.get(consts.CFG_LOG_FILE_COUNT)
self.assertIsNotNone(log_file_count)
self.assertNotEqual(log_file_count, consts.CFG_DEF_LOG_FILE_COUNT)
@classmethod
def tearDownClass(cls):
shutil.rmtree(cls.test_dir)

View file

@ -48,7 +48,7 @@ except ImportError:
import sys
import os
import time
import configobj
import collections
import subprocess
import tuned.logs
@ -508,8 +508,7 @@ class Base(object):
def data_to_profile_config(self):
name = self._gobj('entryProfileName').get_text()
config = configobj.ConfigObj(list_values = False,
interpolation = False)
config = collections.OrderedDict()
activated = self._gobj('comboboxIncludeProfile').get_active()
model = self._gobj('comboboxIncludeProfile').get_model()

View file

@ -66,9 +66,8 @@ BuildRequires: %{_py}, %{_py}-devel
%if %{without python3} && ( ! 0%{?rhel} || 0%{?rhel} >= 8 )
BuildRequires: %{_py}-mock
%endif
BuildRequires: %{_py}-configobj
BuildRequires: %{_py}-pyudev
Requires: %{_py}-pyudev, %{_py}-configobj
Requires: %{_py}-pyudev
Requires: %{_py}-linux-procfs, %{_py}-perf
%if %{without python3}
Requires: %{_py}-schedutils

View file

@ -16,6 +16,8 @@ DEFAULT_STORAGE_FILE = "/run/tuned/save.pickle"
LOAD_DIRECTORIES = ["/usr/lib/tuned", "/etc/tuned"]
PERSISTENT_STORAGE_DIR = "/var/lib/tuned"
PLUGIN_MAIN_UNIT_NAME = "main"
# Magic section header because ConfigParser does not support "headerless" config
MAGIC_HEADER_NAME = "this_is_some_magic_section_header_because_of_compatibility"
RECOMMEND_DIRECTORIES = ["/usr/lib/tuned/recommend.d", "/etc/tuned/recommend.d"]
TMP_FILE_SUFFIX = ".tmp"
@ -79,6 +81,10 @@ ENV_PREFIX = "TUNED_"
PREFIX_PROFILE_FACTORY = "System"
PREFIX_PROFILE_USER = "User"
# After adding new option to tuned-main.conf add here its name with CFG_ prefix
# and eventually default value with CFG_DEF_ prefix (default is None)
# and function for check with CFG_FUNC_ prefix
# (see configobj for methods, default is get for string)
CFG_DAEMON = "daemon"
CFG_DYNAMIC_TUNING = "dynamic_tuning"
CFG_SLEEP_INTERVAL = "sleep_interval"
@ -87,25 +93,40 @@ CFG_RECOMMEND_COMMAND = "recommend_command"
CFG_REAPPLY_SYSCTL = "reapply_sysctl"
CFG_DEFAULT_INSTANCE_PRIORITY = "default_instance_priority"
CFG_UDEV_BUFFER_SIZE = "udev_buffer_size"
CFG_LOG_FILE_COUNT = "log_file_count"
CFG_LOG_FILE_MAX_SIZE = "log_file_max_size"
CFG_UNAME_STRING = "uname_string"
CFG_CPUINFO_STRING = "cpuinfo_string"
# no_daemon mode
CFG_DEF_DAEMON = True
CFG_FUNC_DAEMON = "getboolean"
# default configuration
CFG_DEF_DYNAMIC_TUNING = True
CFG_FUNC_DYNAMIC_TUNING = "getboolean"
# how long to sleep before checking for events (in seconds)
CFG_DEF_SLEEP_INTERVAL = 1
CFG_FUNC_SLEEP_INTERVAL = "getint"
# update interval for dynamic tuning (in seconds)
CFG_DEF_UPDATE_INTERVAL = 10
CFG_FUNC_UPDATE_INTERVAL = "getint"
# recommend command availability
CFG_DEF_RECOMMEND_COMMAND = True
CFG_FUNC_RECOMMEND_COMMAND = "getboolean"
# reapply system sysctl
CFG_DEF_REAPPLY_SYSCTL = True
CFG_FUNC_REAPPLY_SYSCTL = "getboolean"
# default instance priority
CFG_DEF_DEFAULT_INSTANCE_PRIORITY = 0
CFG_FUNC_DEFAULT_INSTANCE_PRIORITY = "getint"
# default pyudev.Monitor buffer size
CFG_DEF_UDEV_BUFFER_SIZE = 1024 * 1024
# default log file count
CFG_DEF_LOG_FILE_COUNT = 2
CFG_FUNC_LOG_FILE_COUNT = "getint"
# default log file max size
CFG_DEF_LOG_FILE_MAX_SIZE = 1024 * 1024
PATH_CPU_DMA_LATENCY = "/dev/cpu_dma_latency"

View file

@ -25,25 +25,23 @@ Created on Mar 30, 2014
'''
import importlib
from validate import Validator
import tuned.consts as consts
import tuned.logs
import configobj as ConfigObj
try:
from configparser import ConfigParser, Error
from io import StringIO
except ImportError:
# python2.7 support, remove RHEL-7 support end
from ConfigParser import ConfigParser, Error
from StringIO import StringIO
from tuned.exceptions import TunedException
from tuned.utils.global_config import GlobalConfig
from tuned.admin.dbus_controller import DBusController
__all__ = ['GuiPluginLoader']
global_config_spec = ['dynamic_tuning = boolean(default=%s)'
% consts.CFG_DEF_DYNAMIC_TUNING,
'sleep_interval = integer(default=%s)'
% consts.CFG_DEF_SLEEP_INTERVAL,
'update_interval = integer(default=%s)'
% consts.CFG_DEF_UPDATE_INTERVAL]
class GuiPluginLoader():
@ -84,19 +82,26 @@ class GuiPluginLoader():
"""
try:
config = ConfigObj.ConfigObj(file_name,
configspec=global_config_spec,
raise_errors = True, file_error = True, list_values = False, interpolation = False)
config_parser = ConfigParser()
config_parser.optionxform = str
with open(file_name) as f:
config_parser.readfp(StringIO("[" + consts.MAGIC_HEADER_NAME + "]\n" + f.read()))
config, functions = GlobalConfig.get_global_config_spec()
for option in config_parser.options(consts.MAGIC_HEADER_NAME):
if option in config:
try:
func = getattr(config_parser, functions[option])
config[option] = func(consts.MAGIC_HEADER_NAME, option)
except Error:
raise TunedException("Global TuneD configuration file '%s' is not valid."
% file_name)
else:
config[option] = config_parser.get(consts.MAGIC_HEADER_NAME, option, raw=True)
except IOError as e:
raise TunedException("Global TuneD configuration file '%s' not found."
% file_name)
except ConfigObj.ConfigObjError as e:
except Error as e:
raise TunedException("Error parsing global TuneD configuration file '%s'."
% file_name)
vdt = Validator()
if not config.validate(vdt, copy=True):
raise TunedException("Global TuneD configuration file '%s' is not valid."
% file_name)
return config

View file

@ -25,10 +25,17 @@ Created on Mar 13, 2014
'''
import os
import configobj
try:
from configparser import ConfigParser, Error
from io import StringIO
except ImportError:
# python2.7 support, remove RHEL-7 support end
from ConfigParser import ConfigParser, Error
from StringIO import StringIO
import subprocess
import json
import sys
import collections
import tuned.profiles.profile as p
import tuned.consts
@ -59,14 +66,21 @@ class GuiProfileLoader(object):
profilePath = self._locate_profile_path(profile_name)
config_lines = config.split('\n')
if profilePath == tuned.consts.LOAD_DIRECTORIES[1]:
file_path = profilePath + '/' + profile_name + '/' + tuned.consts.PROFILE_FILE
config_parser = ConfigParser()
config_parser.optionxform = str
config_parser.readfp(StringIO(config))
config_obj = configobj.ConfigObj(infile=config_lines,list_values = False, interpolation = False)
config_obj.filename = file_path
config_obj.initial_comment = ('#', 'tuned configuration', '#')
config_obj = {
'main': collections.OrderedDict(),
'filename': file_path,
'initial_comment': ('#', 'tuned configuration', '#')
}
for s in config_parser.sections():
config_obj['main'][s] = collections.OrderedDict()
for o in config_parser.options(s):
config_obj['main'][s][o] = config_parser.get(s, o, raw=True)
self._save_profile(config_obj)
self._refresh_profiles()
else:
@ -76,8 +90,15 @@ class GuiProfileLoader(object):
def load_profile_config(self, profile_name, path):
conf_path = path + '/' + profile_name + '/' + tuned.consts.PROFILE_FILE
profile_config = configobj.ConfigObj(conf_path, list_values = False,
interpolation = False)
config = ConfigParser()
config.optionxform = str
profile_config = collections.OrderedDict()
with open(conf_path) as f:
config.readfp(f)
for s in config.sections():
profile_config[s] = collections.OrderedDict()
for o in config.options(s):
profile_config[s][o] = config.get(s, o, raw=True)
return profile_config
def _locate_profile_path(self, profile_name):
@ -95,11 +116,11 @@ class GuiProfileLoader(object):
try:
self.profiles[profile] = p.Profile(profile,
self.load_profile_config(profile, d))
except configobj.ParseError:
except Error:
pass
# print "can not make \""+ profile +"\" profile without correct config on path: " + d
# except:
# except:StringIO
# raise managerException.ManagerException("Can not make profile")
# print "can not make \""+ profile +"\" profile without correct config with path: " + d
@ -113,20 +134,24 @@ class GuiProfileLoader(object):
def save_profile(self, profile):
path = tuned.consts.LOAD_DIRECTORIES[1] + '/' + profile.name
config = configobj.ConfigObj(list_values = False, interpolation = False)
config.filename = path + '/' + tuned.consts.PROFILE_FILE
config.initial_comment = ('#', 'tuned configuration', '#')
config = {
'main': collections.OrderedDict(),
'filename': path + '/' + tuned.consts.PROFILE_FILE,
'initial_comment': ('#', 'tuned configuration', '#')
}
config['filename'] = path + '/' + tuned.consts.PROFILE_FILE
config['initial_comment'] = ('#', 'tuned configuration', '#')
try:
config['main'] = profile.options
config['main']['main'] = profile.options
except KeyError:
config['main'] = ''
config['main']['main'] = {}
# profile dont have main section
pass
for (name, unit) in list(profile.units.items()):
config[name] = unit.options
config['main'][name] = unit.options
self._save_profile(config)
@ -148,18 +173,20 @@ class GuiProfileLoader(object):
if old_profile_name != profile.name:
self.remove_profile(old_profile_name, is_admin=is_admin)
config = configobj.ConfigObj(list_values = False, interpolation = False)
config.filename = path + '/' + tuned.consts.PROFILE_FILE
config.initial_comment = ('#', 'tuned configuration', '#')
config = {
'main': collections.OrderedDict(),
'filename': path + '/' + tuned.consts.PROFILE_FILE,
'initial_comment': ('#', 'tuned configuration', '#')
}
try:
config['main'] = profile.options
config['main']['main'] = profile.options
except KeyError:
# profile dont have main section
pass
for (name, unit) in list(profile.units.items()):
config[name] = unit.options
config['main'][name] = unit.options
self._save_profile(config)

View file

@ -1,7 +1,11 @@
import os
import sys
import json
from configobj import ConfigObj
try:
from configparser import ConfigParser
except ImportError:
# python2.7 support, remove RHEL-7 support end
from ConfigParser import ConfigParser
if __name__ == "__main__":
@ -11,13 +15,19 @@ if __name__ == "__main__":
if not os.path.exists(profile_dict['filename']):
os.makedirs(os.path.dirname(profile_dict['filename']))
profile_configobj = ConfigObj()
for section in profile_dict['sections']:
profile_configobj[section] = profile_dict['main'][section]
profile_configobj = ConfigParser()
profile_configobj.optionxform = str
for section, options in profile_dict['main'].items():
profile_configobj.add_section(section)
for option, value in options.items():
profile_configobj.set(section, option, value)
profile_configobj.filename = os.path.join('/etc','tuned',os.path.dirname(os.path.abspath(profile_dict['filename'])),'tuned.conf')
profile_configobj.initial_comment = profile_dict['initial_comment']
profile_configobj.write()
path = os.path.join('/etc','tuned',os.path.dirname(os.path.abspath(profile_dict['filename'])),'tuned.conf')
with open(path, 'w') as f:
profile_configobj.write(f)
with open(path, 'r+') as f:
content = f.read()
f.seek(0, 0)
f.write("\n".join(profile_dict['initial_comment']) + "\n" + content)
sys.exit(0)

View file

@ -1,6 +1,10 @@
import tuned.profiles.profile
import tuned.profiles.variables
from configobj import ConfigObj, ConfigObjError
try:
from configparser import ConfigParser, Error
except ImportError:
# python2.7 support, remove RHEL-7 support end
from ConfigParser import ConfigParser, Error
import tuned.consts as consts
import os.path
import collections
@ -96,30 +100,22 @@ class Loader(object):
def _load_config_data(self, file_name):
try:
config_obj = ConfigObj(file_name, raise_errors = True, list_values = False, interpolation = False)
except ConfigObjError as e:
config_obj = ConfigParser()
config_obj.optionxform=str
with open(file_name) as f:
config_obj.readfp(f)
except Error as e:
raise InvalidProfileException("Cannot parse '%s'." % file_name, e)
config = collections.OrderedDict()
for section in list(config_obj.keys()):
config[section] = collections.OrderedDict()
try:
keys = list(config_obj[section].keys())
except AttributeError:
raise InvalidProfileException("Error parsing section '%s' in file '%s'." % (section, file_name))
for option in keys:
config[section][option] = config_obj[section][option]
dir_name = os.path.dirname(file_name)
# TODO: Could we do this in the same place as the expansion of other functions?
for section in config:
for option in config[section]:
for section in list(config_obj.sections()):
config[section] = collections.OrderedDict()
for option in config_obj.options(section):
config[section][option] = config_obj.get(section, option, raw=True)
config[section][option] = self._expand_profile_dir(dir_name, config[section][option])
# TODO: HACK, this needs to be solved in a better way (better config parser)
for unit_name in config:
if "script" in config[unit_name] and config[unit_name].get("script", None) is not None:
script_path = os.path.join(dir_name, config[unit_name]["script"])
config[unit_name]["script"] = [os.path.normpath(script_path)]
if config[section].get("script") is not None:
script_path = os.path.join(dir_name, config[section]["script"])
config[section]["script"] = [os.path.normpath(script_path)]
return config

View file

@ -1,6 +1,12 @@
import os
import tuned.consts as consts
from configobj import ConfigObj, ConfigObjError
try:
from configparser import ConfigParser, Error
from io import StringIO
except ImportError:
# python2.7 support, remove RHEL-7 support end
from ConfigParser import ConfigParser, Error
from StringIO import StringIO
class Locator(object):
"""
@ -48,8 +54,12 @@ class Locator(object):
if config_file is None:
return None
try:
return ConfigObj(config_file, list_values = False, interpolation = False)
except (IOError, OSError, ConfigObjError) as e:
config = ConfigParser()
config.optionxform = str
with open(config_file) as f:
config.readfp(StringIO("[" + consts.MAGIC_HEADER_NAME + "]\n" + f.read()))
return config
except (IOError, OSError, Error) as e:
return None
# Get profile attributes (e.g. summary, description), attrs is list of requested attributes,
@ -75,17 +85,16 @@ class Locator(object):
config = self.parse_config(profile_name)
if config is None:
return [False, "", "", ""]
if consts.PLUGIN_MAIN_UNIT_NAME in config:
d = config[consts.PLUGIN_MAIN_UNIT_NAME]
else:
d = dict()
main_unit_in_config = consts.PLUGIN_MAIN_UNIT_NAME in config.sections()
vals = [True, profile_name]
for (attr, defval) in zip(attrs, defvals):
if attr == "" or attr is None:
vals[0] = False
vals = vals + [""]
elif main_unit_in_config and attr in config.options(consts.PLUGIN_MAIN_UNIT_NAME):
vals = vals + [config.get(consts.PLUGIN_MAIN_UNIT_NAME, attr, raw=True)]
else:
vals = vals + [d.get(attr, defval)]
vals = vals + [defval]
return vals
def list_profiles(self):

View file

@ -4,7 +4,13 @@ import tuned.logs
from .functions import functions as functions
import tuned.consts as consts
from tuned.utils.commands import commands
from configobj import ConfigObj, ConfigObjError
try:
from configparser import ConfigParser, Error
from io import StringIO
except ImportError:
# python2.7 support, remove RHEL-7 support end
from ConfigParser import ConfigParser, Error
from StringIO import StringIO
log = tuned.logs.get()
@ -40,24 +46,21 @@ class Variables():
self._lookup_re[r'(?<!\\)\${' + re.escape(s) + r'}'] = v
self._lookup_env[self._add_env_prefix(s, consts.ENV_PREFIX)] = v
def add_dict(self, d):
for item in d:
self.add_variable(item, d[item])
def add_from_file(self, filename):
if not os.path.exists(filename):
log.error("unable to find variables_file: '%s'" % filename)
return
try:
config = ConfigObj(filename, raise_errors = True, file_error = True, list_values = False, interpolation = False)
except ConfigObjError:
config = ConfigParser()
config.optionxform = str
with open(filename) as f:
config.readfp(StringIO("[" + consts.MAGIC_HEADER_NAME + "]\n" + f.read()))
except Error:
log.error("error parsing variables_file: '%s'" % filename)
return
for item in config:
if isinstance(config[item], dict):
self.add_dict(config[item])
else:
self.add_variable(item, config[item])
for s in config.sections():
for o in config.options(s):
self.add_variable(o, config.get(s, o, raw=True))
def add_from_cfg(self, cfg):
for item in cfg:

View file

@ -1,6 +1,11 @@
import tuned.logs
from configobj import ConfigObj, ConfigObjError
from validate import Validator
try:
from configparser import ConfigParser, Error
from io import StringIO
except ImportError:
# python2.7 support, remove RHEL-7 support end
from ConfigParser import ConfigParser, Error
from StringIO import StringIO
from tuned.exceptions import TunedException
import tuned.consts as consts
from tuned.utils.commands import commands
@ -11,31 +16,55 @@ log = tuned.logs.get()
class GlobalConfig():
global_config_spec = ["dynamic_tuning = boolean(default=%s)" % consts.CFG_DEF_DYNAMIC_TUNING,
"sleep_interval = integer(default=%s)" % consts.CFG_DEF_SLEEP_INTERVAL,
"update_interval = integer(default=%s)" % consts.CFG_DEF_UPDATE_INTERVAL,
"recommend_command = boolean(default=%s)" % consts.CFG_DEF_RECOMMEND_COMMAND]
def __init__(self,config_file = consts.GLOBAL_CONFIG_FILE):
self._cfg = {}
self.load_config(file_name=config_file)
self._cmd = commands()
@staticmethod
def get_global_config_spec():
"""
Easy validation mimicking configobj
Returns two dicts, firts with default values (default None)
global_default[consts.CFG_SOMETHING] = consts.CFG_DEF_SOMETHING or None
second with configobj function for value type (default "get" for string, others eg getboolean, getint)
global_function[consts.CFG_SOMETHING] = consts.CFG_FUNC_SOMETHING or get
}
"""
options = [opt for opt in dir(consts)
if opt.startswith("CFG_") and
not opt.startswith("CFG_FUNC_") and
not opt.startswith("CFG_DEF_")]
global_default = dict((getattr(consts, opt), getattr(consts, "CFG_DEF_" + opt[4:], None)) for opt in options)
global_function = dict((getattr(consts, opt), getattr(consts, "CFG_FUNC_" + opt[4:], "get")) for opt in options)
return global_default, global_function
def load_config(self, file_name = consts.GLOBAL_CONFIG_FILE):
"""
Loads global configuration file.
"""
log.debug("reading and parsing global configuration file '%s'" % file_name)
try:
self._cfg = ConfigObj(file_name, configspec = self.global_config_spec, raise_errors = True, \
file_error = True, list_values = False, interpolation = False)
config_parser = ConfigParser()
config_parser.optionxform = str
with open(file_name) as f:
config_parser.readfp(StringIO("[" + consts.MAGIC_HEADER_NAME + "]\n" + f.read()))
self._cfg, _global_config_func = self.get_global_config_spec()
for option in config_parser.options(consts.MAGIC_HEADER_NAME):
if option in self._cfg:
try:
func = getattr(config_parser, _global_config_func[option])
self._cfg[option] = func(consts.MAGIC_HEADER_NAME, option)
except Error:
raise TunedException("Global TuneD configuration file '%s' is not valid."
% file_name)
else:
log.info("Unknown option '%s' in global config file '%s'." % (option, file_name))
self._cfg[option] = config_parser.get(consts.MAGIC_HEADER_NAME, option, raw=True)
except IOError as e:
raise TunedException("Global TuneD configuration file '%s' not found." % file_name)
except ConfigObjError as e:
except Error as e:
raise TunedException("Error parsing global TuneD configuration file '%s'." % file_name)
vdt = Validator()
if (not self._cfg.validate(vdt, copy=True)):
raise TunedException("Global TuneD configuration file '%s' is not valid." % file_name)
def get(self, key, default = None):
return self._cfg.get(key, default)

View file

@ -3,7 +3,11 @@ import re
import errno
import procfs
import subprocess
from configobj import ConfigObj, ConfigObjError
try:
from configparser import ConfigParser, Error
except ImportError:
# python2.7 support, remove RHEL-7 support end
from ConfigParser import ConfigParser, Error
try:
import syspurpose.files
@ -59,11 +63,14 @@ class ProfileRecommender:
try:
if not os.path.isfile(fname):
return None
config = ConfigObj(fname, list_values = False, interpolation = False)
for section in list(config.keys()):
config = ConfigParser()
config.optionxform = str
with open(fname) as f:
config.readfp(f)
for section in config.sections():
match = True
for option in list(config[section].keys()):
value = config[section][option]
for option in config.options(section):
value = config.get(section, option, raw=True)
if value == "":
value = r"^$"
if option == "virt":
@ -117,7 +124,7 @@ class ProfileRecommender:
r = re.compile(r",[^,]*$")
matching_profile = r.sub("", section)
break
except (IOError, OSError, ConfigObjError) as e:
except (IOError, OSError, Error) as e:
log.error("error processing '%s', %s" % (fname, e))
return matching_profile