Golang template in Ansible - docker

I'm passing as log_options the following dict in the Ansible package docker_container:
log_options:
tag: "{% raw %}{{.ImageName}}/{{.Name}}/{{.ID}}{% endraw %}"
I've already tried with the above trick but it doesn't work the tag is not created in the container. Any idea?

You should escape every double curly brackets separately, not whole expression:
tag: "{{ '{{' }}.ImageName{{ '}}' }}/{{ '{{' }}.Name{{ '}}' }}/{{ '{{' }}.ID{{ '}}' }}"

Related

Helm resolve .Release.Namespace that was passed into template file

I'm trying to set a var in my values.yaml that by default is set to {{ .Release.Namespace }}. But when I check the end result using --dry-run the value is "{{ .Release.Namespace }}", and not the actual namespace.
If I set ticker.secretNamespace to a string i.e. "foo", it works. How to get this working...
Thanks!
values.yaml
ticker:
secretNamespace: "{{ .Release.Namespace }}"
/tempaltes/prep.yaml
...
containers:
- name: prep
command:
- /bin/bash
- -exuc
- |
DEBUG A: {{ $.Release.Namespace }}
{{- $namespace := $.Release.Namespace }}
DEBUG B: {{ $namespace }}
{{- with .Values.ticker }}
{{- if not (eq .secretNamespace $namespace) }}
DEBUG C: {{ .secretNamespace }}
kubectl --namespace "{{ .secretNamespace }}" create secret ..."
{{- end }}
{{- end }}
...
dry-run result
containers:
- name: prep
command:
- /bin/bash
- -exuc
- |
DEBUG A: test-ns
DEBUG B: test-ns
DEBUG C: {{ .Release.Namespace }}
kubectl --namespace "{{ .Release.Namespace }}" create secret ...
Tried some different notation inside the values.yaml, but no luck.
secretNamespace: {{ .Release.Namespace }}
secretNamespace: {{ $.Release.Namespace }}
secretNamespace: .Release.Namespace
secretNamespace: "{{ .Release.Namespace | quote }}"
secretNamespace: "{{ .Release.Namespace | tpl }}"

How to escape JSON in Ansible playbook

I have the following YAML Ansible playbook file which I intent do use to capture some information from my docker containers:
---
# Syntax check: /usr/bin/ansible-playbook --syntax-check --inventory data/config/host_inventory.yaml data/config/ansible/docker_containers.yaml
- hosts: hosts
gather_facts: no
tasks:
- name: Docker ps output - identify running containers
shell: "/usr/bin/docker ps --format '{\"ID\":\"{{ .ID }}\", \"Image\": \"{{ .Image }}\", \"Names\":\"{{ .Names }}\"}'"
register: docker_ps_output
- name: Show content of docker_ps_output
debug:
msg: docker_ps_output.stdout_lines
But escaping is not working, Ansible gives me the middle finger when I try to run the playbook:
PLAY [hosts] ***********************************************************************************************************************************************************
TASK [Docker ps output - identify running containers] **********************************************************************************************************************************************
fatal: [myhost.com]: FAILED! => {"msg": "template error while templating string: unexpected '.'. String: /usr/bin/docker ps --format ''{\"ID\":\"{{ .ID }}\", \"Image\": \"{{ .Image }}\", \"Names\":\"{{ .Names }}\"}''"}
to retry, use: --limit #/tmp/docker_containers.retry
PLAY RECAP *****************************************************************************************************************************************************************************************
myhost.com : ok=0 changed=0 unreachable=0 failed=1
The original command I'm trying to run:
/usr/bin/docker ps --format '{"ID":"{{ .ID }}", "Image": "{{ .Image }}", "Names":"{{ .Names }}"}'
I would suggest to use a block scalar. Your problem is that {{ .ID }} etc is processed by Ansible's Jinja templating engine when it should not. Probably the most readable way around this is:
---
# Syntax check: /usr/bin/ansible-playbook --syntax-check --inventory data/config/host_inventory.yaml data/config/ansible/docker_containers.yaml
- hosts: hosts
gather_facts: no
tasks:
- name: Docker ps output - identify running containers
shell: !unsafe >-
/usr/bin/docker ps --format
'{"ID":"{{ .ID }}", "Image": "{{ .Image }}", "Names":"{{ .Names }}"}'
register: docker_ps_output
- name: Show content of docker_ps_output
debug:
msg: docker_ps_output.stdout_lines
>- starts a folded block scalar, in which you do not need to escape anything and newlines are folded into spaces. The tag !unsafe prevents the value to be processed with Jinja.
If you want to avoid templating, you need to cover double-brackets by another double-brackets:
{{ thmthng }}
should look like:
{{ '{{' }} thmthng {{ '}}' }}
Your playbook:
---
- hosts: hosts
gather_facts: no
tasks:
- name: Docker ps output - identify running containers
shell: "docker ps -a --format '{\"ID\": \"{{ '{{' }} .ID {{ '}}' }}\", \"Image\": \"{{ '{{' }} .Image {{ '}}' }}\", \"Names\" : \"{{ '{{' }} .Names {{ '}}' }}}\"'"
register: docker_ps_output
- name: Show content of docker_ps_output
debug:
var: docker_ps_output.stdout_lines

Restart multiple Docker containers using Ansible

how do i dynamically restart all my docker containers from Ansible? I mean i know a way where i can define my containers in a variable and loop through them but what i want to achieve is this -
Fetch the currently running containers and restart all or some of them one by one through some loop.
How to achieve this using Ansible?
Docker explanation
Retrieve name/image for all the running container:
docker container ls -a --format '{{.Names}} {{.Image}}'
You could also filter the output of the docket container command to a specific image name, thanks to the --filter ancestor=image_name option:
docker container ls -a --filter ancestor=alpine --format '{{.Names}} {{.Image}}'
Ansible integration:
First I would define some filters as Ansible variables:
vars:
- image_v1: '--filter ancestor=my_image:v1'
- image_v2: '--filter ancestor=my_image:v2'
Them I will execute the docker container command in a dedicated task and save the command output to an Ansible variable:
- name: Get images name
command: docker container ls -a {{ image_v1 }} {{ image_v2 }} --format "{{ '{{' }}.Names {{ '}}' }} {{ '{{' }}.Image {{ '}}' }}"
register: docker_images
Finally I will iterate over it and use it into the docker_container ansible module:
- name: Restart images
docker_container:
name: "{{ item.split(' ')[0]}}"
image: "{{ item.split(' ')[1]}}"
state: started
restart: yes
loop: "{{ docker_images.stdout_lines}}"
final playbook.yml
---
- hosts: localhost
gather_facts: no
vars:
- image_v1: '--filter ancestor=my_image:v1'
- image_v2: '--filter ancestor=my_image:v2'
tasks:
- name: Get images name
command: docker container ls -a {{ image_v1 }} {{ image_v2 }} --format "{{ '{{' }}.Names {{ '}}' }} {{ '{{' }}.Image {{ '}}' }}"
register: docker_images
- name: Restart images
docker_container:
name: "{{ item.split(' ')[0]}}"
image: "{{ item.split(' ')[1]}}"
state: started
restart: yes
loop: "{{ docker_images.stdout_lines}}"

docker_container: How to add multiple Volumes

I am trying to execute with Ansible the following Docker command:
docker run --name soadb_test1 --network=soa_net --ip 172.16.1.10 -d -v $TEST1/SOADB-Volume/u01:/u01/ -v $TEST1/SOADB-Volume/u02:/u02/ -v $TEST1/SOADB-Volume/u03:/u03/ -v $TEST1/SOADB-Volume/u04:/u04/ -v $TEST1/SOADB-Volume/ORCL:/ORCL/ --env-file $ENV_HOME/db.env.list database/enterprise:12.2.0.1
This is my Ansible Script:
---
- name: Create DB container
docker_container:
name: "{{ name }}"
image: "{{ image }}"
env_file: "{{ env_file }}"
detach: yes
volumes:
- "{{ src_vol }}:{{ dest_vol }}"
- "{{ src_vol_2 }}:{{ dest_vol_2 }}"
- "{{ src_vol_3 }}:{{ dest_vol_3 }}"
- "{{ src_vol_4 }}:{{ dest_vol_4 }}"
- "{{ src_vol_5 }}:{{ dest_vol_5 }}"
networks:
- name: soa_net
ipv4_address: "{{ ip }}"
vars_files:
- vars.yml
When I run it I get the following error:
TASK [install_docker_DB : Create DB container] *******************************************************************************************************************************************************************
fatal: [soa_poc]: FAILED! => {"changed": false, "msg": "Unsupported parameters for (docker_container) module: vars_files Supported parameters include: api_version, auto_remove, blkio_weight, cacert_path, cap_drop, capabilities, cert_path, cleanup, command, cpu_period, cpu_quota, cpu_shares, cpuset_cpus, cpuset_mems, debug, detach, devices, dns_opts, dns_search_domains, dns_servers, docker_host, domainname, entrypoint, env, env_file, etc_hosts, exposed_ports, force_kill, groups, hostname, ignore_image, image, init, interactive, ipc_mode, keep_volumes, kernel_memory, key_path, kill_signal, labels, links, log_driver, log_options, mac_address, memory, memory_reservation, memory_swap, memory_swappiness, name, network_mode, networks, oom_killer, oom_score_adj, output_logs, paused, pid_mode, privileged, published_ports, pull, purge_networks, read_only, recreate, restart, restart_policy, restart_retries, security_opts, shm_size, ssl_version, state, stop_signal, stop_timeout, sysctls, timeout, tls, tls_hostname, tls_verify, tmpfs, trust_image_content, tty, ulimits, user, userns_mode, uts, volume_driver, volumes, volumes_from, working_dir"}
Am i declaring the volumes the wrong way?
It looks like your indentation level for the vars_files entry is wrong - please move it to somewhere else:
---
- name: Create DB container
docker_container:
name: "{{ name }}"
image: "{{ image }}"
env_file: "{{ env_file }}"
detach: yes
volumes:
- "{{ src_vol }}:{{ dest_vol }}"
- "{{ src_vol_2 }}:{{ dest_vol_2 }}"
- "{{ src_vol_3 }}:{{ dest_vol_3 }}"
- "{{ src_vol_4 }}:{{ dest_vol_4 }}"
- "{{ src_vol_5 }}:{{ dest_vol_5 }}"
networks:
- name: soa_net
ipv4_address: "{{ ip }}"
The indentation for the first network entry was also wrong.
Depending on whether the above is from a playbook file, or from a role, the location of vars_files might differ. If this is a playbook, then vars_files should be at the same indentation level as tasks:
---
- hosts: all
vars_files:
- vars.yml
tasks:
- name: Create DB container
docker_container: ...
This has nothing to do with the volumes...

Ansible docker_container etc_hosts with variable key

I've an ansible script through which I spawn a docker container and add few hosts entries to it, since etc_hosts takes key as host name and corresponding IP address. In my case I need to have both host name and IP address to be driven by some variable, for instance
docker_container:
name: image-name
image: image-to-be-pulled
state: started
restart_policy: always
etc_hosts:
"{{ domain_1 }}": "{{ domain_1_ip }}"
domain_2 : "{{ domain_2_ip }}"
domain_3 : "{{ domain_3_ip }}"
When I make above configuration then it makes an entry to host file as
xx.xx.xx.xxx {{ domain_1 }}
Ideally the the host file should contain host name against the IP, can someone suggest how can i achieve this. Thanks in advance
Try this syntax:
docker_container:
name: image-name
image: image-to-be-pulled
state: started
restart_policy: always
etc_hosts: >
{
"{{ domain_1 }}": "{{ domain_1_ip }}",
"domain_2" : "{{ domain_2_ip }}",
"domain_3" : "{{ domain_3_ip }}"
}
This will form dict-like string that ansible's templator will evaluate into dict.
Pay attention, that every item should be quoted and pairs are separated by commas.
I had success with...
in my play(book):
- vars:
my_etc_hosts:
{
"host1.example.com host1": 10.3.1.5,
"host2.example.com host2": 10.3.1.3
}
(no ">" character, compared to the accepted answer)
Separated from the playbook, the role with...
in the task:
- name: have the container created
docker_container:
etc_hosts: "{{ my_etc_hosts | default({}) }}"
in defaults/main.yml:
my_etc_hosts: {}
Additionally (not needed by the task above, but part of another template task):
in a template, with jinja2:
{% for host in my_etc_hosts | default([]) %}
--add-host "{{ host }}":{{ my_etc_hosts[host] }} \
{% endfor %}
(As a plus, you see how two hostnames for one IP address can be handled: "fqdn alias1". If you instead split them into two values, they will form two lines in /etc/hosts with the same IP, which is not correct according to the man page.)

Resources