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:
parent
ab598cd6ef
commit
b2c80cabe5
5 changed files with 116 additions and 91 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)))
|
||||
|
|
|
|||
Loading…
Reference in a new issue