ansible - change precedence of role variables - ansible

I've created a role to install my apps.
This role needs specific variables defined in separate files in the vars dir of the role, depending of the app (here pdt_type), like that:
- name: Include pkg list of {{ pdt_type }}
include_vars:
file: "{{ pdt_type }}.yml"
It's working fine. But I'd like to be able to overload those variables of my role by the inventory ones. Or vars loaded by include_vars has a greater precedence of the inventory ones.
Do you know how I can do to change this behavior?
How I can defined default variables of a role based on a condition?
Thanks

I think you can't change the variable precedence in ansible and that's good.
A lot of folks may ask about how variables override another. Ultimately it’s Ansible’s philosophy that it’s better you know where to put a variable, and then you have to think about it a lot less. [...] There is only one Empire State Building. One Mona Lisa, etc. Figure out where to define a variable, and don’t make it complicated.
For defining variables on a condition see:
https://serverfault.com/questions/907164/ansible-conditionally-define-variables-in-vars-file-if-a-certain-condition-is-m
Conditionally define variable in Ansible
https://everythingshouldbevirtual.com/automation/ansible-using-set_facts-module/
For including variables conditionally from a file see:
https://docs.ansible.com/ansible/2.7/modules/include_vars_module.html

Related

How to debug ansible variable precedence

I have a complex ansible setup which I want to refactor, with variables defined in various places / at various levels.
I am aware of the basic inheritance rules:
https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#ansible-variable-precedence
I would like to do a verbose debug run, that dumps all the variable key-value pairs to stdout or a file - as they would be effectively applied to my host or environments, but without actually applying any playbooks.
How can I do that with Ansible?
Also, how can I get Ansible to show which yaml files it sources in which order (e.g. what it has found where)

Ansible inventory: aws_ec2 module -- Looking for an example of a working 'groups:' function

I have a dynamic ansible inventory which uses the aws_ec2 module. It works quite well, generally. However, there is one issue. I've tried several times to create groups using the 'groups:' keyword, and all attempts have failed. The documentation is a little sparse -- in fact here it is, in its entirety:
groups: (dictionary)
Default:{}
Add hosts to group based on Jinja2 conditionals.
I've tried a number of syntaxes, Jinja2, conditionals, declarations, and so far none have succeeded in creating a group named 'foo'. For awhile I thought maybe I need to pass a small code snibbet that returns true or false, and thus include or exclude the targeted hosts. This doesn't seem to be the case. I'm wondering if anyone here has used the 'groups:' keyword and gotten further than I have. I found very little while Googling. FWIW, I am using ansible 2.9.9 on Linux.
Some examples of things that don't work:
---
plugin: aws_ec2
### fails to create a group
groups:
foo: >-
tags.get('Name') if tags.get('Name') == 'foo-server'
### returns every host in the AWS account.
groups:
bar:
- "{{ tags.get('Name') == 'bar-server' }}"
Also, it is difficult to use ansible's debugging tools with this module.
Many, like the playbook debugger, seem not to work properly, though I find
them quite useful in other contexts. Any tips you might have for debugging
in this context would be warmly appreciated.
It looks like you were very close
As with many things ansible, the authoritative "documentation" is the source code. Specifically their use of the 'groups' option which calls _add_host_to_composed_groups wherein they feed the groups: dict into a Jinja2 evaluation context containing all the hostvars. The expression is plugged into {% if ... %} so you wouldn't want to include the {{ markers in your expression, just the "raw" jinja2 expression
groups:
foo: tags.get('Name') == 'foo-server'
Be forewarned that I don't have an environment handy to test that inventory script, but that's the theory

Ansible role dependencies - install but don't run (yet) - how?

I want my roles to be reusable and self-contained. To be reusable, each role does a focused piece of work following the "single level of abstraction" paradigm. This leads to many small "atomic" roles, with layers of coordination roles building on them to provide more complex abstractions.
To be self-contained, each role should declare its dependencies on other roles. I don't want such dependencies to be tightly bound to the top-level playbook (e.g. by way of an omnibus playbook/roles/requirements.yml). A role should be fully responsible for managing (declaring) roles it depends upon. This is easily done by way of abc_role/meta/main.yml with suitable entires in the "dependencies" array.
All well and good - except that Ansible Tower not only pulls external dependent roles, e.g. from public or private (custom) repository, IT ALSO RUNS THE ROLE. The "pulling of external roles" happens by Tower in a pre-job that follows all the dependencies recursively and gathers them into the playbook's "roles" directory. This is 100% prior to launching the job template itself. This same declaration of dependencies is also used, by Ansible proper, as a sequence of "pre-tasks" for the role - but without the benefit of any coordination by the using role. This is an unfortunate conflation of the "make available for later use" functionality and the "execute certain tasks first" functionality.
One simple reason for wanting to separate these two functionalities is so that I can have a role available (i.e. it's been installed from wherever) but only execute it conditionally based on dynamic host values. (Even where it's possible to put a role's task flow into "dependencies[]" those items don't seem to honor the "when:" conditional stanza. Thus, conditionals for dependencies are off the table.)
As per https://github.com/ansible/ansible/issues/35905 "Allow role dependencies to not be executed" - this desire of mine has some recognized value. Unfortunately, #35905's commentary / conversation offers no direct solution or mitigation (that I could find).
But I realllly want a solution with the properties that I want. Yes, I want what I want.
So I banged my head bloody, cursed my protoplasmic ancestry, and finally derived log(deps^tags) as a power set of {42} - et voila! (See my selfie answer, below.)
Simply enhance each element of abc_role/meta/main.yml ~ "dependencies:" with "tags: [never]"
This gives me exactly what I want:
roles can declare what sub-roles they depend upon and have them made available (i.e. pulled down from wherever they come from and installed)
yet NOT compel the execution of said sub-roles in declaration sequence as "pre-tasks" of the depending role.
For the "I want to see an actual example" crowd -
===== abc_role/meta/main.yml =====
galaxy_info:
# boring stuff elided...
dependencies:
- src: ssh://git#repos-galore.example.com/projectum/subrollio.git
scm: git
tags: [never] # <<<=== This is the key bit
I have tested this and it works well.
_______________
< AWX 6.1.0.0 >
---------------
\ ^__^
\ (oo)\_______
(__) A )\/\
||----w |
|| ||
Ansible 2.8.2
EDIT: Actually, this doesn't quite work in practice.
It does work as described, but when a parent-role is selected by explicit tag (e.g. from a playbook), then the child-roles listed in the parent's dependencies array are executed, despite having a "tags: [never]" element.
I'm still trying to revive my method, by fiddling with the tags or manipsmating them somehow and will update this posting when I have a definitive answer. In the meantime, I wanted to clarify the (very) serious limits of the solution I found and described - and (hope springs eternal) maybe get a better answer from our community...
RE-EDIT
After re-blooding my head through various bangings on the role dependencies array with a multitude of tag combinations plus reading through some of the Ansible source, I have given up my quest.
Over a year ago, #bcoca (one of the Ansible contributors, I think) said an "install but don't execute" meta keyword would be a good option, but there's been no traction on the feature request since then. Smells like dead fish (meaning: this isn't likely to get done).
So, it's back to the (very annoying) "bloat the playbook's requirements.yml with all its transitively-required roles" approach and then just deal with the code-maintenance craziness that entails. It's a fugly way to do things, but at least it can be made to work.

How to extend ansible playbooks to achieve complex conditions?

I understand that ansible is limited to being a configuration tool i.e., we create configurations in yaml files and python scripts does execution by looking at the configuration.
There are howevever a useful attribute when that will help in deciding which configuration to be done based on the condition mentioned in when and the order of the configurations is also done based on the order of the tasks,
variables and facts are available in achieving dynamic configurations.
However, my requirement involves complex loops and conditions and recursive processing which is either entirely not achievable in playbooks or multiple tasks need to be created with the conditions.
Few issues I find in using ansible playbooks are:
No if else structures
loops has very limited functionality
variable scopes does not work like in scripting languages
And the issue with recursive tasks is like for example:
start_installation.yml does installation of packages defined in a variable
The package has dependencies and the dependencies has dependencies i.e., recursive dependencies and installation should be done on the dependencies first recursively by calling start_installation.yml. However, this is creating problems with the variable scoping i.e., if a package_to_install is 'A' at the time of starting start_installation.yml for A, and if A has dependency 'B', then package_to_install will be set to 'B', at the time of starting start_installation.yml for B. Now, once installation of B is done, it can't do installation of A, as the variable scope is not local to the called function.
My question is mainly if it is a correct approach to use Ansible in doing these tasks or do I need to use a scripting language to do the required checks?
To answer your question:
" ... it is a correct approach to use Ansible in doing these tasks or do I need to use a scripting language to do the required checks?
Correct approach is to use package – Generic OS package manager. If this does not work create a Minimal, Complete, and Verifiable example

Trace/Debug ansible-playbook variable resolution

ansible-playbook has a fairly complex variable precedence hierarchy.
In one case I am having trouble figuring out where a variable value is being resolved from.
I'm expecting it to come from group_vars but it isn't.
Is there a simple way to print where a variable value is coming from?
Hoping For something like:
max_mem: roles/app/defaults/main.yml

Resources