generated from linux-system-roles/template
-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add bootloader_settings module to configure settings instead of tasks
- Loading branch information
Showing
8 changed files
with
217 additions
and
107 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
# Copyright: (c) 2023, Sergei Petrosian <[email protected]> | ||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
from __future__ import absolute_import, division, print_function | ||
|
||
__metaclass__ = type | ||
|
||
DOCUMENTATION = r""" | ||
|
@@ -47,23 +48,20 @@ def run_module(): | |
# supports check mode | ||
module = AnsibleModule(argument_spec=module_args, supports_check_mode=True) | ||
|
||
# Keys from `grubby --info=ALL`, values for which this module returns | ||
grubby_keys = ["args", "id", "index", "initrd", "kernel", "root", "title"] | ||
|
||
rc, stdout, stderr = module.run_command("grubby --info=ALL") | ||
if "Permission denied" in stderr: | ||
module.fail_json(msg="You must run this as sudo", **result) | ||
stdout_lines = stdout.strip().split('\n') | ||
stdout_lines = stdout.strip().split("\n") | ||
kernels = [] | ||
index_count = 0 | ||
for line in stdout_lines: | ||
if re.search("index=\d+", line): | ||
if re.search(r"index=\d+", line): | ||
index_count += 1 | ||
kernels.append({}) | ||
search = re.search("(.*?)=(.*)", line) | ||
search = re.search(r"(.*?)=(.*)", line) | ||
key = search.group(1).strip('"') | ||
value = search.group(2).strip('"') | ||
kernels[index_count -1].update({key: value}) | ||
kernels[index_count - 1].update({key: value}) | ||
result["ansible_facts"]["bootloader_facts"] = kernels | ||
|
||
# in the event of a successful module execution, you will want to | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,203 @@ | ||
#!/usr/bin/python | ||
|
||
# Copyright: (c) 2023, Sergei Petrosian <[email protected]> | ||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
from __future__ import absolute_import, division, print_function | ||
|
||
__metaclass__ = type | ||
|
||
DOCUMENTATION = r""" | ||
--- | ||
module: bootloader_settings | ||
short_description: Configure grubby boot loader arguments for specified kernels | ||
version_added: "0.0.1" | ||
description: | ||
- "WARNING: Do not use this module directly! It is only for role internal use." | ||
- Configure grubby boot loader arguments for specified kernels | ||
options: | ||
bootloader_settings: | ||
description: List of kernels and their command line parameters that you want to set. | ||
required: true | ||
type: list | ||
author: | ||
- Sergei Petrosian (@spetrosi) | ||
""" | ||
|
||
EXAMPLES = r""" | ||
- name: Test with a message | ||
bootloader_settings: | ||
bootloader_settings: | ||
""" | ||
|
||
RETURN = r""" | ||
# These are examples of possible return values, and in general should use other names for return values. | ||
# original_message: | ||
# description: The original name param that was passed in. | ||
# type: str | ||
# returned: always | ||
# sample: 'hello world' | ||
# message: | ||
# description: The output message that the test module generates. | ||
# type: str | ||
# returned: always | ||
# sample: 'goodbye' | ||
""" | ||
|
||
import re | ||
|
||
from ansible.module_utils.basic import AnsibleModule | ||
|
||
# import ansible.module_utils.six as ansible_six | ||
import ansible.module_utils.six.moves as ansible_six_moves | ||
|
||
|
||
def get_grubby_args(kernel): | ||
module_args = dict(bootloader_settings=dict(type="list", required=True)) | ||
module = AnsibleModule(argument_spec=module_args, supports_check_mode=True) | ||
rc, kernel_info, stderr = module.run_command("grubby --info=" + kernel) | ||
# kernel_info = "index=0\nkernel=\"/boot/vmlinuz-5.14.0-386.el9.x86_64\"\nargs=\"console=tty0 console=ttyS0,115200n8 no_timer_check net.ifnames=0 crashkernel=1G-4G:192M,4G-64G:256M,64G-:512M $tuned_params\"\nroot=\"UUID=b4f467ad-fe53-4523-af54-30fcad90aacc\"\ninitrd=\"/boot/initramfs-5.14.0-386.el9.x86_64.img $tuned_initrd\"\ntitle=\"Red Hat Enterprise Linux (5.14.0-386.el9.x86_64) 9.4 (Plow)\"\nid=\"ffffffffffffffffffffffffffffffff-5.14.0-386.el9.x86_64\"\n" | ||
return re.search(r'args="(.*)"', kernel_info).group(1) | ||
|
||
|
||
def escapeval(val): | ||
"""make sure val is quoted as in shell""" | ||
return ansible_six_moves.shlex_quote(str(val)) | ||
|
||
|
||
def run_module(): | ||
# define available arguments/parameters a user can pass to the module | ||
module_args = dict(bootloader_settings=dict(type="list", required=True)) | ||
|
||
# seed the result dict in the object | ||
# we primarily care about changed and state | ||
# changed is if this module effectively modified the target | ||
# state will include any data that you want your module to pass back | ||
# for consumption, for example, in a subsequent task | ||
result = dict( | ||
changed=False, | ||
) | ||
|
||
# the AnsibleModule object will be our abstraction working with Ansible | ||
# this includes instantiation, a couple of common attr would be the | ||
# args/params passed to the execution, as well as if the module | ||
# supports check mode | ||
module = AnsibleModule(argument_spec=module_args, supports_check_mode=True) | ||
|
||
kernels = [] | ||
# kernels_keys = ["kernel_index", "kernel_path", "kernel_title"] | ||
for bootloader_setting in module.params["bootloader_settings"]: | ||
# if type(bootloader_setting["kernel"]) is not str: | ||
# bootloader_kernel = bootloader_setting["kernel"] | ||
# for kernel_key in kernels_keys: | ||
# kernel_key_list = [] | ||
# if kernel_key in bootloader_setting["kernel"]: | ||
# if type(bootloader_setting["kernel"][kernel_key]) is list: | ||
# for kernel_val in bootloader_setting["kernel"][kernel_key]: | ||
# kernel_key_list.append( | ||
# {"name": escapeval(kernel_val)} | ||
# ) | ||
# kernel_key_list.append( | ||
# {"options": bootloader_setting["options"]} | ||
# ) | ||
# else: | ||
# kernel_key_list.append( | ||
# {"name": escapeval(bootloader_setting["kernel"][kernel_key])} | ||
# ) | ||
# kernel_key_list.append( | ||
# {"options": bootloader_setting["options"]} | ||
# ) | ||
# kernels.append({kernel_key: kernel_key_list}) | ||
# else: | ||
# kernels.append({bootloader_setting["kernel"]: bootloader_setting["options"]}) | ||
|
||
if "kernel_path" in bootloader_setting["kernel"]: | ||
kernels = bootloader_setting["kernel"]["kernel_path"] | ||
elif "kernel_index" in bootloader_setting["kernel"]: | ||
kernels = bootloader_setting["kernel"]["kernel_index"] | ||
elif "kernel_title" in bootloader_setting["kernel"]: | ||
if isinstance(bootloader_setting["kernel"], str): | ||
kernels = "TITLE=" + bootloader_setting["kernel"]["kernel_title"] | ||
else: | ||
for kernel_title in bootloader_setting["kernel"]["kernel_title"]: | ||
kernels.append( | ||
"TITLE=" + bootloader_setting["kernel"]["kernel_title"] | ||
) | ||
elif ( | ||
bootloader_setting["kernel"] == "ALL" | ||
or bootloader_setting["kernel"] == "DEFAULT" | ||
): | ||
kernels = bootloader_setting["kernel"] | ||
else: | ||
module.fail_json( | ||
msg='bootloader_settings.kernel must contain one of kernel_path, kernel_index, kernel_title, "ALL", "DEFAULT"', | ||
**result | ||
) | ||
if not isinstance(kernels, list): | ||
kernels = [kernels] | ||
|
||
for kernel in kernels: | ||
kernel = escapeval(kernel) | ||
# Remove all existing boot settings | ||
if {"previous": "replaced"} in bootloader_setting["options"]: | ||
bootloader_args = get_grubby_args(kernel) | ||
if len(bootloader_args) > 0: | ||
rc, stdout, stderr = module.run_command( | ||
"grubby --update-kernel=" | ||
+ kernel | ||
+ " --remove-args=" | ||
+ escapeval(bootloader_args) | ||
) | ||
# result['remove_args_cmd'] = "grubby --update-kernel=" + kernel + " --remove-args=" + escapeval(bootloader_args) | ||
result["changed"] = True | ||
# Configure boot settings | ||
bootloader_absent_args = "" | ||
bootloader_present_args = "" | ||
bootloader_mod_args = "" | ||
for kernel_setting in bootloader_setting["options"]: | ||
if {"previous": "replaced"} == kernel_setting: | ||
continue | ||
if "value" in kernel_setting: | ||
setting_name = ( | ||
kernel_setting["name"] + "=" + str(kernel_setting["value"]) | ||
) | ||
else: | ||
setting_name = kernel_setting["name"] | ||
if "state" in kernel_setting and kernel_setting["state"] == "absent": | ||
bootloader_absent_args += setting_name + " " | ||
else: | ||
bootloader_present_args += setting_name + " " | ||
if len(bootloader_absent_args) > 0: | ||
bootloader_mod_args = " --remove-args=" + escapeval( | ||
bootloader_absent_args | ||
) | ||
if len(bootloader_present_args) > 0: | ||
bootloader_mod_args += " --args=" + escapeval(bootloader_present_args) | ||
if len(bootloader_mod_args) > 0: | ||
# result['mod_args_command'] = "grubby --update-kernel=" + kernel + bootloader_mod_args | ||
rc, stdout, stderr = module.run_command( | ||
"grubby --update-kernel=" + kernel + bootloader_mod_args | ||
) | ||
result["changed"] = True | ||
|
||
# if the user is working with this module in only check mode we do not | ||
# want to make any changes to the environment, just return the current | ||
# state with no modifications | ||
# if module.check_mode: | ||
# module.exit_json(**result) | ||
|
||
# in the event of a successful module execution, you will want to | ||
# simple AnsibleModule.exit_json(), passing the key/value results | ||
module.exit_json(**result) | ||
|
||
|
||
def main(): | ||
run_module() | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters