I would like to have a master playbook, which include's other playbooks. Is it possible to pass a variable to that included playbook?
The normal syntax which is used for passing variables to included tasks doesn't work (see below)
- include: someplaybook.yml variable=value
and
- include: someplaybook.yml
vars:
variable: value
I'm running v2.0.2.0.
The only thing i see missing is quotes.
- include: someplaybook.yml variable='value'
It works for me and should work for you too. If not share the error you face.
Make sure you have this variable "variable" defined in the task of the role as well and from here you are just passing the value to that variable.
Tested on ansible 2.4
- import_playbook: any_playbook.yml variable='value'
Also, I suggest you read this,
http://docs.ansible.com/ansible/latest/playbooks_reuse.html
and try using roles in this case, it'll help in a case like this, where you're trying to include/import multiple playbooks in a single main playbook.
And about passing a value to the include statement you can add it to the vars main.yml of the role.
Or, if the variable you want to pass is the result of a previous task in the single main playbook use 'register' and save the output in a varible.
- debug: msg="{{result.stdout_lines}}"
here, result is the registered variable.
Use the debug module to know exactly what you want to pass to the playbook.
Hope this helps.
In my opinion most consistent way to pass variable to included playbook and to another play in the current playbook as well is using:
set_fact:
global_var_name: "{{ your_var }}"
before
- import_playbook: your_playbook.yml
After you set the fact it's is accessible from any play in the playbook and imported playbooks, for instance inside "your_playbook" you can call it like so:
debug:
var: global_var_name
If you use:
- import_playbook: someplaybook.yml variable='value'
you can only pass fixed 'value'(in include as well) if you try to pass var value:
- import_playbook: someplaybook.yml internal_var="{{ your_var }}"
you will get NOT DEFINED when you call internal_var inside 'someplaybook.yml'
All of this is true for the beginning of 2021, ansible 2.9*, it's quite possible they will 'fix' import_playbook, I would like this, by the way.
Related
What I am trying to achieve is something like following
vars_files:
- "{{ 'vars/vars.yml' if condition==True else 'vars/vars1.yml' }}"
Can someone help me with the correct syntax?
vars_files is a playbook keyword. The conditions can't be applied to keywords. Instead, an option would be using include_vars which is a task. For example
- hosts: all
tasks:
- include_vars: vars/vars1.yml
when: condition|bool
Notes
The directory vars in the path is not necessary. See The magic of ‘local’ paths
See CONDITIONAL_BARE_VARS
Make sure there is no problem with the higher precedence. If there is a problem with the higher precedence of include_vars open a new question with mcve details. There are many options for how to solve it depending on the use-case.
You can do something like this:
vars_files:
- vars/{{ 'vars' if condition==True else 'vars1' }}.yml
my playbook structure looks like:
- hosts: all
name: all
roles:
- roles1
- roles2
In tasks of roles1, I define such a variable
---
# tasks for roles1
- name: Get the zookeeper image tag # rel3.0
run_once: true
shell: echo '{{item.split(":")[-1]}}' # Here can get the string rel3.0 normally
with_items: "{{ret.stdout.split('\n')}}"
when: "'zookeeper' in item"
register: zk_tag
ret.stdout:
Loaded image: test/old/kafka:latest
Loaded image: test/new/mysql:v5.7
Loaded image: test/old/zookeeper:rel3.0
In tasks of roles2, I want to use the zk_tag variable
- name: Test if the variable zk_tag can be used in roles2
debug: var={{ zk_tag.stdout }}
Error :
The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'stdout'
I think I encountered the following 2 problems:
When registering a variable with register, when condition is added, this variable cannot be used in all groups. How to solve this problem? How to make this variable available to all groups?
is my title, How to use variables between different roles in ansible?
You're most likely starting a new playbook for a new host. Meaning all previous collected vars are lost.
What you can do is pass a var to another host with the add_host module.
- name: Pass variable from this play to the other host in the same play
add_host:
name: hostname2
var_in_play_2: "{{ var_in_play_1 }}"
--- EDIT ---
It's a bit unclear. Why do you use the when statement in the first place if you want every host in the play for it to be available?
You might want to use the group_vars/all.yml file to place vars in.
Also, using add_host should be the way to go as how I read it. Can you post your playbook, and the outcome of your playbook on a site, e.g. pastebin?
If there is any chance the var is not defined because of a when condition, you should use a default value to force the var to be defined when using it. While you are at it, use the debug module for your tests rather than echoing something in a shell
- name: Debug my var
debug:
msg: "{{ docker_exists | default(false) }}"
I have the following version installed: ansible 2.3.0 (devel 2131eaba0c)
I want to specify my host variable as external variable and then use it in the playbook similar to this:
hosts: "{{integration}}"
In my group_vars/all file I have the following defined variable:
integration: "int60"
The host file looks like this:
[int60]
hostA
[int61]
hostB
Unfortunately this does not work. I also tried to define the host var in the following way:
[integration]
127.0.0.1 ansible_host="{{ integration_env }}"
and have the integration_env specified in my group_vars/all file. In this case it seemed like it ran the tasks locally and not in the desired environment.
Is it possible to do something like this? I'd be open to whole new ways of doing this. The main goal is simply to define the host variable in a var file.
This will work if you pass integration variable as extra variable:
ansible-playbook -e integration=int60 myplaybook.yml
Any variables used in play "header", should be defined before Ansible parses playbook.
In your example you define integration as host facts. Facts are only defined on task level, not play level.
Update: and you can use other ways of passing variables, not only extra vars.
For example:
- hosts: "{{ lookup('env','DYN_HOSTS') }}"
will also work.
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?
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 !!!
A bit of documentation:
Ansible has 3 main scopes:
Global: this is set by config, environment variables and the command line
Play: each play and contained structures, vars entries, include_vars, role defaults and vars.
Host: variables directly associated to a host, like inventory, facts or registered task outputs
So variables you define for each play don't know about each other.
You have two options:
set required_node_version globally (via -e switch), so it will be defined everywhere
set required_node_version for each individual host (i.e. via ./group_vars/all.yml file), so it will be available in each task as host-bound fact.
I'd like to be able to set configuration variables for my ansible modules as standard host/group vars. How can I access them from within the module?
I'm aware I can pass all the values in the actual call, but that seems really tedious.
--
tasks:
- name: tell everyone
foo_announce: msg="tell everyone" token=x091232 uri=https://api.com
Versus having an appropriate set of default configuration variables and referencing those:
--
tasks:
- name: tell everyone
foo_announce: msg="tell everyone"
easiest to use an include file and reference it - you can specify default variables or just hard-code the defaults that way.
Personally I use variables and pass them as part of the include:
tasks:
- include: include-notification.yaml
vars:
themessage: "Starting on {{ inventory_hostname }}"
As long as your include file uses a variable called 'themessage' in the above example, it should work fine...