I want to create a more generic Ansible role where you could refine a prefix for all variables you might want to access (just so you won't have to overwrite variables). For this, I had the following scenario:
- define the prefix as an ansible variable (e.g.
my_role
), - define a bunch of other ansible variables having the same prefix (e.g.
my_role_message
) and - Use
my_role_message
in the role itself programmatically.
How?
I found that you can use lookup('vars')
to get your name programmarically like so:
# tasks for my generic_role
- name: Display message based on prefix variable
ansible.builtin.debug:
msg: "Text is: [{{ lookup('vars', my_role ~ '_message') }}]"
This is a simple task which displays the content in a dynamic variable. if my_role
is for example "app", then the role would expect to find a variable named app_message
and will display its content.
Results
This allows me to define a set of variables:
---
# localhost.yml
super_app_text: "Super App message"
buggy_app_text: "I don't have bugs!"
... and use the role in an ansible playbook like so:
---
- name: Use generic_role with super_app
hosts: localhost
vars:
my_role: "super_app"
roles:
- role: generic_role
- name: Use generic_role with buggy_app
hosts: localhost
vars:
my_role: "buggy_app"
roles:
- role: generic_role
The result should be something along the lines:
PLAY [Converge] ***********************************************************
TASK [Include laurivan.generic_test] **************************************
TASK [laurivan.generic_test : Display message based on prefix variable] ***
ok: [localhost] => {
"msg": "Default text for generic_test role"
}
TASK [Include laurivan.generic_test] **************************************
TASK [laurivan.generic_test : Display message based on prefix variable] ***
ok: [localhost] => {
"msg": "Super App message"
}
TASK [Include laurivan.generic_test] **************************************
TASK [laurivan.generic_test : Display message based on prefix variable] ***
ok: [localhost] => {
"msg": "I don't have bugs!"
}
PLAY RECAP ****************************************************************
localhost: ok=3 ...
Conclusion
With the above, you can dynamically change the behaviour of a role and make it 'portable' across different instantiations, but this also has some disadvantages:
- This is another abstraction layer
- You have to cater for all different use cases
- Testing is more difficult (multiple use cases)
- If you have optional steps (e.g. use templates if defined), the role implementation becomes quite complex
With such a generic approachm you practically move behaviour from role description to role configuration.
In the end, you'll have to decide if it's worth writing a generic role or just use dedicated ones, which would be much clearer.
You can find a sample code here. Please look into the molecule's converge.yml to see a bit more details
HTH,
Member discussion: