1
0
Fork 0

Store profile selection mode in a separate file

The profile selection mode is now written to /etc/tuned/profile_mode
instead of the second line of /etc/tuned/active_profile.

Here are the rules for interpreting the contents of the files. If
either of the files does not exist, it is treated the same as if
it were empty.

If active_profile is empty:
    If profile_mode contains 'manual':
        Manual mode, no profile will be used, tuned will run without a profile
    else if profile_mode is empty or contains 'auto':
        Automatic mode, recommended profile is used
    else:
        Error
else:
    If profile_mode contains 'manual', or is empty (for compatibility reasons):
        Manual mode, the profile in active_profile will be used
    else if profile_mode contains 'auto':
        Automatic mode, recommended profile is used
    else:
        Error

Resolves: https://github.com/redhat-performance/tuned/issues/64

Signed-off-by: Ondřej Lysoněk <olysonek@redhat.com>
This commit is contained in:
Ondřej Lysoněk 2017-09-18 10:50:41 +02:00
parent ab598cd6ef
commit b2c80cabe5
5 changed files with 116 additions and 91 deletions

View file

@ -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)

View file

@ -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"

View file

@ -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):

View file

@ -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

View file

@ -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)))