5
votes

I'm trying to use ansible for a parameterised docker deployment. I want to be able to specify image, version and various different environment variables via the command line.

Image, Version and so on can be specified directly but the env parameter of the docker module requires a dictionary. Here is a shortened playbook example:

-name: some deployment
docker:
   [..]
   name: myname
   [..]
   env:
      FOO: bar
      ANOTHERFOO: anotherbar

The environment variables are choosen during runtime, so it is not possible to define them directly in the supplied extra vars. The playbook looks like this at the moment:

-name: some deployment
docker:
   [..]
   name: "{{ name }}"
   [..]
   env: "{{ env }}"

Since env is a nested dictionary we need to supply the --extra-vars as nested json. I would expected the following to work:

./ansible-playbook [..] --extra-vars '{"name":"myname", "env":{"FOO":"bar", "ANOTHERFOO":"anotherbar"}}' [..]

After the container is running, the values of env are not there. Supplying the json directly in the playbook for testing purposes works.

I tried the following different json with no working results:

{"name":"myname", "env":{"FOO":"bar", "ANOTHERFOO":"anotherbar"}}

{"name":"myname", "env":[{"FOO":"bar"}, {"ANOTHERFOO":"anotherbar"}]}

How do you supply and use a nested dictionary via command line or is this a limitation of the Jinja2 template engine.

2
Which version of Ansible do you run? This should be possible since Ansible 1.2, according to the docs: --extra-vars '{"pacman":"mrs","ghosts":["inky","pinky","clyde","sue"]}' docs.ansible.com/ansible/…udondan
Ansible 1.9.2 , the difference to the quoted documentation is here I try to use an dictionary/nested json object, not an array. But {{ env[0] }} for testing purposes does also not work...echox
That's very strange. I tested this here and it perfectly works. Though I use the devel branch from github. My task: - debug: msg="{{ env[0].FOO }}". My Call: ansible-playbook -i inventory/test test.yml --extra-vars '{"name":"myname", "env":[{"FOO":"bar"}, {"ANOTHERFOO":"anotherbar"}]}' and the output of the debug task: "msg": "bar".udondan
the point is I need the whole dictionary, but let me test it again with the debug task.echox
Yes, I have access to the whole dict. I just used FOO in the debug to show it not only is text but an accessible object.udondan

2 Answers

3
votes

The right structure to use if you need a dict in your YAML/ansible playbook is a nested json supplied with --extra-vars like in the questions example:

./ansible-playbook [..] --extra-vars '{"name":"myname", "env":{"FOO":"bar", "ANOTHERFOO":"anotherbar"}}' [..]

and

-name: some deployment
docker:
   [..]
   name: "{{ name }}"
   [..]
   env: "{{ env }}"

For testing purposes I did use environment on my system which I shortened to env as an example. The problem is environment is a reserved variable and always gets overridden.

1
votes

Try like the following way :

test.json

{"name":"myname", "env":{"FOO":"bar", "ANOTHERFOO":"anotherbar"}}

test.yml

---
 - hosts: localhost
   connection: local
   gather_facts: false

   tasks:
   - name: Print nested json input
     debug:
        msg: "name : {{ name }} || env.foo : {{ env.FOO }} || env.anotherfoo : {{  env.ANOTHERFOO }}"

Ansible Output

[root@localhost test]$ ansible-playbook test.yml -e "@test.json"
 [WARNING]: Could not match supplied host pattern, ignoring: all

 [WARNING]: provided hosts list is empty, only localhost is available

 [WARNING]: Found variable using reserved name: name


PLAY [localhost] ********************************************************************************************************************

TASK [Print nested json input] ******************************************************************************************************
ok: [localhost] => {
    "msg": "name : myname || env.foo : bar || env.anotherfoo : anotherbar"
}

PLAY RECAP **************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0

[root@localhost test]$