diff --git a/tuned/profiles/functions/function_cpuinfo_check.py b/tuned/profiles/functions/function_cpuinfo_check.py new file mode 100644 index 0000000..6519482 --- /dev/null +++ b/tuned/profiles/functions/function_cpuinfo_check.py @@ -0,0 +1,32 @@ +import re +import tuned.logs +from . import base + +log = tuned.logs.get() + +class cpuinfo_check(base.Function): + """ + Checks regexes against /proc/cpuinfo. Accepts arguments in the + following form: REGEX1, STR1, REGEX2, STR2, ...[, STR_FALLBACK] + If REGEX1 matches something in /proc/cpuinfo it expands to STR1, + if REGEX2 matches it expands to STR2. It stops on the first match, + i.e. if REGEX1 matches, no more regexes are processed. If none + regex matches it expands to STR_FALLBACK. If there is no fallback, + it expands to empty string. + """ + def __init__(self): + # unlimited number of arguments, min 2 arguments + super(cpuinfo_check, self).__init__("cpuinfo_check", 0, 2) + + def execute(self, args): + if not super(cpuinfo_check, self).execute(args): + return None + cpuinfo = self._cmd.read_file("/proc/cpuinfo") + for i in range(0, len(args), 2): + if i + 1 < len(args): + if re.search(args[i], cpuinfo, re.MULTILINE): + return args[i + 1] + if len(args) % 2: + return args[-1] + else: + return "" diff --git a/tuned/profiles/loader.py b/tuned/profiles/loader.py index e844472..050c1d8 100644 --- a/tuned/profiles/loader.py +++ b/tuned/profiles/loader.py @@ -62,12 +62,18 @@ class Loader(object): del(final_profile.units["variables"]) # FIXME hack, do all variable expansions in one place self._expand_vars_in_devices(final_profile) + self._expand_vars_in_regexes(final_profile) return final_profile def _expand_vars_in_devices(self, profile): for unit in profile.units: profile.units[unit].devices = self._variables.expand(profile.units[unit].devices) + def _expand_vars_in_regexes(self, profile): + for unit in profile.units: + profile.units[unit].cpuinfo_regex = self._variables.expand(profile.units[unit].cpuinfo_regex) + profile.units[unit].uname_regex = self._variables.expand(profile.units[unit].uname_regex) + def _load_profile(self, profile_names, profiles, processed_files): for name in profile_names: filename = self._profile_locator.get_config(name, processed_files) diff --git a/tuned/profiles/merger.py b/tuned/profiles/merger.py index 2364543..d3520c5 100644 --- a/tuned/profiles/merger.py +++ b/tuned/profiles/merger.py @@ -35,6 +35,10 @@ class Merger(object): profile_a.units[unit_name].devices = unit.devices if unit.devices_udev_regex is not None: profile_a.units[unit_name].devices_udev_regex = unit.devices_udev_regex + if unit.cpuinfo_regex is not None: + profile_a.units[unit_name].cpuinfo_regex = unit.cpuinfo_regex + if unit.uname_regex is not None: + profile_a.units[unit_name].uname_regex = unit.uname_regex if unit.script_pre is not None: profile_a.units[unit_name].script_pre = unit.script_pre if unit.script_post is not None: diff --git a/tuned/profiles/unit.py b/tuned/profiles/unit.py index f944d1d..0f5778e 100644 --- a/tuned/profiles/unit.py +++ b/tuned/profiles/unit.py @@ -6,7 +6,7 @@ class Unit(object): """ __slots__ = [ "_name", "_type", "_enabled", "_replace", "_devices", "_devices_udev_regex", \ - "_script_pre", "_script_post", "_options" ] + "_cpuinfo_regex", "_uname_regex", "_script_pre", "_script_post", "_options" ] def __init__(self, name, config): self._name = name @@ -15,6 +15,8 @@ class Unit(object): self._replace = config.pop("replace", False) in [True, "true", 1, "1"] self._devices = config.pop("devices", "*") self._devices_udev_regex = config.pop("devices_udev_regex", None) + self._cpuinfo_regex = config.pop("cpuinfo_regex", None) + self._uname_regex = config.pop("uname_regex", None) self._script_pre = config.pop("script_pre", None) self._script_post = config.pop("script_post", None) self._options = collections.OrderedDict(config) @@ -59,6 +61,22 @@ class Unit(object): def devices_udev_regex(self, value): self._devices_udev_regex = value + @property + def cpuinfo_regex(self): + return self._cpuinfo_regex + + @cpuinfo_regex.setter + def cpuinfo_regex(self, value): + self._cpuinfo_regex = value + + @property + def uname_regex(self): + return self._uname_regex + + @uname_regex.setter + def uname_regex(self, value): + self._uname_regex = value + @property def script_pre(self): return self._script_pre diff --git a/tuned/units/manager.py b/tuned/units/manager.py index 3594340..2fee283 100644 --- a/tuned/units/manager.py +++ b/tuned/units/manager.py @@ -1,9 +1,12 @@ import collections +import os +import re import traceback import tuned.exceptions import tuned.logs import tuned.plugins.exceptions import tuned.consts as consts +from tuned.utils.commands import commands log = tuned.logs.get() @@ -23,6 +26,7 @@ class Manager(object): self._hardware_inventory = hardware_inventory self._instances = [] self._plugins = [] + self._cmd = commands() @property def plugins(self): @@ -36,12 +40,33 @@ class Manager(object): def plugins_repository(self): return self._plugins_repository + def _unit_matches_cpuinfo(self, unit): + if unit.cpuinfo_regex is None: + return True + return re.search(unit.cpuinfo_regex, + self._cmd.read_file("/proc/cpuinfo"), + re.MULTILINE) is not None + + def _unit_matches_uname(self, unit): + if unit.uname_regex is None: + return True + return re.search(unit.uname_regex, + " ".join(os.uname()), + re.MULTILINE) is not None + def create(self, instances_config): instance_info_list = [] for instance_name, instance_info in list(instances_config.items()): if not instance_info.enabled: log.debug("skipping disabled instance '%s'" % instance_name) continue + if not self._unit_matches_cpuinfo(instance_info): + log.debug("skipping instance '%s', cpuinfo does not match" % instance_name) + continue + if not self._unit_matches_uname(instance_info): + log.debug("skipping instance '%s', uname does not match" % instance_name) + continue + instance_info.options.setdefault("priority", self._def_instance_priority) instance_info.options["priority"] = int(instance_info.options["priority"]) instance_info_list.append(instance_info)