Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass through a variable to an included playbook

I am including another playbook from my playbook. I need to pass it a variable, called required_node_version. I am using the same variable in my playbook, so was expecting that the included playbook will inherit it. But it doesn't causing 'undefined' error. So I tried to use this not very elegant solution:

- hosts: localhost
  connection: local
  vars:
    required_node_version: v6.3.1

  ...    

- include: ../../base/ci/build.yml
  vars:
    required_node_version: "{{required_node_version}}"

Which causes {"failed": true, "msg": "ERROR! recursive loop detected in template string: {{required_node_version}}"}.

Any elegant solution for this?

like image 846
warvariuc Avatar asked Mar 10 '23 20:03

warvariuc


1 Answers

Ansible maintains the state of each play separately. Variable scope of one play is also separated from other plays. you may consider variable scope defined in a play as a directed acyclic graph where each node name is unique and values will be overwritten on second write.

When you include some other playbook in a playbook (including the playbook at top level), the included playbook will have its own variable scope because its a completely different play. So you won’t be able to access the variables defined in the main play . The actual error is not recursive loop detected error, the actual error is variable undefined error because you are trying to access a variable that is defined in some other play.

Try this:

main.yml

---
- hosts: all
  vars:
    name: shasha

- include: included_playbook.yml
  vars:
    name1: "{{name}}""

Now you will get the actual error which is : name is undefined, because you are trying to access a variable from different scope(different play) while assigning name to name1.

Now change your main.yml with this:

main.yml

---
- hosts: all
  vars:
    name: shasha

- include: included_playbook.yml
  vars:
    name: shashank

Though the name is defined twice, they are different than each other because the scope for both are different (scope of main play and the scope of included play). So this works fine without any issues.


Some alternate solutions:

1. Pass the variable while invoking the playbook:

Since the playbook you are including can also be run as a main playbook, in that case how would you use that variable ? Either you will define the variable inside that playbook or you will pass it from command line.

When you pass the variable while invoking playbook,it will automatically create that variable in scope of both playbooks (the main playbook as well as the included one):

ansible-playbook -i hosts main.yml -e "required_node_version=v6.3.1"

Or maybe you can create a JSON file which contains all the common variables which are common across all the playbooks you are including and then pass that JSON file while invoking the main ansible playbook.

2. Redesign you Ansible playbooks:

In case the ansible playbook that you are including, works as a helper and not being used in standalone manner, you should then include this playbook at task level. You will still maintain the re-usability and there will be only single scope so you don't need to worry about passing variable explicitly.

A little more about the reason behind recursive loop detected error:

Ansible actually does not use the concept of rvalue when you assign a variable to a variable, It performs the binding between the two instead. For example, What do you think would be the value of variable name1 in the following code:

main.yml

---
- hosts: all
  vars:
   - name: old_val
   - name1: "{{name}}"
   - name: new_val

  tasks:
    - debug: msg="{{name1}}"

If your answer is new_val, you understood the logic. Consider name1 as a reference, which is referring to name and name is now referring to new_val. So the only value present is new_value and name1 and name are just the references referring to new_value. reference to old_value is lost.

Now consider the below script:

main_recursive.yml

---
- hosts: all
  vars:
   - name: shasha
   - name1: "{{name}}"
   - name: "{{name1}}"

  tasks:
    - debug: msg="{{name}}"

Now let's try resoving the value of name. name is pointing to name1 and name1 is pointing to name. That's ok but how are we going to reach the actual value ??? No way, its a recursive loop !!!

like image 90
Shasha99 Avatar answered Apr 29 '23 01:04

Shasha99