11.4 Jinja2 Filters 🔧

Τι είναι τα Filters;

Τα filters μετασχηματίζουν τιμές μέσα σε expressions. Χρησιμοποιούν το σύμβολο | (pipe):

{{ value | filter }}
{{ value | filter(argument) }}
{{ value | filter1 | filter2 | filter3 }}  ← chaining!

String Filters

{# ── Μετατροπή κειμένου ──────────────────── #}
{{ 'hello world' | upper }}          → HELLO WORLD
{{ 'HELLO WORLD' | lower }}          → hello world
{{ 'hello world' | capitalize }}     → Hello world
{{ 'hello world' | title }}          → Hello World

{# ── Trim & Replace ──────────────────────── #}
{{ '  hello  '  | trim }}            → hello
{{ '  hello  '  | lstrip }}          → hello  (αριστερά)
{{ '  hello  '  | rstrip }}          →   hello (δεξιά)
{{ 'hello world'| replace('world', 'ansible') }}
                                     → hello ansible

{# ── Length & Count ──────────────────────── #}
{{ 'hello' | length }}               → 5
{{ ['a','b','c'] | length }}         → 3

{# ── Truncate ────────────────────────────── #}
{{ 'Hello World' | truncate(5) }}    → Hello...

{# ── String testing ──────────────────────── #}
{{ 'hello' | string }}               → 'hello' (string type)

{# ── Formatting ──────────────────────────── #}
{{ '%s:%d' | format('host', 80) }}   → host:80

{# ── Center/Left/Right align ─────────────── #}
{{ 'hi' | center(10) }}              →     hi
{{ 'hi' | ljust(10)  }}              → hi
{{ 'hi' | rjust(10)  }}              →         hi

List Filters

{# ── Sorting ─────────────────────────────── #}
{{ [3,1,4,1,5] | sort }}             → [1,1,3,4,5]
{{ [3,1,4,1,5] | sort(reverse=true) }}
                                     → [5,4,3,1,1]
{{ ['b','a','c'] | sort }}           → ['a','b','c']

{# ── Unique ──────────────────────────────── #}
{{ [1,2,2,3,3,3] | unique }}         → [1,2,3]
{{ [1,2,2,3,3,3] | unique | list }}  → [1,2,3]

{# ── Min/Max/Sum ─────────────────────────── #}
{{ [3,1,4,1,5] | min }}              → 1
{{ [3,1,4,1,5] | max }}              → 5
{{ [3,1,4,1,5] | sum }}              → 14

{# ── First/Last ──────────────────────────── #}
{{ [1,2,3,4,5] | first }}            → 1
{{ [1,2,3,4,5] | last }}             → 5

{# ── Join ────────────────────────────────── #}
{{ ['a','b','c'] | join(', ') }}     → a, b, c
{{ ['a','b','c'] | join('\n') }}     → a\nb\nc

{# ── Flatten ──────────────────────────────── #}
{{ [[1,2],[3,4]] | flatten }}        → [1,2,3,4]

{# ── Reverse ──────────────────────────────── #}
{{ [1,2,3] | reverse | list }}       → [3,2,1]

{# ── Select/Reject ───────────────────────── #}
{{ [1,2,3,4,5] | select('odd')  | list }}  → [1,3,5]
{{ [1,2,3,4,5] | reject('odd')  | list }}  → [2,4]
{{ [1,2,3,4,5] | select('gt',3) | list }}  → [4,5]

{# ── Map ─────────────────────────────────── #}
{{ ['hello','world'] | map('upper') | list }}
                                     → ['HELLO','WORLD']

{# ── Batch (χωρισμός σε ομάδες) ──────────── #}
{{ [1,2,3,4,5] | batch(2) | list }} → [[1,2],[3,4],[5]]

Math Filters

{# ── Βασικά ──────────────────────────────── #}
{{ 3.7  | round }}               → 4.0
{{ 3.7  | round(0, 'floor') }}   → 3.0
{{ 3.7  | round(0, 'ceil')  }}   → 4.0
{{ 3.14159 | round(2) }}         → 3.14

{# ── Absolute value ──────────────────────── #}
{{ -5   | abs }}                 → 5

{# ── Integer/Float conversion ────────────── #}
{{ '42' | int }}                 → 42
{{ '42' | int(0) }}              → 42 (default=0 αν αποτύχει)
{{ '3.14' | float }}             → 3.14
{{ '3.14' | float(0.0) }}        → 3.14

{# ── Power/Log ───────────────────────────── #}
{{ 2 | pow(10) }}                → 1024.0
{{ 1024 | log(2) }}              → 10.0

Type Conversion Filters

{# ── Type casting ────────────────────────── #}
{{ 'true'  | bool }}             → True
{{ 'false' | bool }}             → False
{{ 1       | bool }}             → True
{{ 0       | bool }}             → False

{{ '42'    | int }}              → 42
{{ '3.14'  | float }}            → 3.14
{{ 42      | string }}           → '42'

{# ── List/Dict conversions ───────────────── #}
{{ 'hello'       | list }}       → ['h','e','l','l','o']
{{ {'a':1,'b':2} | dict2items }} → [{'key':'a','value':1},...]
{{ [{'key':'a','value':1}] | items2dict }}
                                 → {'a': 1}

Dict Filters

{# ── Keys & Values ───────────────────────── #}
{{ {'a':1,'b':2} | dict2items }}
{# → [{'key':'a','value':1},{'key':'b','value':2}] #}

{{ {'a':1,'b':2}.keys()   | list }}  → ['a','b']
{{ {'a':1,'b':2}.values() | list }}  → [1,2]

{# ── Combine (merge dicts) ───────────────── #}
{% set dict1 = {'a': 1, 'b': 2} %}
{% set dict2 = {'b': 3, 'c': 4} %}
{{ dict1 | combine(dict2) }}
{# → {'a':1, 'b':3, 'c':4} (dict2 override) #}

Path Filters

{# ── Path operations ─────────────────────── #}
{{ '/etc/nginx/nginx.conf' | basename }}    → nginx.conf
{{ '/etc/nginx/nginx.conf' | dirname  }}    → /etc/nginx
{{ '/etc/nginx/nginx.conf' | splitext }}    → ['/etc/nginx/nginx', '.conf']

{{ '/etc/nginx' | realpath }}               → /etc/nginx (resolved)
{{ 'relative/path' | expanduser }}          → /home/user/relative/path

Hashing & Crypto Filters

{# ── Hashing ─────────────────────────────── #}
{{ 'hello' | hash('sha1')   }}      → aaf4c61...
{{ 'hello' | hash('sha256') }}      → 2cf24dba...
{{ 'hello' | hash('md5')    }}      → 5d41402a...

{# ── Password hashing (για /etc/shadow) ──── #}
{{ 'MyPassword' | password_hash('sha512') }}
{# → $6$rounds=... (salted hash) #}

{# ── Base64 ──────────────────────────────── #}
{{ 'hello' | b64encode }}           → aGVsbG8=
{{ 'aGVsbG8=' | b64decode }}        → hello

Ansible-specific Filters

{# ── Human readable ──────────────────────── #}
{{ 1073741824 | human_readable }}        → 1.00 GB
{{ ansible_facts['memtotal_mb'] * 1024 * 1024
   | human_readable }}

{# ── Human to bytes ──────────────────────── #}
{{ '1GB' | human_to_bytes }}             → 1073741824

{# ── IP address filters ───────────────────── #}
{{ '192.168.1.10' | ipaddr }}            → 192.168.1.10
{{ '192.168.1.10' | ipaddr('network') }} → 192.168.1.0
{{ '192.168.1.10/24' | ipaddr('prefix') }}→ 24

{# ── Regex ───────────────────────────────── #}
{{ 'Hello World' | regex_replace('World', 'Ansible') }}
                                         → Hello Ansible
{{ 'foo123bar' | regex_findall('[0-9]+') }}
                                         → ['123']
{{ 'hello' | regex_search('e(l+)o', '\\1') }}
                                         → ['ll']

{# ── Random ──────────────────────────────── #}
{{ ['a','b','c'] | random }}             → τυχαίο στοιχείο
{{ 100 | random }}                       → 0-99
{{ range(1,10) | random }}              → 1-9

{# ── Shuffle ──────────────────────────────── #}
{{ ['a','b','c','d'] | shuffle }}        → τυχαία σειρά

{# ── Unique ──────────────────────────────── #}
{{ [1,2,2,3,3] | unique | list }}        → [1,2,3]

{# ── zip ─────────────────────────────────── #}
{{ [1,2,3] | zip(['a','b','c']) | list }}
{# → [[1,'a'],[2,'b'],[3,'c']] #}

Filters σε Templates — Πρακτικά παραδείγματα

{# templates/nginx.conf.j2 #}

{# ── Worker processes — από facts ─────────── #}
worker_processes {{ ansible_facts['processor_vcpus'] | int }};

{# ── Worker connections — υπολογισμός ────── #}
worker_connections {{ (ansible_facts['memtotal_mb'] / 4) | int | min(1024) }};

{# ── Server names — join από λίστα ─────────── #}
server_name {{ server_names | join(' ') }};

{# ── Keepalive — με default ─────────────── #}
keepalive_timeout {{ keepalive | default(65) }};

{# ── Client max body size — human readable ─ #}
client_max_body_size {{ max_upload | default('10M') }};

{# ── Log format — με replace ────────────── #}
access_log /var/log/nginx/{{ app_name | replace('-', '_') }}_access.log;

{# ── SSL protocols — join από λίστα ──────── #}
{% if ssl_enabled %}
ssl_protocols {{ ssl_protocols | default(['TLSv1.2', 'TLSv1.3']) | join(' ') }};
{% endif %}
{# templates/hosts.j2 #}

{# ── Δημιουργία /etc/hosts από inventory ─── #}
127.0.0.1   localhost
::1         localhost

{# Όλοι οι managed servers #}
{% for host in groups['all_managed'] %}
{{ hostvars[host]['ansible_host'] | default(host) }}   {{ host }}
{% endfor %}
{# templates/fail2ban_jail.j2 #}

[DEFAULT]
bantime  = {{ bantime  | default(3600) }}
findtime = {{ findtime | default(600)  }}
maxretry = {{ maxretry | default(5)    }}

{# ── IPs από λίστα ───────────────────────── #}
{% if whitelist_ips is defined and whitelist_ips | length > 0 %}
ignoreip = 127.0.0.1/8 ::1 {{ whitelist_ips | join(' ') }}
{% else %}
ignoreip = 127.0.0.1/8 ::1
{% endif %}

[sshd]
enabled  = true
port     = {{ ssh_port | default(2022) }}
maxretry = {{ ssh_maxretry | default(3) }}

Filter Chaining — Συνδυασμός Filters

{# Πολλαπλά filters σε σειρά #}

{# Πάρε τα CPU cores, διπλασίασέ τα, μέγιστο 16 #}
{{ ansible_facts['processor_vcpus'] | int | multiply(2) | min(16) }}

{# Λίστα → unique → sort → join #}
{{ packages | unique | sort | join(', ') }}

{# String → lower → replace spaces → truncate #}
{{ app_name | lower | replace(' ', '_') | truncate(20, false, '') }}

{# Memory σε GB με 2 δεκαδικά #}
{{ (ansible_facts['memtotal_mb'] / 1024) | round(2) }} GB

{# Hostname → πρώτο γράμμα κεφαλαίο #}
{{ inventory_hostname | split('.') | first | capitalize }}

Σύνοψη 11.4

Jinja2 Filters
├── Σύνταξη: {{ value | filter }}
├── Chaining: {{ value | f1 | f2 | f3 }}
│
├── String:   upper, lower, title, trim, replace,
│             length, truncate, format, center
├── List:     sort, unique, min, max, sum,
│             first, last, join, flatten,
│             select, reject, map, batch
├── Math:     round, abs, int, float, pow, log
├── Type:     bool, int, float, string, list
├── Dict:     dict2items, items2dict, combine
├── Path:     basename, dirname, splitext
├── Crypto:   hash, password_hash, b64encode/decode
└── Ansible:  human_readable, ipaddr,
              regex_replace, random, shuffle,
              unique, zip, human_to_bytes