This is a first post in the series of posts (I hope) about little project I’ve been working on.
Idea of the project is to demonstrate ansible capabilities. In my experience I see many misunderstandings (from my point of view) what ansible-core is capable of and subsequent misuse of ansible-core functionality. This makes ansible content (here I mean yaml content) much more complex to understand, change and write than it suppose to be.
When I’ve started learning ansible I’ve lerning a lot from the community posts and content, this is my way of giving back to community. And I am looking forward to your feedback (positive or negative).
I would like to introduce capable.core212 collection. I’ve released versions 1.0.0 today.
Let me clarify the naming - namespace = “capable” indicates that ansible is capable of many things, name = “core212” indicates that all plugins and modules (all content) in this collection shoud work with all ansible-core versions starting from 2.12. There will be more (capable.core219 is partly done already, but not yet ready to be published).
For the first content in this collection credit goes to @utoddl and his logical plugin (GitHub - utoddl/logical: A filter for Ansible that adds if / elif / else and logical operators to Ansible data. · GitHub). I’ve changed a syntax a bit, but kept majority of the code and logic.
Ever wondered how to write if, then, else conditon in ansible? Used with_first_found to do that (this is bad practice from my point of view), used other complex setups to do the same thing?
Now you can just write if/then/else in simple yaml.
Here are examples:
---
# Simple if/then/else conditional
- name: simple conditional
vars:
data:
if: true
then: purple
else: green
result: "{{ data | logical }}"
# result == "purple"
# if/then/elseif/else - first matching branch wins
- name: elseif chain
vars:
data:
if: false
then: first
elseif:
- elseif: true
then: second
- elseif: true
then: third
else: last
result: "{{ data | logical }}"
# result == "second"
# Nested conditionals - then/else values can themselves contain conditionals
- name: nested conditionals
vars:
data:
server:
if: true
then:
region:
if: false
then: us-east-1
else: eu-west-1
size: large
else:
region: default
size: small
result: "{{ data | logical }}"
# result == {server: {region: "eu-west-1", size: "large"}}
# Complex then/else values - dicts and lists as results
- name: dict as then value
vars:
data:
if: true
then:
name: server1
port: 8080
tags:
- web
- production
else:
name: fallback
port: 80
result: "{{ data | logical }}"
# result == {name: "server1", port: 8080, tags: ["web", "production"]}
- name: list as then/else value
vars:
data:
if: false
then:
- item1
- item2
else:
- fallback1
- fallback2
- fallback3
result: "{{ data | logical }}"
# result == ["fallback1", "fallback2", "fallback3"]
# Missing else - returns None when condition is false and no else provided
- name: no else clause
vars:
data:
if: false
then: unreachable
result: "{{ data | logical }}"
# result == None
# Mixed static and conditional keys - regular keys pass through unchanged
- name: passthrough with nested conditional
vars:
data:
static_key: static_value
nested:
if: true
then: resolved
result: "{{ data | logical }}"
# result == {static_key: "static_value", nested: "resolved"}
# String booleans from Jinja2 templating
- name: string booleans
vars:
my_flag: true
data:
if: "{{ my_flag }}"
then: resolved true
else: resolved false
result: "{{ data | logical }}"
# result == "resolved true"
# Logical operators standalone
- name: and operator - true if all are true
vars:
data:
and:
- true
- true
- true
result: "{{ data | logical }}"
# result == true
- name: or operator - true if any is true
vars:
data:
or:
- false
- true
- false
result: "{{ data | logical }}"
# result == true
- name: xor operator - true if exactly one is true
vars:
xor_true:
xor:
- false
- true
- false
xor_false_none:
xor:
- false
- false
- false
xor_false_many:
xor:
- true
- true
- false
# xor_true | logical == true (exactly one)
# xor_false_none | logical == false (zero true)
# xor_false_many | logical == false (more than one true)
- name: not operator - flips the boolean value
vars:
data:
not: false
result: "{{ data | logical }}"
# result == true
# Logical operators as conditions in if
- name: and as condition
vars:
data:
if:
and:
- true
- true
then: and passed
else: and failed
result: "{{ data | logical }}"
# result == "and passed"
- name: or as condition
vars:
data:
if:
or:
- false
- true
then: or passed
else: or failed
result: "{{ data | logical }}"
# result == "or passed"
- name: not as condition
vars:
data:
if:
not: false
then: not passed
else: not failed
result: "{{ data | logical }}"
# result == "not passed"
# Nested operators in condition
- name: nested operators
vars:
data:
if:
and:
- not: false
- or:
- false
- true
- xor:
- true
- false
then: all passed
else: something failed
result: "{{ data | logical }}"
# result == "all passed"
What do you want me to release next?
- validate_vars plugin - add vadation rules of any complexity to your ansible roles
- how to write and use python functions in ansible-core 2.19
- include_fact plugin - same as set_fact, but uses files similar to include_vars
- set_vars plugin - same as include_vars, but uses parameters similar to set_fact
- how to create and publish modern documentation website for ansible collection