1
0
Fork 0

Merge pull request #690 from zacikpa/rpm-ostree-fix

bootloader: Simplify tuning of rpm-ostree kargs
This commit is contained in:
Jaroslav Škarvada 2025-07-23 08:54:38 +02:00 committed by GitHub
commit b208ff4d5d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 63 additions and 92 deletions

View file

@ -43,7 +43,6 @@ GRUB2_DEFAULT_ENV_FILE = "/etc/default/grub"
INITRD_IMAGE_DIR = "/boot"
BOOT_CMDLINE_TUNED_VAR = "TUNED_BOOT_CMDLINE"
BOOT_CMDLINE_INITRD_ADD_VAR = "TUNED_BOOT_INITRD_ADD"
BOOT_CMDLINE_KARGS_DELETED_VAR = "TUNED_BOOT_KARGS_DELETED"
BOOT_CMDLINE_FILE = "/etc/tuned/bootcmdline"
PETITBOOT_DETECT_DIR = "/sys/firmware/opal"
MACHINE_ID_FILE = "/etc/machine-id"

View file

@ -105,7 +105,7 @@ class BootloaderPlugin(base.Plugin):
----
[main]
include=profile_1
[bootloader]
cmdline_profile_2=-quiet
----
@ -114,7 +114,7 @@ class BootloaderPlugin(base.Plugin):
----
[main]
include=profile_1
[bootloader]
cmdline_profile_1=-quiet
----
@ -209,24 +209,6 @@ class BootloaderPlugin(base.Plugin):
"skip_grub_config": None,
}
@staticmethod
def _options_to_dict(options, omit=""):
"""
Returns dict created from options
e.g.: _options_to_dict("A=A A=B A B=A C=A", "A=B B=A B=B") returns {'A': ['A', None], 'C': ['A']}
"""
d = {}
omit = omit.split()
for o in options.split():
if o not in omit:
arr = o.split('=', 1)
d.setdefault(arr[0], []).append(arr[1] if len(arr) > 1 else None)
return d
@staticmethod
def _dict_to_options(d):
return " ".join([k + "=" + v1 if v1 is not None else k for k, v in d.items() for v1 in v])
def _rpm_ostree_status(self):
"""
Returns status of rpm-ostree transactions or None if not run on rpm-ostree system
@ -241,68 +223,45 @@ class BootloaderPlugin(base.Plugin):
return None
return splited[1]
def _wait_till_idle(self):
def _wait_till_rpm_ostree_idle(self):
"""Check that rpm-ostree is idle, allowing some waiting time."""
sleep_cycles = 10
sleep_secs = 1.0
for i in range(sleep_cycles):
for _ in range(sleep_cycles):
if self._rpm_ostree_status() == "idle":
return True
sleep(sleep_secs)
if self._rpm_ostree_status() == "idle":
return True
return False
return self._rpm_ostree_status() == "idle"
def _rpm_ostree_kargs(self, append={}, delete={}):
"""
Method for appending or deleting rpm-ostree karg
returns None if rpm-ostree not present or is run on not ostree system
or tuple with new kargs, appended kargs and deleted kargs
"""
(rc, out, err) = self._cmd.execute(['rpm-ostree', 'kargs'], return_err=True)
log.debug("rpm-ostree output stdout:\n%s\nstderr:\n%s" % (out, err))
def _get_rpm_ostree_kargs(self):
"""Retrieve the output of rpm-ostree kargs, i.e., current default kernel arguments."""
if not self._wait_till_rpm_ostree_idle():
log.error("Error getting rpm-ostree kargs: rpm-ostree is busy")
return None
(rc, out, err) = self._cmd.execute(["rpm-ostree", "kargs"], return_err=True)
if out:
log.debug("rpm-ostree kargs: %s" % out)
if rc != 0:
return None, None, None
kargs = self._options_to_dict(out)
log.error("Error getting rpm-ostree kargs: %s" % err)
return None
return out
if not self._wait_till_idle():
log.error("Cannot wait for transaction end")
return None, None, None
deleted = {}
delete_params = self._dict_to_options(delete).split()
# Deleting kargs, e.g. deleting added kargs by profile
for k, val in delete.items():
for v in val:
kargs[k].remove(v)
deleted[k] = val
appended = {}
append_params = self._dict_to_options(append).split()
# Appending kargs, e.g. new kargs by profile or restoring kargs replaced by profile
for k, val in append.items():
if kargs.get(k):
# If there is karg that we add with new value we want to delete it
# and store old value for restoring after profile unload
log.debug("adding rpm-ostree kargs %s: %s for delete" % (k, kargs[k]))
deleted.setdefault(k, []).extend(kargs[k])
delete_params.extend([k + "=" + v if v is not None else k for v in kargs[k]])
kargs[k] = []
kargs.setdefault(k, []).extend(val)
appended[k] = val
if append_params == delete_params:
log.info("skipping rpm-ostree kargs - append == deleting (%s)" % append_params)
return kargs, appended, deleted
log.info("rpm-ostree kargs - appending: '%s'; deleting: '%s'" % (append_params, delete_params))
(rc, _, err) = self._cmd.execute(['rpm-ostree', 'kargs'] +
['--append=%s' % v for v in append_params] +
['--delete=%s' % v for v in delete_params], return_err=True)
def _modify_rpm_ostree_kargs(self, delete_kargs=[], append_kargs=[]):
"""
Modify (delete and append) kernel arguments in a rpm-ostree system.
Return a boolean indicating whether the operation was successful.
"""
if not self._wait_till_rpm_ostree_idle():
log.error("Error modifying rpm-ostree kargs: rpm-ostree is busy")
return False
(rc, _, err) = self._cmd.execute(
["rpm-ostree", "kargs"] +
["--delete=%s" % karg for karg in delete_kargs] +
["--append=%s" % karg for karg in append_kargs], return_err=True)
if rc != 0:
log.error("Something went wrong with rpm-ostree kargs\n%s" % (err))
return self._options_to_dict(out), None, None
else:
return kargs, appended, deleted
log.error("Error modifying rpm-ostree kargs: %s" % err)
return False
return True
def _get_effective_options(self, options):
"""Merge provided options with plugin default options and merge all cmdline.* options."""
@ -368,18 +327,16 @@ class BootloaderPlugin(base.Plugin):
log.info("removing initrd image '%s'" % self._initrd_dst_img_val)
self._cmd.unlink(self._initrd_dst_img_val)
def _get_rpm_ostree_changes(self):
def _get_appended_rpm_ostree_kargs(self):
"""Return the list of kernel arguments that were appended by this profile (in a rpm-ostree system)."""
f = self._cmd.read_file(consts.BOOT_CMDLINE_FILE)
appended = re.search(consts.BOOT_CMDLINE_TUNED_VAR + r"=\"(.*)\"", f, flags=re.MULTILINE)
appended = appended[1] if appended else ""
deleted = re.search(consts.BOOT_CMDLINE_KARGS_DELETED_VAR + r"=\"(.*)\"", f, flags=re.MULTILINE)
deleted = deleted[1] if deleted else ""
return appended, deleted
return appended[1].split() if appended else []
def _remove_rpm_ostree_tuning(self):
appended, deleted = self._get_rpm_ostree_changes()
self._rpm_ostree_kargs(append=self._options_to_dict(deleted), delete=self._options_to_dict(appended))
self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR: "", consts.BOOT_CMDLINE_KARGS_DELETED_VAR: ""})
"""Remove kernel parameter tuning in a rpm-ostree system."""
self._modify_rpm_ostree_kargs(delete_kargs=self._get_appended_rpm_ostree_kargs())
self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR: ""})
def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
if rollback == consts.ROLLBACK_FULL and not self._skip_grub_config_val:
@ -489,14 +446,30 @@ class BootloaderPlugin(base.Plugin):
return True
def _rpm_ostree_update(self):
appended, _ = self._get_rpm_ostree_changes()
_cmdline_dict = self._options_to_dict(self._cmdline_val, appended)
if not _cmdline_dict:
return None
(_, _, d) = self._rpm_ostree_kargs(append=_cmdline_dict)
if d is None:
"""Apply kernel parameter tuning in a rpm-ostree system."""
appended_kargs = self._get_appended_rpm_ostree_kargs()
profile_kargs = self._cmdline_val.split()
active_kargs = self._get_rpm_ostree_kargs()
if active_kargs is None:
log.error("Not updating kernel arguments, could not read the current ones.")
return
self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR : self._cmdline_val, consts.BOOT_CMDLINE_KARGS_DELETED_VAR : self._dict_to_options(d)})
# Ignore kargs previously appended by TuneD, these will be removed later.
non_tuned_kargs = active_kargs.split()
for karg in appended_kargs:
non_tuned_kargs.remove(karg)
# Only append key=value pairs that do not yet appear in kernel parameters,
# otherwise we would not be able to restore the cmdline to the previous state
# via rpm-ostree kargs --delete.
kargs_to_append = [karg for karg in profile_kargs if karg not in non_tuned_kargs]
if appended_kargs == kargs_to_append:
# The correct kargs are already set in /etc/tuned/bootcmldine,
# we are likely post-reboot and done.
log.info("Kernel arguments already set, not updating.")
return
# If there are kargs in /etc/bootcmdline and they do not match
# the requested ones, there was no rollback, so remove them now.
if self._modify_rpm_ostree_kargs(delete_kargs=appended_kargs, append_kargs=kargs_to_append):
self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR : " ".join(kargs_to_append)})
def _grub2_update(self):
self._grub2_cfg_patch({consts.GRUB2_TUNED_VAR : self._cmdline_val, consts.GRUB2_TUNED_INITRD_VAR : self._initrd_val})
@ -646,11 +619,10 @@ class BootloaderPlugin(base.Plugin):
v = self._variables.expand(self._cmd.unquote(value))
if verify:
if self._rpm_ostree:
rpm_ostree_kargs = self._rpm_ostree_kargs()[0]
cmdline = self._dict_to_options(rpm_ostree_kargs)
cmdline = self._get_rpm_ostree_kargs()
else:
cmdline = self._cmd.read_file("/proc/cmdline")
if len(cmdline) == 0:
if cmdline is None or len(cmdline) == 0:
return None
cmdline_set = set(cmdline.split())
value_set = set(v.split())