Ansible Data Structures - The Silent Architect Way

Ansible Data Structures - The Silent Architect Way

The Silent Architect Way

You install Ansible.
You automate the first system.
The gain is visible.
It feels liberating.

Projects. Inventories. Variables. Secrets.

New items pop up.
They're scattered around.
Then they're duplicated in different places.

Confusion.
Errors.
Bug hunts.

Re-architect your growing data - like a Silent Architect.

Variables Haunt You - Everywhere

You start it simple.

Variables thrive in tasks. Roles. Playbooks.
Defaults, vars files. Even in templates.

name: DeadSwitch
slogan: Fear the silence, Fear the Switch.

You just use it.

- name: Using a variable
  ansible.builtin.debug:
    msg: "The variable is: {{ slogan }}."

Then you realize you need structure.
You build lists.

occupations:
  - Ghost Operator
  - Silent Architect
  - Digital Resistance Leader

The occupations variable is a list.
Comfortable.
You don't pick one element. You iterate the structure.

- name: Iterating a list
  ansible.builtin.debug:
    msg: The element is: {{ item }}.
  loop: "{{ occupations }}"

The silent echo comes:

ok: [localhost] => (item=Ghost Operator) => The element is: Ghost Operator
ok: [localhost] => (item=Silent Architect) => The element is: Silent Architect
ok: [localhost] => (item=Digital Resistance Leader) => The element is: Digital Resistance Leader

With dictionaries you identify the values.
They have keys.

user:
  deadswitch:
    name: DeadSwitch
    slogan: Fear the silence, Fear the Switch.
    occupation: Silent Architect

You can pick an element.

- name: Picking a dictionary element
  ansible.builtin.debug:
    msg: "The user's occupation is: {{ user.deadswitch.occupation }}."

Clean and dry.

Then Dark Ghosts possess the structure.
The Architect must tame them.

When The Structure Is Haunted - Embedded Data Structures

The lists were clean.
The dictionaries were sharp.

Then they merge.
They nest.
They twist inside each other.

servers:
  web:
    hosts:
      - web1.ghostnet.local
      - web2.ghostnet.local
    vars:
      role: frontend
      ssl: true
  db:
    hosts:
      - db1.ghostnet.local
    vars:
      role: backend
      replication: enabled

Now the structure is alive.
Keys hold lists. Lists hide keys.
Ghost Operators must know the paths.

- name: Access a nested dictionary
  ansible.builtin.debug:
    msg: "DB role is: {{ servers.db.vars.role }}"
- name: Iterate hosts of the web group
  ansible.builtin.debug:
    msg: "Web host: {{ item }}"
  loop: "{{ servers.web.hosts }}"

Haunted structures demand clarity.
Without discipline, you chase ghosts.

Walk The Path Of The Ghosts - Iterate The Structure

You tamed the Dark Ghosts.
The paths are clear.
Now you want to walk it.
A part of it. Or the entire system.

users:
  - name: ghost1
    role: watcher
  - name: ghost2
    role: operator
  - name: ghost3
    role: architect

Iterating a list of dictionaries:

- name: Walk through each ghost
  ansible.builtin.debug:
    msg: "{{ item.name }} takes the role: {{ item.role }}"
  loop: "{{ users }}"

But sometimes the dictionary itself must be walked:

secrets:
  key1: shadow
  key2: fog
  key3: silence
- name: Dict to items
  ansible.builtin.debug:
    msg: "Key: {{ item.key }} | Value: {{ item.value }}"
  loop: "{{ secrets | dict2items }}"

When the map is too twisted, flatten it.
When the ghosts hide, reveal them.

Exorcism Tools - Filters And Transforms

Walking the paths is not enough.
Sometimes you reshape them.
Bend them.
Burn away the noise.

Filters are the exorcism tools.

users:
  - name: ghost1
    role: watcher
  - name: ghost2
    role: operator
  - name: ghost3
    role: architect

Map reveals only what you need:

- name: Extract only the roles
  ansible.builtin.debug:
    msg: "Role: {{ item }}"
  loop: "{{ users | map(attribute='role') | list }}"

It whispers:

ok: [localhost] => (item=watcher) => Role: watcher
ok: [localhost] => (item=operator) => Role: operator
ok: [localhost] => (item=architect) => Role: architect

Select banishes what does not fit:

- name: Keep only operators
  ansible.builtin.debug:
    msg: "Operator: {{ item.name }}"
  loop: "{{ users | selectattr('role', 'equalto', 'operator') | list }}"

When the maze grows darker, json_query cuts through.
(JMESPath is your blade.)

- name: Using json_query
  ansible.builtin.debug:
    msg: "Architect: {{ users | json_query('[?role==`architect`].name') }}"

The echo is:

ok: [localhost] => Architect: ['ghost3']

Sometimes you want a clean string.

- name: Using json_query
  ansible.builtin.debug:
    msg: "Architect: {{ users | json_query('[?role==`architect`].name') | first }}"

The answer comes in a form of a string:

ok: [localhost] => Architect: ghost3

The Ghost Operator does not drown in data.
He transforms it.
The Architect reshapes the chaos into silence.

Final Whisper

The Operator is you.
You write the data. Architect the structure.
Then you bend it.

Lists grow, Dictionaries bind, Filters cut.