diff --git a/tuned/admin/admin.py b/tuned/admin/admin.py index fd96b0a..8d1b107 100644 --- a/tuned/admin/admin.py +++ b/tuned/admin/admin.py @@ -3,6 +3,7 @@ import tuned.admin from tuned.utils.commands import commands from tuned.profiles import Locator as profiles_locator from exceptions import TunedAdminDBusException +from tuned.exceptions import TunedException import tuned.consts as consts import os import sys @@ -111,29 +112,14 @@ class Admin(object): return profile_name def _get_active_profile(self): - profile_name = None - contents = str.strip(self._cmd.read_file(consts.ACTIVE_PROFILE_FILE)) - if contents == '': - profile_name = '' - else: - arr = contents.split('\n') - profile_name = arr[0] - if profile_name == "": - profile_name = None + profile_name, manual = self._cmd.get_active_profile() return profile_name def _get_profile_mode(self): - contents = str.strip(self._cmd.read_file(consts.ACTIVE_PROFILE_FILE)) - if contents == '': - mode = consts.ACTIVE_PROFILE_AUTO - else: - arr = contents.split('\n') - if len(arr) == 1: - # The file was generated by old Tuned -> manual mode - mode = consts.ACTIVE_PROFILE_MANUAL - else: - mode = arr[1] - return mode + (profile, manual) = self._cmd.get_active_profile() + if manual is None: + manual = profile is not None + return consts.ACTIVE_PROFILE_MANUAL if manual else consts.ACTIVE_PROFILE_AUTO def _print_profile_info(self, profile, profile_info): if profile_info[0] == True: @@ -157,7 +143,14 @@ class Admin(object): def _action_profile_info(self, profile = ""): if profile == "": - profile = self._get_active_profile() + try: + profile = self._get_active_profile() + if profile is None: + print("No current active profile.") + return False + except TunedException as e: + self._error(str(e)) + return False return self._print_profile_info(profile, self._profiles_locator.get_profile_attrs(profile, [consts.PROFILE_ATTR_SUMMARY, consts.PROFILE_ATTR_DESCRIPTION], ["", ""])) def _print_profile_name(self, profile_name): @@ -172,7 +165,11 @@ class Admin(object): return self._controller.exit(self._print_profile_name(self._dbus_get_active_profile())) def _action_active(self): - profile_name = self._get_active_profile() + try: + profile_name = self._get_active_profile() + except TunedException as e: + self._error(str(e)) + return False if profile_name is not None and not self._tuned_is_running(): print("It seems that tuned daemon is not running, preset profile is not activated.") print("Preset profile: %s" % profile_name) @@ -183,14 +180,21 @@ class Admin(object): print("Profile selection mode: " + mode) def _action_dbus_profile_mode(self): - mode = self._controller.profile_mode() + mode, error = self._controller.profile_mode() self._print_profile_mode(mode) + if error != "": + self._error(error) + return self._controller.exit(False) return self._controller.exit(True) def _action_profile_mode(self): - mode = self._get_profile_mode() - self._print_profile_mode(mode) - return True + try: + mode = self._get_profile_mode() + self._print_profile_mode(mode) + return True + except TunedException as e: + self._error(str(e)) + return False def _profile_print_status(self, ret, msg): if ret: @@ -238,16 +242,13 @@ class Admin(object): def _set_profile(self, profile_name, manual): if profile_name in self._profiles_locator.get_known_names(): - s = profile_name + '\n' - if manual: - s += consts.ACTIVE_PROFILE_MANUAL + '\n' - else: - s += consts.ACTIVE_PROFILE_AUTO + '\n' - if self._cmd.write_to_file(consts.ACTIVE_PROFILE_FILE, s): + try: + self._cmd.save_active_profile(profile_name, manual) self._restart_tuned() return True - else: - self._error("Unable to switch profile, do you have enough permissions?") + except TunedException as e: + self._error(str(e)) + self._error("Unable to switch profile.") return False else: self._error("Requested profile '%s' doesn't exist." % profile_name) diff --git a/tuned/consts.py b/tuned/consts.py index 7ac6094..0b9fed3 100644 --- a/tuned/consts.py +++ b/tuned/consts.py @@ -1,5 +1,6 @@ GLOBAL_CONFIG_FILE = "/etc/tuned/tuned-main.conf" ACTIVE_PROFILE_FILE = "/etc/tuned/active_profile" +PROFILE_MODE_FILE = "/etc/tuned/profile_mode" PROFILE_FILE = "tuned.conf" RECOMMEND_CONF_FILE = "/etc/tuned/recommend.conf" DAEMONIZE_PARENT_TIMEOUT = 5 @@ -104,7 +105,7 @@ STR_VERIFY_PROFILE_FAIL = "verify: failed: '%s'" # timout for tuned-adm operations in seconds ADMIN_TIMEOUT = 600 -# Strings for /etc/tuned/active_profile specifying if the active profile +# Strings for /etc/tuned/profile_mode specifying if the active profile # was set automatically or manually ACTIVE_PROFILE_AUTO = "auto" ACTIVE_PROFILE_MANUAL = "manual" diff --git a/tuned/daemon/controller.py b/tuned/daemon/controller.py index 087380b..59a55b1 100644 --- a/tuned/daemon/controller.py +++ b/tuned/daemon/controller.py @@ -1,6 +1,7 @@ from tuned import exports import tuned.logs import tuned.exceptions +from tuned.exceptions import TunedException import threading import tuned.consts as consts from tuned.utils.commands import commands @@ -128,14 +129,23 @@ class Controller(tuned.exports.interfaces.ExportableInterface): else: return "" - @exports.export("", "s") + @exports.export("", "(ss)") def profile_mode(self, caller = None): if caller == "": - return "" - if self._daemon.manual: - return consts.ACTIVE_PROFILE_MANUAL - else: - return consts.ACTIVE_PROFILE_AUTO + return "unknown", "Unauthorized" + manual = self._daemon.manual + if manual is None: + # This means no profile is applied. Check the preset value. + try: + profile, manual = self._cmd.get_active_profile() + if manual is None: + manual = profile is not None + except TunedException as e: + mode = "unknown" + error = str(e) + return mode, error + mode = consts.ACTIVE_PROFILE_MANUAL if manual else consts.ACTIVE_PROFILE_AUTO + return mode, "" @exports.export("", "b") def disable(self, caller = None): diff --git a/tuned/daemon/daemon.py b/tuned/daemon/daemon.py index 4292575..930c40c 100644 --- a/tuned/daemon/daemon.py +++ b/tuned/daemon/daemon.py @@ -60,6 +60,11 @@ class Daemon(object): manual = True if profile_name is None: (profile_name, manual) = self._get_startup_profile() + if profile_name is None: + log.info("No profile is preset, running in manual mode. No profile will be enabled.") + # Passed through '-p' cmdline option + elif profile_name == "": + log.info("No profile will be enabled.") self._profile = None self._manual = None @@ -71,7 +76,7 @@ class Daemon(object): if profile_name == "" or profile_name is None: self._profile = None - self._manual = None + self._manual = manual elif profile_name not in self.profile_loader.profile_locator.get_known_names(): raise TunedException(self._notify_profile_changed(profile_name, False, "Requested profile '%s' doesn't exist." % profile_name)) else: @@ -92,8 +97,7 @@ class Daemon(object): @property def manual(self): - # manual == None means /etc/tuned/active_profile is empty -> automatic mode - return self._manual == True or self._manual is None + return self._manual @property def profile_loader(self): @@ -164,58 +168,23 @@ class Daemon(object): def _save_active_profile(self, profile_name, manual): try: - with open(consts.ACTIVE_PROFILE_FILE, "w") as f: - if len(profile_name) > 0: - f.write(profile_name + "\n") - if manual: - f.write(consts.ACTIVE_PROFILE_MANUAL + "\n") - else: - f.write(consts.ACTIVE_PROFILE_AUTO + "\n") - except (OSError,IOError) as e: - log.error("Cannot write active profile into %s: %s" % (consts.ACTIVE_PROFILE_FILE, str(e))) + self._cmd.save_active_profile(profile_name, manual) + except TunedException as e: + log.error(str(e)) - def _set_recommended_profile(self): - log.info("no profile preset, checking what is recommended for your configuration") + def _get_recommended_profile(self): + log.info("Running in automatic mode, checking what profile is recommended for your configuration.") profile = self._cmd.recommend_profile(hardcoded = not self._recommend_command) - log.info("using '%s' profile and setting it as active" % profile) - self._save_active_profile(profile, False) + log.info("Using '%s' profile" % profile) return profile def _get_startup_profile(self): - manual = False - try: - with open(consts.ACTIVE_PROFILE_FILE, "r") as f: - content = f.read().strip() - if content == "": - profile = self._set_recommended_profile() - else: - arr = content.split('\n') - if len(arr) > 2 or (len(arr) == 2 and arr[1] != consts.ACTIVE_PROFILE_AUTO and arr[1] != consts.ACTIVE_PROFILE_MANUAL): - profile = self._set_recommended_profile() - log.error("cannot read active profile from '%s': bad format. Falling back to '%s' profile." - % consts.ACTIVE_PROFILE_FILE, profile) - else: - profile = arr[0] - if len(arr) == 2: - manual = arr[1] == consts.ACTIVE_PROFILE_MANUAL - if not manual: - profile = self._set_recommended_profile() - else: - # The file has only one line - generated by previous Tuned version. - # Treat the profile as manually set. - manual = True - return (profile, manual) - except IOError as e: - if e.errno == errno.ENOENT: - # No such file or directory - profile = self._set_recommended_profile() - else: - profile = consts.DEFAULT_PROFILE - log.error("error reading active profile from '%s', falling back to '%s' profile" % (consts.ACTIVE_PROFILE_FILE, profile)) - return (profile, manual) - except (OSError, EOFError) as e: - log.error("cannot read active profile, falling back to '%s' profile" % consts.DEFAULT_PROFILE) - return (consts.DEFAULT_PROFILE, manual) + profile, manual = self._cmd.get_active_profile() + if manual is None: + manual = profile is not None + if not manual: + profile = self._get_recommended_profile() + return profile, manual def is_enabled(self): return self._profile is not None diff --git a/tuned/utils/commands.py b/tuned/utils/commands.py index c0b4e2d..9e31d78 100644 --- a/tuned/utils/commands.py +++ b/tuned/utils/commands.py @@ -8,6 +8,7 @@ from configobj import ConfigObj, ConfigObjError import re import procfs from subprocess import * +from tuned.exceptions import TunedException log = tuned.logs.get() @@ -463,3 +464,46 @@ class commands: return val except ValueError: return None + + def get_active_profile(self): + profile_name = "" + mode = "" + try: + with open(consts.ACTIVE_PROFILE_FILE, "r") as f: + profile_name = f.read().strip() + except IOError as e: + if e.errno != errno.ENOENT: + raise TunedException("Failed to read active profile: %s" % e) + except (OSError, EOFError) as e: + raise TunedException("Failed to read active profile: %s" % e) + try: + with open(consts.PROFILE_MODE_FILE, "r") as f: + mode = f.read().strip() + if mode not in ["", consts.ACTIVE_PROFILE_AUTO, consts.ACTIVE_PROFILE_MANUAL]: + raise TunedException("Invalid value in file %s." % consts.PROFILE_MODE_FILE) + except IOError as e: + if e.errno != errno.ENOENT: + raise TunedException("Failed to read profile mode: %s" % e) + except (OSError, EOFError) as e: + raise TunedException("Failed to read profile mode: %s" % e) + if mode == "": + manual = None + else: + manual = mode == consts.ACTIVE_PROFILE_MANUAL + if profile_name == "": + profile_name = None + return (profile_name, manual) + + def save_active_profile(self, profile_name, manual): + try: + with open(consts.ACTIVE_PROFILE_FILE, "w") as f: + if profile_name is not None: + f.write(profile_name + "\n") + except (OSError,IOError) as e: + raise TunedException("Cannot write active profile into %s: %s" % (consts.ACTIVE_PROFILE_FILE, str(e))) + try: + with open(consts.PROFILE_MODE_FILE, "w") as f: + mode = consts.ACTIVE_PROFILE_MANUAL if manual else consts.ACTIVE_PROFILE_AUTO + f.write(mode + "\n") + except (OSError,IOError) as e: + raise TunedException("Cannot write profile mode into %s: %s" % (consts.PROFILE_MODE_FILE, str(e)))