I Tried to create a custom module that merge vars:
#!/usr/bin/python
import os
import yaml
from ansible.module_utils.basic import AnsibleModule
DOCUMENTATION = r'''
---
module: load_vars
short_description: This module loads variables from files based on the distribution
description:
- This module loads variables from YAML files based on the distribution, major version, and version number.
- The module will merge the variables from multiple files if they exist.
options:
distribution:
description: The distribution name (e.g., CentOS, Ubuntu).
required: true
type: str
distribution_major_version:
description: The major version of the distribution.
required: true
type: str
distribution_version:
description: The version of the distribution.
required: true
type: str
role_path:
description: The path to the Ansible role.
required: true
type: str
'''
def main():
module = AnsibleModule(
argument_spec=dict(
distribution=dict(type='str', required=True),
distribution_major_version=dict(type='str', required=True),
distribution_version=dict(type='str', required=True),
role_path=dict(type='str', required=True)
),
supports_check_mode=True
)
distribution = module.params['distribution']
major_version = module.params['distribution_major_version']
version = module.params['distribution_version']
role_path = module.params['role_path']
paths = [
os.path.join(role_path, 'vars', f'{distribution}/main.yml'),
os.path.join(role_path, 'vars', f'{distribution}/{major_version}/main.yml'),
os.path.join(role_path, 'vars', f'{distribution}/{major_version}/{version}.yml')
]
merged_vars = {}
for path in paths:
if os.path.exists(path):
with open(path, 'r') as file:
vars_dict = yaml.safe_load(file)
merged_vars.update(vars_dict)
module.exit_json(changed=False, ansible_facts=merged_vars)
if __name__ == '__main__':
main()
Questions:
- is it possible to use facts inside (distribution, major_version, …) ?
- why vars.toto and ansible_facts.toto differs ?
I create a demo role, with roles/demo/tasks/main.yml
that use my library called merge_vars
:
- name: Merge all file vars found
merge_vars:
distribution: "{{ ansible_distribution }}"
distribution_major_version: "{{ ansible_distribution_major_version }}"
distribution_version: "{{ ansible_distribution_version }}"
role_path: "{{ role_path }}"
- name: debug toto vars
debug:
var: vars.toto
- name: debug toto facts
debug:
var: ansible_facts.toto
roles/demo/vars/main.yml
file:
toto: main
roles/demo/vars/Ubuntu/main.yml
file:
toto: ubuntu
playbook.yml
file:
- name: Demo
hosts: all
roles:
- role: demo
$ ansible-playbook -i "localhost," -c local playbook.yml
TASK [demo : debug toto vars] ****************************************************************************************************************************************************************
ok: [localhost] =>
vars.toto: main
TASK [demo : debug toto facts] ***************************************************************************************************************************************************************
ok: [localhost] =>
ansible_facts.toto: ubuntu
ansible_facts
has the good value but not the vars
If I do the same directly with Ansible it works:
- name: Merge all file vars found
ansible.builtin.include_vars: "{{ item }}"
loop:
- "{{ ansible_distribution }}/main.yml"
- "{{ ansible_distribution }}/{{ ansible_distribution_major_version }}/main.yml"
- "{{ ansible_distribution }}/{{ ansible_distribution_major_version }}/{{ ansible_distribution_version }}.yml"
when:
- ([path, item] | path_join) in query("community.general.filetree", path) | selectattr("state", "in", "file") | map(attribute="src") | list
vars:
path: "{{ [role_path, 'vars'] | path_join }}"