Add an option to configure profile directories
Resolves: RHEL-26157
This commit is contained in:
parent
a916594a49
commit
90ea23b8b3
8 changed files with 45 additions and 28 deletions
|
|
@ -6,10 +6,19 @@
|
||||||
*TuneD* stores profiles in the following directories:
|
*TuneD* stores profiles in the following directories:
|
||||||
|
|
||||||
[filename]`/usr/lib/tuned/`::
|
[filename]`/usr/lib/tuned/`::
|
||||||
Distribution-specific profiles are stored in the directory. Each profile has its own directory. The profile consists of the main configuration file called `tuned.conf`, and optionally other files, for example helper scripts.
|
Distribution-specific profiles are stored in the [filename]`/usr/lib/tuned/` directory. Each profile has its own directory. The profile consists of the main configuration file called `tuned.conf`, and optionally other files, for example helper scripts.
|
||||||
|
|
||||||
[filename]`/etc/tuned/`::
|
[filename]`/etc/tuned/`::
|
||||||
If you need to customize a profile, copy the profile directory into the directory, which is used for custom profiles. If there are two profiles of the same name, the custom profile located in [filename]`/etc/tuned/` is used.
|
If you need to customize a profile, copy the profile directory into the [filename]`/etc/tuned/` directory, which is used for custom profiles, and then adjust it. If there is a system profile and a custom profile of the same name, the custom profile located in [filename]`/etc/tuned/` is used.
|
||||||
|
|
||||||
|
.User-defined profile directories
|
||||||
|
====
|
||||||
|
If you want to make TuneD load profiles from a directory other than [filename]`/usr/lib/tuned/` and [filename]`/etc/tuned/`, you can list it in [filename]`/etc/tuned/tuned-main.conf` as follows:
|
||||||
|
----
|
||||||
|
profile_dirs=/usr/lib/tuned,/etc/tuned,/my/custom/profiles
|
||||||
|
----
|
||||||
|
In this example, profiles are loaded also from [filename]`/my/custom/profiles/`. If two directories contain profiles with the same names, the one that is listed later takes precedence.
|
||||||
|
====
|
||||||
|
|
||||||
[role="_additional-resources"]
|
[role="_additional-resources"]
|
||||||
.Additional resources
|
.Additional resources
|
||||||
|
|
|
||||||
|
|
@ -124,10 +124,11 @@ if __name__ == "__main__":
|
||||||
log_level = options.pop("loglevel")
|
log_level = options.pop("loglevel")
|
||||||
result = False
|
result = False
|
||||||
|
|
||||||
|
profile_dirs = config.get_list(consts.CFG_PROFILE_DIRS, consts.CFG_DEF_PROFILE_DIRS)
|
||||||
dbus = config.get_bool(consts.CFG_DAEMON, consts.CFG_DEF_DAEMON)
|
dbus = config.get_bool(consts.CFG_DAEMON, consts.CFG_DEF_DAEMON)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
admin = tuned.admin.Admin(dbus, debug, asynco, timeout, log_level)
|
admin = tuned.admin.Admin(profile_dirs, dbus, debug, asynco, timeout, log_level)
|
||||||
|
|
||||||
result = admin.action(action_name, **options)
|
result = admin.action(action_name, **options)
|
||||||
except:
|
except:
|
||||||
|
|
|
||||||
10
tuned-gui.py
10
tuned-gui.py
|
|
@ -130,7 +130,7 @@ class Base(object):
|
||||||
return
|
return
|
||||||
|
|
||||||
self.manager = tuned.gtk.gui_profile_loader.GuiProfileLoader(
|
self.manager = tuned.gtk.gui_profile_loader.GuiProfileLoader(
|
||||||
tuned.consts.LOAD_DIRECTORIES)
|
self.config.get_list(consts.CFG_PROFILE_DIRS, consts.CFG_DEF_PROFILE_DIRS))
|
||||||
|
|
||||||
self.plugin_loader = tuned.gtk.gui_plugin_loader.GuiPluginLoader()
|
self.plugin_loader = tuned.gtk.gui_plugin_loader.GuiPluginLoader()
|
||||||
|
|
||||||
|
|
@ -373,8 +373,8 @@ class Base(object):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.manager.remove_profile(profile, is_admin=self.is_admin)
|
self.manager.remove_profile(profile, is_admin=self.is_admin)
|
||||||
except ManagerException:
|
except ManagerException as ex:
|
||||||
self.error_dialog('failed to authorize', '')
|
self.error_dialog('Removing profile failed', ex.__str__())
|
||||||
return
|
return
|
||||||
|
|
||||||
for item in self.treestore_profiles:
|
for item in self.treestore_profiles:
|
||||||
|
|
@ -591,8 +591,8 @@ class Base(object):
|
||||||
copied_profile.name = self.editing_profile_name + '-modified'
|
copied_profile.name = self.editing_profile_name + '-modified'
|
||||||
try:
|
try:
|
||||||
self.manager.save_profile(copied_profile)
|
self.manager.save_profile(copied_profile)
|
||||||
except ManagerException:
|
except ManagerException as ex:
|
||||||
self.error_dialog('failed to authorize', '')
|
self.error_dialog('Error saving profile', ex.__str__())
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
if not TunedDialog('System profile can not be modified '
|
if not TunedDialog('System profile can not be modified '
|
||||||
|
|
|
||||||
|
|
@ -82,3 +82,8 @@ log_file_max_size = 1MB
|
||||||
# - not_on_exit: rollbacks are always performed on a profile
|
# - not_on_exit: rollbacks are always performed on a profile
|
||||||
# switch, but not on any kind of TuneD process exit
|
# switch, but not on any kind of TuneD process exit
|
||||||
# rollback = auto
|
# rollback = auto
|
||||||
|
|
||||||
|
# Directories to search for profiles separated by , or ;
|
||||||
|
# In case of conflicts in profile names, the later directory
|
||||||
|
# takes precedence
|
||||||
|
# profile_dirs = /usr/lib/tuned,/etc/tuned
|
||||||
|
|
|
||||||
|
|
@ -15,15 +15,15 @@ import threading
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
class Admin(object):
|
class Admin(object):
|
||||||
def __init__(self, dbus = True, debug = False, asynco = False,
|
def __init__(self, profile_dirs, dbus = True, debug = False,
|
||||||
timeout = consts.ADMIN_TIMEOUT,
|
asynco = False, timeout = consts.ADMIN_TIMEOUT,
|
||||||
log_level = logging.ERROR):
|
log_level = logging.ERROR):
|
||||||
self._dbus = dbus
|
self._dbus = dbus
|
||||||
self._debug = debug
|
self._debug = debug
|
||||||
self._async = asynco
|
self._async = asynco
|
||||||
self._timeout = timeout
|
self._timeout = timeout
|
||||||
self._cmd = commands(debug)
|
self._cmd = commands(debug)
|
||||||
self._profiles_locator = profiles_locator(consts.LOAD_DIRECTORIES)
|
self._profiles_locator = profiles_locator(profile_dirs)
|
||||||
self._daemon_action_finished = threading.Event()
|
self._daemon_action_finished = threading.Event()
|
||||||
self._daemon_action_profile = ""
|
self._daemon_action_profile = ""
|
||||||
self._daemon_action_result = True
|
self._daemon_action_result = True
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ DBUS_INTERFACE = "com.redhat.tuned.control"
|
||||||
DBUS_OBJECT = "/Tuned"
|
DBUS_OBJECT = "/Tuned"
|
||||||
DEFAULT_PROFILE = "balanced"
|
DEFAULT_PROFILE = "balanced"
|
||||||
DEFAULT_STORAGE_FILE = "/run/tuned/save.pickle"
|
DEFAULT_STORAGE_FILE = "/run/tuned/save.pickle"
|
||||||
LOAD_DIRECTORIES = ["/usr/lib/tuned", "/etc/tuned"]
|
SYSTEM_PROFILE_DIR = "/usr/lib/tuned"
|
||||||
PERSISTENT_STORAGE_DIR = "/var/lib/tuned"
|
PERSISTENT_STORAGE_DIR = "/var/lib/tuned"
|
||||||
PLUGIN_MAIN_UNIT_NAME = "main"
|
PLUGIN_MAIN_UNIT_NAME = "main"
|
||||||
# Magic section header because ConfigParser does not support "headerless" config
|
# Magic section header because ConfigParser does not support "headerless" config
|
||||||
|
|
@ -122,6 +122,7 @@ CFG_UNIX_SOCKET_PERMISIONS = "unix_socket_permissions"
|
||||||
CFG_UNIX_SOCKET_CONNECTIONS_BACKLOG = "connections_backlog"
|
CFG_UNIX_SOCKET_CONNECTIONS_BACKLOG = "connections_backlog"
|
||||||
CFG_CPU_EPP_FLAG = "hwp_epp"
|
CFG_CPU_EPP_FLAG = "hwp_epp"
|
||||||
CFG_ROLLBACK = "rollback"
|
CFG_ROLLBACK = "rollback"
|
||||||
|
CFG_PROFILE_DIRS = "profile_dirs"
|
||||||
|
|
||||||
# no_daemon mode
|
# no_daemon mode
|
||||||
CFG_DEF_DAEMON = True
|
CFG_DEF_DAEMON = True
|
||||||
|
|
@ -171,6 +172,8 @@ CFG_DEF_UNIX_SOCKET_CONNECTIONS_BACKLOG = "1024"
|
||||||
CFG_FUNC_UNIX_SOCKET_CONNECTIONS_BACKLOG = "getint"
|
CFG_FUNC_UNIX_SOCKET_CONNECTIONS_BACKLOG = "getint"
|
||||||
# default rollback strategy
|
# default rollback strategy
|
||||||
CFG_DEF_ROLLBACK = "auto"
|
CFG_DEF_ROLLBACK = "auto"
|
||||||
|
# default profile directories
|
||||||
|
CFG_DEF_PROFILE_DIRS = [SYSTEM_PROFILE_DIR, "/etc/tuned"]
|
||||||
|
|
||||||
PATH_CPU_DMA_LATENCY = "/dev/cpu_dma_latency"
|
PATH_CPU_DMA_LATENCY = "/dev/cpu_dma_latency"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ class Application(object):
|
||||||
|
|
||||||
profile_factory = profiles.Factory()
|
profile_factory = profiles.Factory()
|
||||||
profile_merger = profiles.Merger()
|
profile_merger = profiles.Merger()
|
||||||
profile_locator = profiles.Locator(consts.LOAD_DIRECTORIES)
|
profile_locator = profiles.Locator(self.config.get_list(consts.CFG_PROFILE_DIRS, consts.CFG_DEF_PROFILE_DIRS))
|
||||||
profile_loader = profiles.Loader(profile_locator, profile_factory, profile_merger, self.config, self.variables)
|
profile_loader = profiles.Loader(profile_locator, profile_factory, profile_merger, self.config, self.variables)
|
||||||
|
|
||||||
self._daemon = daemon.Daemon(unit_manager, profile_loader, profile_name, self.config, self)
|
self._daemon = daemon.Daemon(unit_manager, profile_loader, profile_name, self.config, self)
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ class GuiProfileLoader(object):
|
||||||
|
|
||||||
profilePath = self._locate_profile_path(profile_name)
|
profilePath = self._locate_profile_path(profile_name)
|
||||||
|
|
||||||
if profilePath == tuned.consts.LOAD_DIRECTORIES[1]:
|
if profilePath != tuned.consts.SYSTEM_PROFILE_DIR:
|
||||||
file_path = profilePath + '/' + profile_name + '/' + tuned.consts.PROFILE_FILE
|
file_path = profilePath + '/' + profile_name + '/' + tuned.consts.PROFILE_FILE
|
||||||
config_parser = ConfigParser(delimiters=('='), inline_comment_prefixes=('#'), strict=False)
|
config_parser = ConfigParser(delimiters=('='), inline_comment_prefixes=('#'), strict=False)
|
||||||
config_parser.optionxform = str
|
config_parser.optionxform = str
|
||||||
|
|
@ -127,7 +127,15 @@ class GuiProfileLoader(object):
|
||||||
self._load_all_profiles()
|
self._load_all_profiles()
|
||||||
|
|
||||||
def save_profile(self, profile):
|
def save_profile(self, profile):
|
||||||
path = tuned.consts.LOAD_DIRECTORIES[1] + '/' + profile.name
|
# save the new profile to a non-system directory with the highest priority
|
||||||
|
path = None
|
||||||
|
for d in reversed(self.directories):
|
||||||
|
if d != tuned.consts.SYSTEM_PROFILE_DIR:
|
||||||
|
path = os.path.join(d, profile.name)
|
||||||
|
break
|
||||||
|
if path is None:
|
||||||
|
raise managerException.ManagerException('Cannot save profile to a system directory')
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
'main': collections.OrderedDict(),
|
'main': collections.OrderedDict(),
|
||||||
'filename': path + '/' + tuned.consts.PROFILE_FILE,
|
'filename': path + '/' + tuned.consts.PROFILE_FILE,
|
||||||
|
|
@ -160,7 +168,7 @@ class GuiProfileLoader(object):
|
||||||
raise managerException.ManagerException('Profile: '
|
raise managerException.ManagerException('Profile: '
|
||||||
+ old_profile_name + ' is not in profiles')
|
+ old_profile_name + ' is not in profiles')
|
||||||
|
|
||||||
path = tuned.consts.LOAD_DIRECTORIES[1] + '/' + profile.name
|
path = os.path.join(self._locate_profile_path(old_profile_name), profile.name)
|
||||||
|
|
||||||
if old_profile_name != profile.name:
|
if old_profile_name != profile.name:
|
||||||
self.remove_profile(old_profile_name, is_admin=is_admin)
|
self.remove_profile(old_profile_name, is_admin=is_admin)
|
||||||
|
|
@ -207,20 +215,11 @@ class GuiProfileLoader(object):
|
||||||
+ ' profile is stored in ' + profile_path)
|
+ ' profile is stored in ' + profile_path)
|
||||||
|
|
||||||
def is_profile_removable(self, profile_name):
|
def is_profile_removable(self, profile_name):
|
||||||
|
return not self.is_profile_factory(profile_name)
|
||||||
# profile is in /etc/profile
|
|
||||||
|
|
||||||
profile_path = self._locate_profile_path(profile_name)
|
|
||||||
if profile_path == tuned.consts.LOAD_DIRECTORIES[1]:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def is_profile_factory(self, profile_name):
|
def is_profile_factory(self, profile_name):
|
||||||
|
profile_path = self._locate_profile_path(profile_name)
|
||||||
# profile is in /usr/lib/tuned
|
return profile_path == tuned.consts.SYSTEM_PROFILE_DIR
|
||||||
|
|
||||||
return not self.is_profile_removable(profile_name)
|
|
||||||
|
|
||||||
def _save_profile(self, config):
|
def _save_profile(self, config):
|
||||||
ec = subprocess.call(['pkexec', sys.executable, tuned.gtk.gui_profile_saver.__file__ , json.dumps(config)])
|
ec = subprocess.call(['pkexec', sys.executable, tuned.gtk.gui_profile_saver.__file__ , json.dumps(config)])
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue