diff --git a/tuned-adm.py b/tuned-adm.py index 4339c18..5564d0e 100755 --- a/tuned-adm.py +++ b/tuned-adm.py @@ -56,8 +56,9 @@ if __name__ == "__main__": parser_off = subparsers.add_parser("recommend", help="recommend profile") parser_off.set_defaults(action="recommend_profile") - parser_off = subparsers.add_parser("verify", help="verify profile") - parser_off.set_defaults(action="verify_profile") + parser_verify = subparsers.add_parser("verify", help="verify profile") + parser_verify.set_defaults(action="verify_profile") + parser_verify.add_argument("--ignore-missing", "-i", action="store_true", help="do not treat missing/non-supported tunings as errors") args = parser.parse_args(sys.argv[1:]) diff --git a/tuned/admin/admin.py b/tuned/admin/admin.py index bf16c8f..9db9c3f 100644 --- a/tuned/admin/admin.py +++ b/tuned/admin/admin.py @@ -180,17 +180,21 @@ class Admin(object): profile = self._cmd.recommend_profile() print profile - def verify_profile(self): + def verify_profile(self, ignore_missing): ret = False if self._controller is None: print "Not supported in no_daemon mode." return False - try: - ret = self._controller.verify_profile() - except TunedAdminDBusException as e: - self._error(e) - self._error("Cannot verify profile if there is no connection to daemon") - return False + else: + try: + if ignore_missing: + ret = self._controller.verify_profile_ignore_missing() + else: + ret = self._controller.verify_profile() + except TunedAdminDBusException as e: + self._error(e) + self._error("Cannot verify profile if there is no compatible running Tuned daemon (or Tuned daemon is too old).") + return False if ret: print "Verfication succeeded, current system settings match the preset profile." diff --git a/tuned/admin/dbus_controller.py b/tuned/admin/dbus_controller.py index 0ae8458..44034ce 100644 --- a/tuned/admin/dbus_controller.py +++ b/tuned/admin/dbus_controller.py @@ -80,6 +80,9 @@ class DBusController(object): def verify_profile(self): return self._call("verify_profile") + def verify_profile_ignore_missing(self): + return self._call("verify_profile_ignore_missing") + def off(self): return self._call("disable") diff --git a/tuned/consts.py b/tuned/consts.py index 4dd04cc..b88947a 100644 --- a/tuned/consts.py +++ b/tuned/consts.py @@ -68,6 +68,8 @@ DBUS_SIGNAL_PROFILE_CHANGED = "profile_changed" STR_VERIFY_PROFILE_DEVICE_VALUE_OK = "verify: passed: device %s: %s = %s" STR_VERIFY_PROFILE_VALUE_OK = "verify: passed: %s = %s" STR_VERIFY_PROFILE_OK = "verify: passed: %s" +STR_VERIFY_PROFILE_DEVICE_VALUE_MISSING = "verify: skipped, missing: device %s: %s" +STR_VERIFY_PROFILE_VALUE_MISSING = "verify: skipped, missing: %s" STR_VERIFY_PROFILE_DEVICE_VALUE_FAIL = "verify: failed: device %s: %s = %s, expected %s" STR_VERIFY_PROFILE_VALUE_FAIL = "verify: failed: %s = %s, expected %s" STR_VERIFY_PROFILE_FAIL = "verify: failed: %s" diff --git a/tuned/daemon/controller.py b/tuned/daemon/controller.py index d6d65bc..75b31b0 100644 --- a/tuned/daemon/controller.py +++ b/tuned/daemon/controller.py @@ -126,4 +126,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface): @exports.export("", "b") def verify_profile(self): - return self._daemon.verify_profile() + return self._daemon.verify_profile(ignore_missing = False) + + @exports.export("", "b") + def verify_profile_ignore_missing(self): + return self._daemon.verify_profile(ignore_missing = True) diff --git a/tuned/daemon/daemon.py b/tuned/daemon/daemon.py index f72af21..b567ff0 100644 --- a/tuned/daemon/daemon.py +++ b/tuned/daemon/daemon.py @@ -197,7 +197,7 @@ class Daemon(object): self._thread.start() return True - def verify_profile(self): + def verify_profile(self, ignore_missing): if not self.is_running(): log.error("tuned is not running") return False @@ -213,7 +213,7 @@ class Daemon(object): # using deamon, the main loop mustn't exit before our completion self._not_used.clear() log.info("verifying profile(s): %s" % self._profile.name) - ret = self._unit_manager.verify_tuning() + ret = self._unit_manager.verify_tuning(ignore_missing) # main loop is allowed to exit self._not_used.set() return ret diff --git a/tuned/plugins/base.py b/tuned/plugins/base.py index 3b4652a..ca6cf96 100644 --- a/tuned/plugins/base.py +++ b/tuned/plugins/base.py @@ -192,7 +192,7 @@ class Plugin(object): if instance.has_dynamic_tuning and self._global_cfg.get(consts.CFG_DYNAMIC_TUNING, consts.CFG_DEF_DYNAMIC_TUNING): self._run_for_each_device(instance, self._instance_apply_dynamic) - def instance_verify_tuning(self, instance): + def instance_verify_tuning(self, instance, ignore_missing): """ Verify static tuning if the plugin instance is active. """ @@ -200,7 +200,7 @@ class Plugin(object): return None if instance.has_static_tuning: - return self._instance_verify_static(instance) + return self._instance_verify_static(instance, ignore_missing) else: return None @@ -227,11 +227,11 @@ class Plugin(object): self._execute_all_non_device_commands(instance) self._execute_all_device_commands(instance, instance.devices) - def _instance_verify_static(self, instance): + def _instance_verify_static(self, instance, ignore_missing): ret = True - if self._verify_all_non_device_commands(instance) == False: + if self._verify_all_non_device_commands(instance, ignore_missing) == False: ret = False - if self._verify_all_device_commands(instance, instance.devices) == False: + if self._verify_all_device_commands(instance, instance.devices, ignore_missing) == False: ret = False return ret @@ -346,23 +346,23 @@ class Plugin(object): for device in devices: self._execute_device_command(instance, command, device, new_value) - def _verify_all_non_device_commands(self, instance): + def _verify_all_non_device_commands(self, instance, ignore_missing): ret = True for command in filter(lambda command: not command["per_device"], self._commands.values()): new_value = self._variables.expand(instance.options.get(command["name"], None)) if new_value is not None: - if self._verify_non_device_command(instance, command, new_value) == False: + if self._verify_non_device_command(instance, command, new_value, ignore_missing) == False: ret = False return ret - def _verify_all_device_commands(self, instance, devices): + def _verify_all_device_commands(self, instance, devices, ignore_missing): ret = True for command in filter(lambda command: command["per_device"], self._commands.values()): new_value = instance.options.get(command["name"], None) if new_value is None: continue for device in devices: - if self._verify_device_command(instance, command, device, new_value) == False: + if self._verify_device_command(instance, command, device, new_value, ignore_missing) == False: ret = False return ret @@ -423,10 +423,17 @@ class Plugin(object): return re.sub(r'^\s*(0+,)+', "", v) return v - def _verify_value(self, name, new_value, current_value, device = None): + def _verify_value(self, name, new_value, current_value, ignore_missing, device = None): if new_value is None: return None ret = False + if current_value is None and ignore_missing: + if device is None: + log.info(consts.STR_VERIFY_PROFILE_VALUE_MISSING % name) + else: + log.info(consts.STR_VERIFY_PROFILE_DEVICE_VALUE_MISSING % (device, name)) + return True + if current_value is not None: current_value = self._norm_value(current_value) new_value = self._norm_value(new_value) @@ -450,7 +457,7 @@ class Plugin(object): log.error(consts.STR_VERIFY_PROFILE_DEVICE_VALUE_FAIL % (device, name, str(current_value).strip(), str(new_value).strip())) return False - def _verify_device_command(self, instance, command, device, new_value): + def _verify_device_command(self, instance, command, device, new_value, ignore_missing): if command["custom"] is not None: return command["custom"](True, new_value, device, True) current_value = self._get_current_value(command, device) @@ -458,9 +465,9 @@ class Plugin(object): if new_value is None: return None new_value = command["set"](new_value, device, True) - return self._verify_value(command["name"], new_value, current_value, device) + return self._verify_value(command["name"], new_value, current_value, ignore_missing, device) - def _verify_non_device_command(self, instance, command, new_value): + def _verify_non_device_command(self, instance, command, new_value, ignore_missing): if command["custom"] is not None: return command["custom"](True, new_value, True) current_value = self._get_current_value(command) @@ -468,7 +475,7 @@ class Plugin(object): if new_value is None: return None new_value = command["set"](new_value, True) - return self._verify_value(command["name"], new_value, current_value) + return self._verify_value(command["name"], new_value, current_value, ignore_missing) def _cleanup_all_non_device_commands(self, instance): for command in filter(lambda command: not command["per_device"], self._commands.values()): diff --git a/tuned/plugins/instance/instance.py b/tuned/plugins/instance/instance.py index d9cd68b..d012cb5 100644 --- a/tuned/plugins/instance/instance.py +++ b/tuned/plugins/instance/instance.py @@ -53,8 +53,8 @@ class Instance(object): def apply_tuning(self): self._plugin.instance_apply_tuning(self) - def verify_tuning(self): - return self._plugin.instance_verify_tuning(self) + def verify_tuning(self, ignore_missing): + return self._plugin.instance_verify_tuning(self, ignore_missing) def update_tuning(self): self._plugin.instance_update_tuning(self) diff --git a/tuned/plugins/plugin_script.py b/tuned/plugins/plugin_script.py index 57a6335..09c4c19 100644 --- a/tuned/plugins/plugin_script.py +++ b/tuned/plugins/plugin_script.py @@ -52,11 +52,14 @@ class ScriptPlugin(base.Plugin): super(self.__class__, self)._instance_apply_static(instance) self._call_scripts(instance._scripts, ["start"]) - def _instance_verify_static(self, instance): + def _instance_verify_static(self, instance, ignore_missing): ret = True - if super(self.__class__, self)._instance_verify_static(instance) == False: + if super(self.__class__, self)._instance_verify_static(instance, ignore_missing) == False: ret = False - if self._call_scripts(instance._scripts, ["verify"]) == True: + args = ["verify"] + if ignore_missing: + args += ["ignore_missing"] + if self._call_scripts(instance._scripts, args) == True: log.info(consts.STR_VERIFY_PROFILE_OK % instance._scripts) else: log.error(consts.STR_VERIFY_PROFILE_FAIL % instance._scripts) diff --git a/tuned/plugins/plugin_sysctl.py b/tuned/plugins/plugin_sysctl.py index 0ee1111..2d30af0 100644 --- a/tuned/plugins/plugin_sysctl.py +++ b/tuned/plugins/plugin_sysctl.py @@ -4,6 +4,7 @@ from decorators import * import tuned.logs from subprocess import * from tuned.utils.commands import commands +import tuned.consts as consts log = tuned.logs.get() @@ -47,16 +48,14 @@ class SysctlPlugin(base.Plugin): self._storage.set("options", instance._sysctl_original) - def _instance_verify_static(self, instance): + def _instance_verify_static(self, instance, ignore_missing): ret = True + # override, so always skip missing + ignore_missing = True for option, value in instance._sysctl.iteritems(): curr_val = self._read_sysctl(option) - if curr_val is None: - log.warn("verify: option '%s' is None, option is probably unavailable/unsupported on your system, skipping it", - str(option)) - else: - if self._verify_value(option, self._cmd.remove_ws(self._variables.expand(value)), curr_val) == False: - ret = False + if self._verify_value(option, self._cmd.remove_ws(self._variables.expand(value)), curr_val, ignore_missing) == False: + ret = False return ret def _instance_unapply_static(self, instance, profile_switch = False): diff --git a/tuned/plugins/plugin_sysfs.py b/tuned/plugins/plugin_sysfs.py index 3f4c045..b07f323 100644 --- a/tuned/plugins/plugin_sysfs.py +++ b/tuned/plugins/plugin_sysfs.py @@ -41,14 +41,14 @@ class SysfsPlugin(base.Plugin): else: log.error("rejecting write to '%s' (not inside /sys)" % f) - def _instance_verify_static(self, instance): + def _instance_verify_static(self, instance, ignore_missing): ret = True for key, value in instance._sysfs.iteritems(): v = self._variables.expand(value) for f in glob.iglob(key): if self._check_sysfs(f): curr_val = self._read_sysfs(f) - if self._verify_value(f, v, curr_val) == False: + if self._verify_value(f, v, curr_val, ignore_missing) == False: ret = False return ret diff --git a/tuned/plugins/plugin_video.py b/tuned/plugins/plugin_video.py index 6aeb1b4..22da1ac 100644 --- a/tuned/plugins/plugin_video.py +++ b/tuned/plugins/plugin_video.py @@ -47,7 +47,7 @@ class VideoPlugin(base.Plugin): if not os.path.exists(sys_files["method"]): if not sim: log.warn("radeon_powersave is not supported on '%s'" % device) - return None + return None if value in ["default", "auto", "low", "mid", "high"]: if not sim: @@ -73,4 +73,4 @@ class VideoPlugin(base.Plugin): elif method == "dynpm": return "dynpm" else: - return None + return None diff --git a/tuned/units/manager.py b/tuned/units/manager.py index c108a25..1097063 100644 --- a/tuned/units/manager.py +++ b/tuned/units/manager.py @@ -80,10 +80,10 @@ class Manager(object): for instance in self._instances: instance.apply_tuning() - def verify_tuning(self): + def verify_tuning(self, ignore_missing): ret = True for instance in self._instances: - if instance.verify_tuning() == False: + if instance.verify_tuning(ignore_missing) == False: ret = False return ret