ansible - template json for environmental variable in docker container
I'm trying to assign a one-liner json string to an environmental variable in a docker container. This is what the json look like:
{"ip_access": {"IP_whitelist": {"192.168.99.19/32": "grafana/status (Provider)"}}, "vhosts": {"prometheus1": {"dns_names": ["prometheus1.company.internal"], "add_lines_443": ["include IP_whitelist;", "set $prometheus http://prometheus:9090;", "location / { proxy_pass $prometheus; }"], "options": {"cert_path": "/etc/ssl/certs/prometheus1.crt", "key_path": "/etc/ssl/private/prometheus1.key"}}}}
So instead of ["prometheus1.company.internal"]
I want to have ["{{ inventory_hostname }} .company.internal"]
(and also for the other instances of prometheus1
.
I'm using docker_container as follows:
- name: create nginx reverse proxy container
docker_container:
image: registry.company.com/devops/nginx-reverseproxy:{{ nginx_version }}
name: nginx-reverseproxy
labels:
role=metrics
volumes:
- /etc/ssl/certs/{{ inventory_hostname }}.crt:/etc/ssl/certs/{{ inventory_hostname }}.crt
- /etc/ssl/private/{{ inventory_hostname }}.key:/etc/ssl/private/{{ inventory_hostname }}.key
container_default_behavior: compatibility
networks_cli_compatible: yes
network_mode: default
purge_networks: yes
networks:
- name: metrics-net
- name: proxy-net
env:
STAGING_ENVIRONMENT: 'production'
NGINX_VHOSTS_JSON: '{{ lookup("template", "rproxy/nginx_vhosts_prometheus_develop.j2") }}'
Unfortunately, I keep getting:
TASK [prometheus : create nginx reverse proxy container] **********************************************
fatal: [prometheus_vag]: FAILED! => {"changed": false, "msg": "Non-string value found for env option. Ambiguous env options must be wrapped in quotes to avoid them being interpreted. Key: NGINX_VHOSTS_JSON"}
The weird thing is, if I simply use the template module, it works as expected:
template:
src: rproxy/nginx_vhosts_prometheus_develop.j2
dest: /tmp/tempo.json
when: "prometheus_host in inventory_hostname"
tags:
- copytmp
inventory_hostname
will be replaced by the actual value in the inventory and I get the right thing. Moreover, if I paste this exact result into the playbook as the value of NGINX_VHOSTS_JSON in the yaml playbook, it also works without any issues.
But lookup template seems not to be delivering the expected string.
Any ideas how I can get around the problem?
Solution 1:
Ansible's templating often automatically converts things to a data structure when they look like string representations of a structure.
You can avoid this in this case by explicitly turning it into JSON when you need it:
NGINX_VHOSTS_JSON: '{{ lookup("template", "rproxy/nginx_vhosts_prometheus_develop.j2") | to_json }}'
Personally, I would template it in a more human-friendly representation such as YAML, then convert it to JSON:
test.j2
:
ip_access:
IP_whitelist:
192.168.99.19/32: grafana/status (Provider)
vhosts:
{{ inventory_hostname }}.company.internal:
add_lines_443:
- include IP_whitelist;
- set $prometheus http://prometheus:9090;
- location / { proxy_pass $prometheus; }
dns_names:
- {{ inventory_hostname }}.company.internal
options:
cert_path: /etc/ssl/certs/{{ inventory_hostname }}.company.internal.crt
key_path: /etc/ssl/private/{{ inventory_hostname }}.company.internal.key
test.yml
:
- hosts: localhost
gather_facts: false
tasks:
- debug:
msg: "{{ lookup('template', 'test.j2') | from_yaml | to_json }}"
Result:
ok: [localhost] => {
"msg": "{\"ip_access\": {\"IP_whitelist\": {\"192.168.99.19/32\": \"grafana/status (Provider)\"}}, \"vhosts\": {\"localhost.company.internal\": {\"add_lines_443\": [\"include IP_whitelist;\", \"set $prometheus http://prometheus:9090;\", \"location / { proxy_pass $prometheus; }\"], \"dns_names\": [\"localhost.company.internal\"], \"options\": {\"cert_path\": \"/etc/ssl/certs/localhost.company.internal.crt\", \"key_path\": \"/etc/ssl/private/localhost.company.internal.key\"}}}}"
}