I'd like to pass a variable to an included Ansible playbook as follows:
---
- hosts: localhost
connection: local
vars:
my_group: foo
- include: site.yml hosts={{ my_group }}
Then, in site.yml...
---
- hosts: "{{ hosts }}"
...
Unfortunately, I get an error saying that my_group is undefined in site.yml. Ansible docs do say that:
Note that you cannot do variable substitution when including one playbook inside another.
Is this my case? Is there a way around it?
You can use this syntax, but my_group has to be defined at the global level. Now it's local to the first play - it's even clear from the indentation.
You can confirm this by running your playbook with --extra-vars my_group=foo.
But generally what you seem to want to achieve is done using in-memory inventory files and add_host module. Take this as an example:
- hosts: localhost
gather_facts: no
vars:
target_host: foo
some_other_variable: bar
tasks:
- add_host:
name: "{{ target_host }}"
groups: dynamically_created_hosts
some_other_variable: "{{ some_other_variable }}"
- include: site.yml
with site.yml:
---
- hosts: dynamically_created_hosts
tasks:
- debug:
var: some_other_variable
I added some_other_variable to answer the question from your comment "how do I make a variable globally available from inside a play". It's not global, but it's passed to another play as a "hostvar".
From what I see (and I can't explain why) in Ansible >=2.1.1.0, there must be an inventory file specified for the dynamic in-memory inventory to work. In older versions it worked with Ansible executed ad hoc, without an inventory file, but now you must run ansible-playbook with -i inventory_file or have an inventory file defined through ansible.cfg.
Related
I want to parameterize (use a variable) for remote_user in ansible.
This is the first part from the playbook:
- hosts: xxx
remote_user: "centos"
become: true
I will replace it with
- hosts: wazuh
remote_user: "{{ new_user }}"
become: true
But what is a good place to store the value of this variable? It seems group_vars/all mostly contain variables which are more app/env specific than ansible specific. Or should I put it in inventories/hosts as a var? What is the recommended location to store it?
You should actually store it in your inventory as ansible_user either for the all group (for all host), a specific group or a specific host. You can keep a remote_user in your play which will be used in case the ansible_user is not defined for some hosts in your inventory. If you remove it, you local user on the controller will be the default, unless you use the -u flag on the command line.
You can find a good explanation of the difference between ansible_user and remote_user and how the overide works in the documentation on variable precedence
Using a var as you wrote it in your above example can actually work. But since it must be expanded before the play actually starts and any action is taken on any host, the only place you can "store" it is in an extra_var on the command line.
To be a little more practical, here is what I suggest from your above example:
inventories/dev/hosts.yml
---
wazuh:
hosts:
host_a.wazuh.tld:
host.b.wazuh.tld:
inventories/dev/group_vars/wazuh.yml
---
# Vars for the wazuh group
ansible_user: centos
plabook.yml
---
- hosts: wazuh
tasks:
- name: Proove we connected with the given user
cmd: whoami
register: whoami_result
- name: Show actual result
debug:
var: whoami_result.stdout
Launching the playbook:
ansible-playbook -i inventories/dev playbook.yml
If my ansible_user and ansible_ssh_pass is defined in an inventory, could I override that ansible_user when running a specific play?
I want to be able to keep one inventory but there is a specific play that I want to access as a different ssh user.
You can override ansible_ssh_user at the play level by passing in a vars: section to the relevant play.
---
- hosts: localhost
tasks:
- debug:
var: ansible_ssh_user
- hosts: localhost
vars:
ansible_ssh_user: my_user_123
tasks:
- debug:
var: ansible_ssh_user
This playbook has 2 plays. In the second play, I am overriding the ansible_ssh_user variable.
How can I declare global variable within Ansible playbook. I have searched in google and found the below solution, but its not working as expected.
- hosts: all
vars:
prod-servers:
- x.x.x.x
- x.x.x.x
- hosts: "{{prod-servers}}"
tasks:
- name: ping
action: ping
When I'm trying the above code, it says variable prod-servers is undefined.
You cannot define a variable accessible on a playbook level (global variable) from within a play.
Variable Scopes
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 (vars; vars_files; vars_prompt), role defaults and vars.
Host: variables directly associated to a host, like inventory, include_vars, facts or registered task outputs
Anything you declare inside a play can thus only be either a play variable, or a (host) fact.
To define a variable, which you can use in the hosts declaration:
run ansible-playbook with --extra-vars option and pass the value in the argument;
or to achieve the same functionality (decide which hosts to run a play on, from within a preceding play):
define an in-memory inventory and run the subsequent play against that inventory.
what you seem to want is an inventory (http://docs.ansible.com/ansible/latest/intro_inventory.html), it looks like you have an static list of IP's that may be prod servers (or dev, or whatever), therefore you can create an static inventory.
In your second play you want to use the list of IP's as hosts to run the tasks, that's not what Ansible expects. After the "hosts" keyword in a play declaration, Ansible expects a group name from the inventory.
If, on the opossite, your prod servers change from time to time, you may need to create a dynamic inventory. You can have a look at examples in https://github.com/ansible/ansible/tree/devel/contrib/inventory (for instance, there are examples of dynamic inventory based on EC2 from Amazon or vsphere)
regards
well, this can be done using
set_fact.
I don't know the best practice for this but this works for me
Here's my playbook example
- hosts: all
gather_facts: false
tasks:
- set_fact: host='hostname'
- hosts: host-name1
gather_facts: false
tasks:
- name: CheckHostName
shell: "{{ host }}"
register: output
- debug: msg="{{ output }}"
- hosts: host-name2
gather_facts: false
tasks:
- name: CheckHostName
shell: "{{ host }}"
register: output
- debug: msg="{{ output }}"
The following is a simple playbook which tries to dynamically load variables:
site.yml
---
- hosts: localhost
vars_files:
- "{{ name }}.yml"
tasks:
- debug: var={{ foo }}
Variable foo is defined in this file:
vars/myvars.yml
---
foo: "Hello"
Then playbook is run like this:
ansible-playbook test.yml -e "name=myvars"
However this results in this error:
ERROR! vars file {{ name }}.yml was not found
From what I understood from several code snippets this should be possible and import the variables from myvars.yml. When trying with ansible 1.7.x it indeed seemed to work (although I hit a different issue the file name vas resolved correctly).
Was this behaviour changed (perhaps support for dynamic variable files was removed?). Is there a different way to achieve this behaviour (I can use include_vars tasks, however it is not quite suitable)?
EDIT: To make sure my playbook structure is correct, here is a github repository: https://github.com/jcechace/ansible_sinppets/tree/master/dynamic_vars
Just change your site.yml like this:
- hosts: localhost
vars_files:
- "vars/{{ name }}.yml"
tasks:
- debug: var={{ foo }}
Then run the command like this:
ansible-playbook site.yml -e "name=myvars" -c local
Hope this will help you.
Helllo, what is the best way to make an included playbook run on the same hosts as the playbook that called him?
I've tried declaring a variable in the parent playbook with the host name and then passing it to the included playbook, but I get an error telling me that the variable is undefined.
Below is my playbook:
---
# Main staging configuration playbook
- vars:
host_name: "stage_ansible"
hosts: "{{ host_name }}"
remote_user: ubuntu
tasks:
- name: test connection
ping:
remote_user: ubuntu
- include: NginxDefinitions.yml
vars:
service_name: "interaction.qmerce.com"
env_name: "stage4"
host_name_pass: "{{ host_name }}"
...
and the error I'm receiving:
`ERROR! 'host_name' is undefined
If you want to define the hosts runtime and avoid hard coding them on the playbook, you can pass the hosts as extra variables on the command line.
To do so, remove vars definition from your first play and add the following to the ansible-playbook command line:
--extra-vars host_name=localhost
or when you have multiple hosts:
--extra-vars '{"host_name":["host1","host2","host3"]}'