1
0
Fork 0

Add an option to configure profile directories

Resolves: RHEL-26157
This commit is contained in:
Pavol Žáčik 2024-03-25 16:30:18 +01:00
parent a916594a49
commit 90ea23b8b3
No known key found for this signature in database
GPG key ID: B99527D5E6487A92
8 changed files with 45 additions and 28 deletions

View file

@ -6,10 +6,19 @@
*TuneD* stores profiles in the following directories:
[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/`::
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"]
.Additional resources

View file

@ -124,10 +124,11 @@ if __name__ == "__main__":
log_level = options.pop("loglevel")
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)
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)
except:

View file

@ -130,7 +130,7 @@ class Base(object):
return
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()
@ -373,8 +373,8 @@ class Base(object):
try:
self.manager.remove_profile(profile, is_admin=self.is_admin)
except ManagerException:
self.error_dialog('failed to authorize', '')
except ManagerException as ex:
self.error_dialog('Removing profile failed', ex.__str__())
return
for item in self.treestore_profiles:
@ -591,8 +591,8 @@ class Base(object):
copied_profile.name = self.editing_profile_name + '-modified'
try:
self.manager.save_profile(copied_profile)
except ManagerException:
self.error_dialog('failed to authorize', '')
except ManagerException as ex:
self.error_dialog('Error saving profile', ex.__str__())
return
else:
if not TunedDialog('System profile can not be modified '

View file

@ -82,3 +82,8 @@ log_file_max_size = 1MB
# - not_on_exit: rollbacks are always performed on a profile
# switch, but not on any kind of TuneD process exit
# 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

View file

@ -15,15 +15,15 @@ import threading
import logging
class Admin(object):
def __init__(self, dbus = True, debug = False, asynco = False,
timeout = consts.ADMIN_TIMEOUT,
def __init__(self, profile_dirs, dbus = True, debug = False,
asynco = False, timeout = consts.ADMIN_TIMEOUT,
log_level = logging.ERROR):
self._dbus = dbus
self._debug = debug
self._async = asynco
self._timeout = timeout
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_profile = ""
self._daemon_action_result = True

View file

@ -13,7 +13,7 @@ DBUS_INTERFACE = "com.redhat.tuned.control"
DBUS_OBJECT = "/Tuned"
DEFAULT_PROFILE = "balanced"
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"
PLUGIN_MAIN_UNIT_NAME = "main"
# 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_CPU_EPP_FLAG = "hwp_epp"
CFG_ROLLBACK = "rollback"
CFG_PROFILE_DIRS = "profile_dirs"
# no_daemon mode
CFG_DEF_DAEMON = True
@ -171,6 +172,8 @@ CFG_DEF_UNIX_SOCKET_CONNECTIONS_BACKLOG = "1024"
CFG_FUNC_UNIX_SOCKET_CONNECTIONS_BACKLOG = "getint"
# default rollback strategy
CFG_DEF_ROLLBACK = "auto"
# default profile directories
CFG_DEF_PROFILE_DIRS = [SYSTEM_PROFILE_DIR, "/etc/tuned"]
PATH_CPU_DMA_LATENCY = "/dev/cpu_dma_latency"

View file

@ -50,7 +50,7 @@ class Application(object):
profile_factory = profiles.Factory()
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)
self._daemon = daemon.Daemon(unit_manager, profile_loader, profile_name, self.config, self)

View file

@ -60,7 +60,7 @@ class GuiProfileLoader(object):
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
config_parser = ConfigParser(delimiters=('='), inline_comment_prefixes=('#'), strict=False)
config_parser.optionxform = str
@ -127,7 +127,15 @@ class GuiProfileLoader(object):
self._load_all_profiles()
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 = {
'main': collections.OrderedDict(),
'filename': path + '/' + tuned.consts.PROFILE_FILE,
@ -160,7 +168,7 @@ class GuiProfileLoader(object):
raise managerException.ManagerException('Profile: '
+ 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:
self.remove_profile(old_profile_name, is_admin=is_admin)
@ -207,20 +215,11 @@ class GuiProfileLoader(object):
+ ' profile is stored in ' + profile_path)
def is_profile_removable(self, 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
return not self.is_profile_factory(profile_name)
def is_profile_factory(self, profile_name):
# profile is in /usr/lib/tuned
return not self.is_profile_removable(profile_name)
profile_path = self._locate_profile_path(profile_name)
return profile_path == tuned.consts.SYSTEM_PROFILE_DIR
def _save_profile(self, config):
ec = subprocess.call(['pkexec', sys.executable, tuned.gtk.gui_profile_saver.__file__ , json.dumps(config)])