|
|
|
from ansible.module_utils.basic import AnsibleModule
|
|
|
|
import os
|
|
|
|
import re
|
|
|
|
|
|
|
|
|
|
|
|
def parse_mkinitcpio_line(type: str, line: str) -> list[str]:
|
|
|
|
regex = "^" + type + r"=\((.*)\)$"
|
|
|
|
result = re.search(regex, line)
|
|
|
|
if result is None:
|
|
|
|
return None
|
|
|
|
|
|
|
|
return list(filter(lambda v: v != "", result.group(1).split(" ")))
|
|
|
|
|
|
|
|
|
|
|
|
def build_mkinitcpio_line(type: str, values: list[str]) -> str:
|
|
|
|
return type + "=(" + " ".join(values) + ")"
|
|
|
|
|
|
|
|
|
|
|
|
def update_mkinitcpio_line(type: str, desired_state: str, values: list[str], line) -> tuple[str, bool]:
|
|
|
|
current_values = parse_mkinitcpio_line(type, line)
|
|
|
|
changed = False
|
|
|
|
if current_values is not None:
|
|
|
|
if desired_state == "present":
|
|
|
|
for value in values:
|
|
|
|
if value not in current_values:
|
|
|
|
current_values.append(value)
|
|
|
|
changed = True
|
|
|
|
elif desired_state == "absent":
|
|
|
|
for value in values:
|
|
|
|
if value in current_values:
|
|
|
|
current_values.remove(value)
|
|
|
|
changed = True
|
|
|
|
else:
|
|
|
|
raise ValueError("Invalid state: %" % desired_state)
|
|
|
|
|
|
|
|
return build_mkinitcpio_line(type, current_values), changed
|
|
|
|
else:
|
|
|
|
return None, False
|
|
|
|
|
|
|
|
|
|
|
|
def run_module():
|
|
|
|
# define available arguments/parameters a user can pass to the module
|
|
|
|
module_args = dict(
|
|
|
|
state=dict(default='present', choices=['present', 'absent']),
|
|
|
|
binaries=dict(type='list'),
|
|
|
|
files=dict(type='list'),
|
|
|
|
hooks=dict(type='list'),
|
|
|
|
path=dict(type='str', default='/etc/mkinitcpio.conf')
|
|
|
|
)
|
|
|
|
|
|
|
|
# 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
|
|
|
|
)
|
|
|
|
|
|
|
|
# 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)
|
|
|
|
|
|
|
|
path = module.params['path']
|
|
|
|
if not os.path.isfile(path):
|
|
|
|
module.fail_json(msg="The path is invalid: %s does not exist" % path)
|
|
|
|
|
|
|
|
state = module.params['state']
|
|
|
|
binaries = module.params['binaries']
|
|
|
|
files = module.params['files']
|
|
|
|
hooks = module.params['hooks']
|
|
|
|
|
|
|
|
file = open(path, "r")
|
|
|
|
lines = file.readlines()
|
|
|
|
for index, line in enumerate(lines):
|
|
|
|
if binaries is not None:
|
|
|
|
updated_line, updated = update_mkinitcpio_line(
|
|
|
|
"BINARIES", state, binaries, line)
|
|
|
|
if updated:
|
|
|
|
result['changed'] = True
|
|
|
|
if updated_line is not None:
|
|
|
|
lines[index] = updated_line
|
|
|
|
|
|
|
|
if files is not None:
|
|
|
|
updated_line, updated = update_mkinitcpio_line(
|
|
|
|
"FILES", state, files, line)
|
|
|
|
if updated:
|
|
|
|
result['changed'] = True
|
|
|
|
if updated_line is not None:
|
|
|
|
lines[index] = updated_line
|
|
|
|
|
|
|
|
if hooks is not None:
|
|
|
|
updated_line, updated = update_mkinitcpio_line(
|
|
|
|
"HOOKS", state, hooks, line)
|
|
|
|
if updated:
|
|
|
|
result['changed'] = True
|
|
|
|
if updated_line is not None:
|
|
|
|
lines[index] = updated_line
|
|
|
|
|
|
|
|
if result['changed']:
|
|
|
|
file = open(path, "w")
|
|
|
|
file.write("".join(lines))
|
|
|
|
|
|
|
|
# manipulate or modify the state as needed (this is going to be the
|
|
|
|
# part where your module will do what it needs to do)
|
|
|
|
# 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()
|