To be honest I am not sure I like this additional option to register / set variables. I feel it is closer to an antipattern rather than a pattern. But of course it is not clear at the moment due to missing usage practice.
Let me explain. Let’s consider examples from Register projections and action plugin dynamic host/group/var API by nitzmahone · Pull Request #86241 · ansible/ansible · GitHub.
Registering multiple variables from a task
Before [1]:
- shell: echo hello
failed_when: echo_result.stdout is contains "goodbye"
register: echo_result
- set_fact:
echo_duration: "{{ echo_result.delta }}"
capitalized_result: "{{ echo_result.stdout | capitalize }}"
After [2]:
- shell: echo hello
failed_when: _task.result.stdout is contains "goodbye"
register:
echo_result: _task.result # The old register behavior
echo_duration: _task.result.delta
capitalized_result: _task.result.stdout | capitalize
Putting “pure” functions like “{{ echo_result.stdout | capitalize }}” and actions with side effects like “shell: echo hello” (one might argue about if this particular action has side effects, but this is just an simple example, in a broader case I assume actual action with side effect here) creates a problem for testing. In order to test that there are correct values in echo_duration and capitalized_result one has to run actions, because action and data manipulation are inseparable. Compare that for instance with this already existing approach of defining ansible role variables in vars/main.yml for for the role.
Using vars file [3]
# vars/mail.yml file
echo_duration: _task.result.delta
capitalized_result: _task.result.stdout | capitalize
You do not have to have managed host to event be present - you can load var file, set _task to what ever you want or expect and ensure that echo_duration and capitalized_result are set to expected values. So you can test this data transformation on each and every OS/ platform without even having this platform available. Imagine instead of echo hello there would be cat /etc/os-release and you want to transform data you got from this command to fit your needs. In listing [2] you have to have all the os versions available each and everytime you run tests, in listing [3] you only need data from cat /etc/os-release once so you can reuse it in any number of tests.
Also by registering new variables (like echo_duration and capitalized_result) you are polluting variables in your playbook / role execution - because registered variables are available in the “global” scope. Vars file variables are available only in the role there they are defined.
Similar argument applies to example ** Advanced templating and chaining variable manipulation**. I would like to add here comment to the following
"# Notice that start_hour was just defined and can be used! The order that they’re declared does matter. "
start_hour variable can be defined anywhere - ansible lazily evaluates variables - it can be defined in vars section in playbooks, defaults/main.yml file in the role, in the inventory. Literally in any place where you can define the variable for this code to work. Only caveat is that you need variable to be available in the scope you will be using them and take into account variable precedence (Using variables — Ansible Community Documentation).
Example ** Using failed_when without a register** I like, and not for the reason it is less to type, but because it allows not to pollute “global” variables scope with registers if they are only needed for failed_when, changed_when and similar single task attributes.
There is an interesting suggestion from @felixfontein in regards to ansible variables scope. More ways to set variables for a scope
Maybe some day there will be option to register and load variables only to the certain scope (host, host_group, block, task, role, etc) not to pollute “global” scope.