Ansible version 1.9 introduced the ternary filter. This filter is one of the most useful filters, in my opinion. It can be overused, but typically what ends up happening is instead of using | ternary() a huge amount of logic gets baked into other stuff (with_items, set_fact) instead; so I prefer it.

The filter is tougher to explain than to simply provide examples, so see the following (A snippet from my playbook to manage ec2 instances):

- name: "AWS EC2 INSTANCE(S) | Managing instance(s)" ec2: ... vpc_subnet_id: "{{ (ec2_subnet_type == 'public') | ternary(ec2_vpc_public_subnet_id,ec2_vpc_private_subnet_id) }}" ...

What this is doing is I under defaults/main.yml I set ec2_subnet_type: "private" , so if an instance needs to be deployed in a public subnet in my AWS VPC, I just set the type to public in a variable loaded through vars_files; then the subnet id itself is gathered later on. This allows me to gather all subnets early on in a single task, and then deploy it to the correct subnet in this task.

This is most useful when you find yourself thinking something along the following lines…

“ set_fact and when might work here…”

might work here…” “I’ll just run this module more than once with when “

“ “I could use jinja2 inside this anything…” (Yes, this works, but avoid this at all costs.)

A second example, when LetsEncrypt very first came out, is I needed to setup multiple ‘stubs’ serving port 80 to “bootstrap” new domains in nginx, here’s the snippet that created these stubs:

- name: "NGINX | Setup LetsEncrypt http stubs" template: src: letsencrypt.stub.j2 dest: "/etc/nginx/conf.d/{{ item.name }}.le_stub.conf" with_items: "{{ ('production' not in ansible_fqdn) | ternary(vhosts,nonprod_vhosts) }}" when: "{{ item.letsencrypt }} is defined" tags: letsencrypt

Hopefully these two examples help illustrate some uses of this filter. I find I don’t use it very often, but it’s very much a…

Ah, this is exactly what I was looking for!

Kind of moment!

Update:

Another helpful use of this that I forgot to include here is overloading set_fact, like as follows…

- set_fact: instance_list: "{{ (ec2_instances.tagged_instances is defined) | ternary(ec2_instances.tagged_instances,ec2_instances.instances) }}"

The ec2 module will output “tagged_instances” if you include tags, and ec2_remote_facts outputs “instances,” so you can re-use one role by passing instances explicitly, or passing newly created instances straight to the role, and always get the right list.

Leave a comment if you can provide any other useful examples of this filter.