Ansible: creating docker containers from a variable - ansible

I have a variable structure set up as follows:
container_traefik:
image: 'traefik:latest'
networks:
...
container_oauth:
image: 'thomseddon/traefik-forward-auth:latest'
...
and another variable to define the status of these containers:
enable_traefik: true
enable_oatuh: true
...
My current playbook has a task for each container like this:
docker_container: "{{ container_traefik }}"
when: "enable_traefik | default(False)"
I started looking into running this in a loop, but I have not been able to get it right.
I changed the variable structures to the following:
containers:
traefik:
image: 'traefik:latest'
...
enable:
traefik: true
And tried to create them in a playbook like this:
docker_container: "{{ item.value }}"
when: "{{ enable.{{ item.key }} }}"
loop: "{{ containers }}"
Unfortunately this doesn't work, among the many other combinations I have tried.
How can I get this to work?

Related

Can't extract a nested variable in ansible of a dict based on another variable

I have a variables file like so
apps:
appOne:
slug: none
ports:
- "8999:8999"
kong:
slug: somerepo/ansible.kong.git
ports:
- "8000:8000"
- "8001:8001"
- "8443:8443"
- "8445:8445"
in my vars/apps_config file
I'm trying to figure out the ports based on the {{ app_name }} but can't seem to find a way to drill into the apps object.
So in my yml file I'm executing I have
vars_files:
- "vars/app_config"
vars:
app_name: kong
container_ports: "{{ apps [{{ app_name }}]['ports'] }}"
but ansible doesn't like the nested variable {{ app_name }}. I saw someone mention using vars['somestring'] before but the following doesn't seem to work
vars['apps.{{ app_name }}']
any ideas?
the right syntax is:
container_ports: "{{ apps[app_name]['ports'] }}"
*inside {{}} app_name is seen like a variable
test:
- name: test
hosts: localhost
vars_files:
- "vars/app_config"
vars:
app_name: kong
container_ports: "{{ apps[app_name]['ports'] }}"
tasks:
- debug:
var: container_ports
result:
ok: [localhost] =>
container_ports:
- 8000:8000
- 8001:8001
- 8443:8443
- 8445:8445

Make a line in an Ansible playbook optional

I have built a playbook to build a virtual server in F5. I want to make a line only execute if someone enters the variable. In this case the default_persistence_profile: line has a variable "{{ persistenceProfile }}". Sometimes the developers don't want persistence applied to their app but sometimes they do. I have found when I make the variable optional in the run task and don't select a persistence profile the task errors out. See playbook below:
- name: Build the Virtual Server
bigip_virtual_server:
state: present
partition: Common
name: "{{ vsName }}"
destination: "{{ vsIpAddress }}"
port: "{{ vsPort }}"
pool: "{{ poolName }}"
default_persistence_profile: "{{ persistenceProfile }}"
ip_protocol: tcp
snat: automap
description: "{{ vsDescription }}"
profiles:
- tcp
- http
- name: "{{ clientsslName }}"
context: client-side
- name: default-server-ssl
context: server-side
Ansible has a mechanism for omitting parameters using the default filter, like this:
- name: Build the Virtual Server
bigip_virtual_server:
state: present
partition: Common
name: "{{ vsName }}"
destination: "{{ vsIpAddress }}"
port: "{{ vsPort }}"
pool: "{{ poolName }}"
default_persistence_profile: "{{ persistenceProfile|default(omit) }}"
ip_protocol: tcp
snat: automap
description: "{{ vsDescription }}"
profiles:
- tcp
- http
- name: "{{ clientsslName }}"
context: client-side
- name: default-server-ssl
context: server-side
If persistenceProfile is unset, the default_persistence_profile parameter should not be passed to the bigip_virtual_server module.

How to use list variables defined using Ansible?

I have defined a variable in my defaults as a list:
aws-sec-group-name:
- "es-external"
- "elasticsearch-production"
I am trying to use the above variable in my task playbook as follows:
---
- name: Create EC2 instances
ec2:
keyname: "{{ aws-key-name }}"
#group: "{{ aws-sec-group-name }}"
instance_type: "{{ aws-instance-type }}"
image: "{{ aws-ami }}"
wait: yes
wait_timeout: 500
count: 2
instance_tags:
Name: "{{ aws-tag-name }}"
vpc_subnet_id: "{{ subnet-id }}"
group: ["{{ aws-sec-group-name.[0] }}","{{ aws-sec-group-name.[1] }}"].
Which is not the right way.
Can someone tell me how to use list variable?
And also since the count is 2, I am also interested in knowing if i can add -1- and -2- in the Name tag?
Can someone tell me how to use list variable?
Here you are:
Fix the name of the variable as they cannot contain dashes:
aws_sec_group_name:
- "es-external"
- "elasticsearch-production"
Use the variable:
group: "{{ aws_sec_group_name }}"

Ansible, Boto, AWS - Invalid type for parameter containerDefinitions[0].memory

I have several services running in docker containers on Amazon ECS and am assigning percentages of the total system memory for each service.
In my ansible/roles/ecs_cluster_init/defaults/main.yaml file I have the following entries:
docker_memory_limit_service1: 17
docker_memory_limit_service2: 12
docker_memory_limit_service3: 16
docker_memory_limit_service4: 10
docker_memory_limit_service5: 16
docker_memory_limit_service6: 10
total_system_memory : 2048
Service1 should get 17% of the total system memory while service 4 only gets 10%. This is to easily accommodate changes in instance sizes.
In my ansible/roles/ecs_cluster_init/vars/main.yaml file I have (partial portion):
ecs_task_definitions:
- name: "service1"
elb: "{{ elb_creation_output.results[0].elb.dns_name }}"
image: "{{ service1_docker_image }}"
port: "{{ ports.service1 }}"
memory: "{{ ( total_system_memory * ( docker_memory_limit_service1|int / 100 ))|int|abs }}"
To ensure clarity, the service memory value is turned into a percentage (by dividing by 100) and then determining that portion of the total system memory.
In my ansible/roles/ecs_cluster_init/tasks/main.yaml file I have:
## ECS Task and Service Definitions
- block:
- name: Create ECS Service1 Task Definitions
ecs_taskdefinition:
region: "{{ region }}"
containers:
- name: "{{ item.name }}"
cpu: 0
essential: true
image: "{{ item.image }}"
memory: {{ item.memory|int|abs }}
mountPoints: "{{ item.mounts }}"
environment: "{{ item.env_vars }}"
portMappings: "{{ item.portmap }}"
entryPoint:
- "java"
- "-Xms{{ java_heap_size_initial }}"
- "-Xmx{{ java_heap_size_max }}"
- "-DlogDir=/host"
- "-Dcom.sun.net.ssl.checkRevocation=false"
- "-jar"
- "/app.jar"
logConfiguration:
logDriver: "{{ ecs_task_log_configuration.logDriver }}"
options:
max-size: "{{ ecs_task_log_configuration.options.max_size }}"
max-file: "{{ ecs_task_log_configuration.options.max_file }}"
family: "{{ service_prefix }}-{{ item.name }}-{{ env_name }}"
state: present
increment_revision: true
volumes: "{{ item.volumes }}"
register: service1_task_definition
with_items: "{{ ecs_task_definitions }}"
When I run the playbook for the role I receive the following error:
TASK [ecs_cluster_create : Create ECS Service1 Task Definitions] ****************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: Invalid type for parameter containerDefinitions[0].memory, value: 204, type: <type 'str'>, valid types: <type 'int'>, <type 'long'>
Any idea what I'm doing wrong or where I'm missing specifying the memory value should be an int?
It is a known issue with Ansible/Jinja that you can't preserve int type after templating.
In other words |int is integer inside double braces, but become string when you close braces.
But Ansible preserves complex types like dicts/list after templating, so you may do this trick:
- name: Create ECS Service1 Task Definitions
ecs_taskdefinition:
region: "{{ region }}"
containers: "{{'['+dict(name=item.name, cpu=0, image=item.image, memory=item.memory|int)|to_json+']'}}"
with_items: "{{ ecs_task_definitions }}"
I've shortened the example.
This way we construct a string that is a JSON-list which ansible converts after templating.

Ansible - Use string in a variable lookup

I'm trying to make my playbooks aware of their environment; that being production or stage.
My playbook first pulls the ec2_tag for its environment successfully and set to the variable 'env'. On the ec2 provision task, I would like to use the 'env' variable in the vpc and subnet lookups, so it grabs the correct one based on its environment. Below I tried adding the 'env' variable into the lookups, but I'm getting a full string back instead of it pulling it from my variable file.
Do I need to add some logic checks within the {{}}?
- name: Provision instance
ec2:
key_name: "{{ aws_public_key }}"
instance_type: t2.medium
image: "{{ aws_ubuntu_ami }}"
wait: true
vpc_subnet_id: "{{ env + '_subnet_public1' }}"
group_id: "{{ env + '_app_group' }}"
assign_public_ip: yes
instance_tags:
Name: "{{ sys_name }}"
Environment: "{{ env }}"
region: "{{ aws_region }}"
volumes:
- device_name: /dev/sda1
volume_size: 300
delete_on_termination: true
register: ec2
If you want to do variable interpolation then you'll need to use the hostvars[inventory_hostname]['variable'] syntax.
The FAQs cover this briefly but for your use case you should be able to do something like:
- name: Provision instance
ec2:
key_name: "{{ aws_public_key }}"
instance_type: t2.medium
image: "{{ aws_ubuntu_ami }}"
wait: true
vpc_subnet_id: hostvars[inventory_hostname][env + '_subnet_public1']
group_id: hostvars[inventory_hostname][env + '_app_group']
assign_public_ip: yes
instance_tags:
Name: "{{ sys_name }}"
Environment: "{{ env }}"
region: "{{ aws_region }}"
volumes:
- device_name: /dev/sda1
volume_size: 300
delete_on_termination: true
register: ec2

Resources