From 66d5f819450d2dc69411d05fc3357d83471f43c2 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Thu, 2 Feb 2012 10:16:21 +0100 Subject: [PATCH] Theoretically working plugins inheritance. Now it's time to write sysctl and script --- test.cfg | 1 + tuned/plugins/base.py | 5 +++ tuned/plugins/repository.py | 8 ++++ tuned/profile.py | 86 ++++++++++++++++++++++++++++++++++--- tuned/units/unit.py | 4 +- 5 files changed, 96 insertions(+), 8 deletions(-) diff --git a/test.cfg b/test.cfg index 7ec26c4..327f2e0 100644 --- a/test.cfg +++ b/test.cfg @@ -61,6 +61,7 @@ type=cpu [my_test_plugin] type=test +merge=1 [my_broken_plugin] type=broken diff --git a/tuned/plugins/base.py b/tuned/plugins/base.py index 60371b1..7027190 100644 --- a/tuned/plugins/base.py +++ b/tuned/plugins/base.py @@ -7,6 +7,7 @@ class Plugin(object): Methods requiring reimplementation: - update_tuning(self) + - tunable_devices(cls) """ # class methods @@ -15,6 +16,10 @@ class Plugin(object): def _get_default_options(cls): return {} + @classmethod + def tunable_devices(cls): + return None + # instance methods def __init__(self, devices = None, options = None): diff --git a/tuned/plugins/repository.py b/tuned/plugins/repository.py index 399ad3a..f9cff6b 100644 --- a/tuned/plugins/repository.py +++ b/tuned/plugins/repository.py @@ -23,6 +23,14 @@ class PluginRepository(tuned.patterns.Singleton): plugin_exception = tuned.plugins.exception.LoadPluginException(plugin_name, exception) raise plugin_exception + def tunable_devices(self, plugin_name): + try: + plugin_cls = self._loader.load(plugin_name) + return plugin_cls.tunable_devices() + except Exception as exception: + plugin_exception = tuned.plugins.exception.LoadPluginException(plugin_name, exception) + raise plugin_exception + def delete(self, plugin): assert isinstance(plugin, self._loader.interface) plugin.cleanup() diff --git a/tuned/profile.py b/tuned/profile.py index c6a5c34..d3df859 100644 --- a/tuned/profile.py +++ b/tuned/profile.py @@ -26,6 +26,8 @@ import ConfigParser import glob from subprocess import * +import tuned.plugins + log = logs.get() class Profile(object): @@ -38,6 +40,7 @@ class Profile(object): self._elevator = "" # TODO: match cciss* somehow self._elevator_devs = "/sys/block/sd*/queue/scheduler" + self._plugin_configs = {} def _load_sysctl(self, cfg): if cfg.has_section("sysctl"): @@ -125,6 +128,81 @@ class Profile(object): log.error("Script %s error: %s" % (script, e)) return True + def _replace_plugin(self, name, plugin_cfg): + # Iterates over already loaded plugins. + # If the already loaded plugin contains the same device as the newly + # loaded one, remove the device from the already loaded one. + plugins_to_remove = [] + for plugin, cfg in self._plugin_configs.iteritems(): + if cfg["type"] != plugin_cfg["type"]: + continue + + if cfg.has_key("devices") and cfg["devices"] != None: + for device in plugin_cfg["devices"]: + if device in cfg["devices"]: + cfg["devices"].remove(device) + log.debug("Replacing plugin %s device %s by %s" % (plugin, device, name)) + # If we removed all devices, this plugin is not useful anymore, + # so we should remove it too: + if (len(cfg["devices"]) == 0): + plugins_to_remove.append(plugin) + else: + log.debug("Replacing plugin %s by %s" % (plugin, name)) + plugins_to_remove.append(plugin) + + for plugin in plugins_to_remove: + log.debug("Removing plugin %s because it is useless after replace" % (plugin)) + del self._plugin_configs[plugin] + + def _merge_plugin(self, name, plugin_cfg): + # Iterates over already loaded plugins. + # Merges the option of two plugins with the same types together + plugins_to_remove = [] + for plugin, cfg in self._plugin_configs.iteritems(): + if cfg["type"] != plugin_cfg["type"]: + continue + + if cfg.has_key("devices") and cfg["devices"] != None: + for device in plugin_cfg["devices"]: + if device in cfg["devices"]: + log.debug("Merging plugin %s with %s" % (name, plugin)) + plugin_cfg.update(cfg) + plugins_to_remove.append(plugin) + break + else: + log.debug("Merging plugin %s with %s" % (name, plugin)) + plugin_cfg.update(cfg) + plugins_to_remove.append(plugin) + + for plugin in plugins_to_remove: + log.debug("Removing plugin %s because it is useless after merge" % (plugin)) + del self._plugin_configs[plugin] + + def _store_plugin_config(self, name, plugin_cfg): + plugin = plugin_cfg["type"] + # If there are no devices set, set all tunable_devices as default + if not plugin_cfg.has_key("devices"): + try: + plugin_cfg["devices"] = tuned.plugins.get_repository().tunable_devices(plugin) + except tuned.exceptions.TunedException as e: + e.log() + log.error("unable to create unit %s" % plugin) + return + else: + plugin_cfg["devices"] = plugin_cfg["devices"].split(",") + + if plugin_cfg.has_key("merge"): + self._merge_plugin(name, plugin_cfg) + else: + self._replace_plugin(name, plugin_cfg) + self._plugin_configs[name] = plugin_cfg + + def _apply_config(self): + for name, cfg in self._plugin_configs.iteritems(): + plugin = cfg["type"] + del cfg["type"] + p = self._manager.create(name, plugin, cfg) + def _load_config(self, manager, config): if not os.path.exists(config): log.error("Config file %s does not exist" % (config)) @@ -157,17 +235,13 @@ class Profile(object): log.error("No 'type' option for %s plugin" % (section)) continue - plugin = cfg.get(section, "type") - plugin_cfg = dict(cfg.items(section)) - del plugin_cfg["type"] - - p = manager.create(section, plugin, plugin_cfg) + self._store_plugin_config(section, dict(cfg.items(section))) return True def load(self): return (self._load_config(self._manager, self._config_file) and - self._load_ktuned() and self._apply_sysctl() and + self._apply_config() and self._load_ktuned() and self._apply_sysctl() and self._apply_elevator() and self._call_scripts()) def cleanup(self): diff --git a/tuned/units/unit.py b/tuned/units/unit.py index 88cb429..45c96cf 100644 --- a/tuned/units/unit.py +++ b/tuned/units/unit.py @@ -40,8 +40,8 @@ class Unit(object): devices = None assert type(config) is dict if "devices" in config: - devices = config[devices].strip().split() - if len(devices) == 0: + devices = config["devices"] + if devices and len(devices) == 0: devices = None del(config["devices"])