Tariq
Tariq

Reputation: 2569

Pass array in --extra-vars

How can I pass YAML array to --extra-vars in Ansible playbook?

I mean if I have a playbook:

- hosts: "{{ hostName }}"
  remote_user: admin

Then I should call my playbook like

ansible-playbook DeployWar.yml \
  --extra-vars="hostName=tomcat-webApp"

But I want to run this playbook on two servers say tomcat-webApp and tomcat-all, and I want to control it from outside, i.e.: using --extra-vars.

What I have tried to do is:

ansible-playbook DeployWar.yml \
  --extra-vars="hostName=[tomcat-webApp, tomcat-all]"

ansible-playbook DeployWar.yml \
  --extra-vars="hostName={tomcat-webApp, tomcat-all}"

ansible-playbook DeployWar.yml \
  --extra-vars="[{hostName: tomcat-webApp}, {hostName: tomcat-all}]"

But in all cases my playbook fails declaring a syntax error in my call.

Upvotes: 70

Views: 126455

Answers (6)

Oliver Gaida
Oliver Gaida

Reputation: 1930

the only way to pass yaml directly to the extra-vars:

  • use a namedpipe in form of <(command)
  • then take it like a file, so you need the @ sign
  • to take valid yaml, you just use echo "multiline yaml"

all together:

ansible-playbook DeployWar.yml \
  --extra-vars=@<(echo "
hostName:
- tomcat-webApp
- tomcat-all
")

Upvotes: 1

jarv
jarv

Reputation: 5596

To answer your first question, "How can I pass YAML array to --extra-vars in Ansible playbook.": you can pass a JSON formatted string to extra-vars.

Here is an example play:

- hosts: all
  gather_facts: no
  tasks:
    - debug: 
        var: test_list

And how to pass the variable test_list to the command ansible-playbook:

ansible-playbook \
  test.yml \
  --connection local \ 
  --inventory localhost, \ 
  --extra-vars='{"test_list": [1,2,3]}'

Though you can use a variable for hosts I recommend checking out Ansible's mechanism for host management which is inventory in conjunction with the --limit option.

Upvotes: 65

Rifwan Jaleel
Rifwan Jaleel

Reputation: 19

simply you can use jinja j2 template to fulfil the requirement

my j2 template
----------------------------------------------------------------------
[all_hosts]
{% for ip in my_serverlist.split(',') %}
host ansible_host={{ip}} ansible_connection=ssh 

{% endfor %}
-----------------------------------------------------------------------


playbook task
-----------------------------------------------------------------------
- name: Generate and copy inventory file
  template:
    src: inventory.j2
    dest: "ansible/INVENTORY"
    mode: 774
-----------------------------------------------------------------------

command
------------------------------------------------------------------------
ansible-playbook generate-inventory-file.yml --extra-vars 'my_serverlist=1.1.1.1,2.2.2.2,3.3.3.3'
-------------------------------------------------------------------------

Upvotes: 0

Ivan Ogai
Ivan Ogai

Reputation: 1486

As of Ansible 1.3, extra vars can be formatted as YAML, either on the command line or in a file. See the Ansible documentation titled Defining Variables At Runtime.

Example:

--extra-vars "@some_file.yaml"

Upvotes: 13

cyberPrivacy
cyberPrivacy

Reputation: 917

In addition to answer from jarv, here is my savior note:

In case someone wants to pass in an array of integers, this works:

--extra-vars '{"my_params":[40,50,10,20,30]}'

Note: there should be no space in between the numbers in the array you pass! Removing space solved my problem!

Upvotes: 5

Peter Kahn
Peter Kahn

Reputation: 13036

Perhaps, don't try to pass complex types via command line and handle their creation within the playbook from json files or strings.

So, @NelonG's approach works but how will it work in all execution contexts? My playbooks tend to get executed by Jenkins jobs via ansiblePlaybook and via packer. Getting the following to work in all of those (even when the command line looks right) doesn't work and can lead to an escaping nightmare.

ansible -i localhost, all -m debug -a "var=test_list" \
--extra-vars='{"test_list": [1,2,3]}' 

How about passing in as a string and then splitting via set_fact (note: this only works if you have elements without problematic characters. I have URLs so they are reasonably safe

ansible .... -e "test_list_csv=1,2,3,http://foo.bar/file.txt"

In the playbook

name: generate list from string
  set_fact: 
    test_list: "{{ test_list_csv.split(',') | list }}"

I decided to escape from escaping and it seems to work.

Upvotes: 16

Related Questions