Passing bash variable from gitlab-ci file as an extra argument to ansible job

I have a following problem. I want to pass resolved IP addresses to this j2 template file:

COMMIT
# NAT table
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A PREROUTING -p tcp -m tcp --dport 636 -m statistic --mode nth --every 2 --packet 0 -j DNAT --to-destination {{ idm_ips[0] }}
-A PREROUTING -p tcp -m tcp --dport 636 -j DNAT --to-destination {{ idm_ips[1] }}
-A POSTROUTING -o eth0 -j MASQUERADE
COMMIT

So my variables here are idm_ips[0] and idm_ips[1]. They were set statically inside ansible-vars.yaml file:

idm_ips:
  - "192.168.10.25"
  - "192.168.10.42"

Now I have to resolve FQDNs to idm_ips dynamically, so I wrote a simple python script:

#!/usr/bin/env python3

import socket
import json

ldap_dev = 'ldap.organisation.com'
resolved = socket.gethostbyname_ex(ldap_dev)
ips_arr = resolved[2]
idm_ips_json = json.dumps(ips_arr)
print(idm_ips_json)

This array of IPs is in JSON format, because I read on SO that if I want to pass a bash array as an extra argument to ansible job, it has to be JSON. So I did so.

  1. I tried to pass thees values by storing them inside a .gitlab-ci.yml file as a bash variable:
- chmod +x ${CI_PROJECT_DIR}/scripts/resolve_idm_dev.py
- idm_ips=`python3 ${CI_PROJECT_DIR}/scripts/resolve_idm_dev.py`
  1. And finally pass this variable to ansible as an extra argument:
ansible-playbook ${CI_PROJECT_DIR}/ansible/provision.yml --extra-vars "project_path=${CI_PROJECT_DIR} project_environment=${CI_ENVIRONMENT_NAME} '{"idm_ips": ${idm_ips}}'"

And I am struggling with it, because when I am trying to build my environment, I am getting an error:

fatal: [kibana-development]: FAILED! => changed=false 
  msg: 'AnsibleUndefinedVariable: ''idm_ips'' is undefined'

What am I doing wrong? Could some good soul point me what to do? Sorry for a fuzzy description.


Solution 1:

First, tell python to escape [, ] as they have special meaning in SHELL:

>>> print(json.dumps(socket.gethostbyname_ex("stackoverflow.com")[2]).replace("[","\\[").replace("]","\\]")) 
\["151.101.193.69", "151.101.129.69", "151.101.1.69", "151.101.65.69"\]

Second, properly handle the JSON:

ansible-playbook ${CI_PROJECT_DIR}/ansible/provision.yml \
-e "project_path=${CI_PROJECT_DIR} \
-e project_environment=${CI_ENVIRONMENT_NAME} \
-e '{"idm_ips":' "${idm_ips}"'}'

If this does not work, consider outputting idm_ips_json to a file and pass it with:

 ... -e @yourfile. # because working with json in the shell is terrible ..

Note, if you choose to work with your file, the content should be:

 {"idm_ips": ["192.X.Z.Y", "192."...]}