13.4 set_fact & Cached Facts 🔄

set_fact — Runtime μεταβλητές

Το set_fact σου επιτρέπει να ορίσεις νέα facts κατά την εκτέλεση του playbook — δυναμικά, βάσει άλλων facts ή υπολογισμών.

# Βασική χρήση
- name: Ορισμός fact
  ansible.builtin.set_fact:
    my_fact: "my_value"

# Χρήση αργότερα
- name: Χρήση fact
  ansible.builtin.debug:
    msg: "{{ my_fact }}"

set_fact — Απλά παραδείγματα

tasks:

  # ── Απλοί ορισμοί ─────────────────────────
  - name: Ορισμός απλών facts
    ansible.builtin.set_fact:
      app_version:   "2.1.4"
      deploy_date:   "{{ ansible_facts['date_time']['date'] }}"
      is_production: "{{ app_env == 'production' }}"

  # ── Υπολογισμοί βάσει built-in facts ──────
  - name: Υπολογισμός performance facts
    ansible.builtin.set_fact:
      nginx_workers:    "{{ ansible_facts['processor_vcpus'] | int }}"
      php_memory_limit: "{{ (ansible_facts['memtotal_mb'] * 0.25) | int }}M"
      db_connections:   "{{ (ansible_facts['memtotal_mb'] / 10) | int | min(200) }}"
      ram_gb:           "{{ (ansible_facts['memtotal_mb'] / 1024) | round(1) }}"

  # ── Conditional facts ─────────────────────
  - name: Ορισμός service name βάσει OS
    ansible.builtin.set_fact:
      web_service: >-
        {{ 'apache2'
           if ansible_facts['os_family'] == 'Debian'
           else 'httpd' }}

  # ── Facts από register ────────────────────
  - name: Έλεγχος nginx version
    ansible.builtin.command:
      cmd: nginx -v
    register:     nginx_output
    changed_when: false
    ignore_errors: true

  - name: Αποθήκευση nginx version
    ansible.builtin.set_fact:
      nginx_version: >-
        {{ nginx_output.stderr
           | regex_search('nginx/([0-9.]+)', '\\1')
           | first
           | default('not_installed') }}

  - name: Εμφάνιση version
    ansible.builtin.debug:
      msg: "Nginx: {{ nginx_version }}"

set_fact με cacheable

Κανονικά τα set_fact facts χάνονται όταν τελειώσει το play. Με cacheable: true αποθηκεύονται για επόμενες εκτελέσεις:

tasks:

  - name: Cacheable fact
    ansible.builtin.set_fact:
      app_version:   "2.1.4"
      deploy_commit: "abc123def"
    cacheable: true    # ← αποθηκεύεται στο cache!

Facts Caching — Αποθήκευση Facts

Η Ansible μπορεί να αποθηκεύει facts για να τα χρησιμοποιεί αργότερα χωρίς να τρέχει ξανά το setup module:

# ansible.cfg — ρύθμιση caching
[defaults]
# ── Ενεργοποίηση cache ────────────────────────
fact_caching             = jsonfile   # backend
fact_caching_connection  = /tmp/ansible_facts_cache
fact_caching_timeout     = 3600       # seconds (1 ώρα)

Διαθέσιμα Cache Backends:

┌─────────────────────────────────────────────────────────┐
│  memory     → default, χάνεται μετά την εκτέλεση        │
│  jsonfile   → αρχεία JSON στο δίσκο ✅                  │
│  yaml       → αρχεία YAML στο δίσκο                     │
│  redis      → Redis server (για production)             │
│  memcached  → Memcached server                          │
└─────────────────────────────────────────────────────────┘

jsonfile Cache — Πρακτικό παράδειγμα

# Ρύθμιση cache directory
mkdir -p /tmp/ansible_facts_cache
chmod 700 /tmp/ansible_facts_cache
# ansible.cfg
[defaults]
fact_caching             = jsonfile
fact_caching_connection  = /tmp/ansible_facts_cache
fact_caching_timeout     = 86400    # 24 ώρες
# 1η εκτέλεση — συλλέγει και αποθηκεύει facts
ansible-playbook playbooks/myplaybook.yml
# TASK [Gathering Facts] → ~2 δευτερόλεπτα

# Δες τα cached facts
ls /tmp/ansible_facts_cache/
# nextcloud   ← αρχείο με facts του server

cat /tmp/ansible_facts_cache/nextcloud | python3 -m json.tool | head -20
# {
#   "ansible_architecture": "x86_64",
#   "ansible_distribution": "Debian",
#   ...
# }

# 2η εκτέλεση — χρησιμοποιεί cache!
ansible-playbook playbooks/myplaybook.yml
# TASK [Gathering Facts] → <0.1 δευτερόλεπτα ✅

Facts Caching — Πλήρες παράδειγμα

---
# facts-caching-demo.yml

- name: Facts Caching Demo
  hosts: all
  become: true
  gather_facts: true    # ← χρησιμοποιεί cache αν υπάρχει

  tasks:

    # ── Υπολογισμός & caching facts ───────────
    - name: Υπολογισμός performance facts
      ansible.builtin.set_fact:
        # Performance calculations
        nginx_workers:     "{{ ansible_facts['processor_vcpus'] | int }}"
        php_memory:        "{{ (ansible_facts['memtotal_mb'] * 0.25) | int }}M"
        mysql_buffer_pool: "{{ (ansible_facts['memtotal_mb'] * 0.50) | int }}M"
        redis_maxmemory:   "{{ (ansible_facts['memtotal_mb'] * 0.20) | int }}mb"

        # System profile
        server_profile: >-
          {%- if ansible_facts['memtotal_mb'] | int >= 8192 -%}
          high_performance
          {%- elif ansible_facts['memtotal_mb'] | int >= 4096 -%}
          standard
          {%- elif ansible_facts['memtotal_mb'] | int >= 2048 -%}
          low_memory
          {%- else -%}
          minimal
          {%- endif -%}

        # Deploy metadata
        last_configured: "{{ ansible_facts['date_time']['iso8601'] }}"
      cacheable: true    # ← αποθήκευσε στο cache!

    # ── Εμφάνιση ──────────────────────────────
    - name: Performance profile
      ansible.builtin.debug:
        msg:
          - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
          - "Server Profile: {{ server_profile }}"
          - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
          - "Nginx workers : {{ nginx_workers }}"
          - "PHP memory    : {{ php_memory }}"
          - "MySQL buffer  : {{ mysql_buffer_pool }}"
          - "Redis memory  : {{ redis_maxmemory }}"
          - "Configured at : {{ last_configured }}"
          - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

    # ── Χρήση σε templates ────────────────────
    - name: Deploy performance config
      ansible.builtin.copy:
        dest:  /etc/myapp/performance.conf
        mode:  '0644'
        content: |
          # Performance Configuration
          # Profile: {{ server_profile }}
          # Generated: {{ last_configured }}

          [nginx]
          worker_processes = {{ nginx_workers }}

          [php]
          memory_limit = {{ php_memory }}

          [mysql]
          innodb_buffer_pool_size = {{ mysql_buffer_pool }}

          [redis]
          maxmemory = {{ redis_maxmemory }}

Χρήση Cached Facts από άλλο Play

---
# Το μεγάλο πλεονέκτημα του caching:
# Play 1 συλλέγει facts → Play 2 τα χρησιμοποιεί
# χωρίς να συνδεθεί ξανά στον server!

- name: Play 1 — Συλλογή Facts
  hosts: all
  gather_facts: true
  tasks:
    - name: Cache performance facts
      ansible.builtin.set_fact:
        server_profile: "high_performance"
        nginx_workers:  "{{ ansible_facts['processor_vcpus'] }}"
      cacheable: true

# ── Αργότερα — ξεχωριστό playbook ────────────
- name: Play 2 — Χρήση Cached Facts
  hosts: all
  gather_facts: false    # ← ΔΕΝ τρέχει setup module!
                         # Διαβάζει από cache! ✅
  tasks:
    - name: Χρησιμοποίησε cached facts
      ansible.builtin.debug:
        msg:
          - "Profile : {{ server_profile }}"
          - "Workers : {{ nginx_workers }}"
          - "RAM     : {{ ansible_facts['memtotal_mb'] }}"
          # ↑ Από cache, όχι από live server!

Καθαρισμός Cache

# Καθαρισμός cache για συγκεκριμένο server
rm /tmp/ansible_facts_cache/nextcloud

# Καθαρισμός όλου του cache
rm -rf /tmp/ansible_facts_cache/*

# Εξαναγκασμός ανανέωσης (αγνόησε cache)
ansible-playbook playbooks/myplaybook.yml \
    --flush-cache

set_fact vs vars — Διαφορές

# ── vars: → ορίζονται ΠΡΙΝ την εκτέλεση ──────
vars:
  my_var: "static_value"
  # ← γνωστό από την αρχή

# ── set_fact → ορίζεται ΚΑΤΑ την εκτέλεση ────
tasks:
  - name: Dynamic fact
    ansible.builtin.set_fact:
      my_fact: "{{ register_result.stdout }}"
      # ← εξαρτάται από αποτέλεσμα task!

# ── Βασική διαφορά ────────────────────────────
# vars    → static, ορίζονται εκ των προτέρων
# set_fact→ dynamic, υπολογίζονται κατά εκτέλεση
#           μπορούν να χρησιμοποιούν register results
#           μπορούν να χρησιμοποιούν runtime data
#           διαθέσιμα σε ΟΛΟΥΣ τους hosts (με hostvars)

set_fact μεταξύ Hosts

# Ειδική δυνατότητα: set_fact ενός host
# είναι προσβάσιμο από ΑΛΛΟ host μέσω hostvars!

- name: Play 1 — Server A sets fact
  hosts: server_a
  tasks:
    - name: Set fact
      ansible.builtin.set_fact:
        my_ip: "{{ ansible_facts['default_ipv4']['address'] }}"
      cacheable: true

- name: Play 2 — Server B χρησιμοποιεί fact του Server A
  hosts: server_b
  tasks:
    - name: Χρήση fact από server_a
      ansible.builtin.debug:
        msg: "Server A IP: {{ hostvars['server_a']['my_ip'] }}"
      # ↑ hostvars → πρόσβαση σε facts άλλων hosts!

Σύνοψη 13.4

set_fact & Cached Facts
├── set_fact:
│   ├── Ορισμός facts κατά εκτέλεση
│   ├── Δυναμικοί υπολογισμοί
│   ├── Βάσει register results
│   └── cacheable: true → αποθήκευση στο cache
│
├── Facts Caching:
│   ├── ansible.cfg: fact_caching = jsonfile
│   ├── fact_caching_connection = /tmp/cache
│   ├── fact_caching_timeout = 3600
│   └── --flush-cache → καθαρισμός
│
├── Cache Backends:
│   ├── memory   → default (χάνεται)
│   ├── jsonfile → αρχεία JSON ✅
│   └── redis    → για production
│
└── set_fact vs vars:
    ├── vars     → static, πριν εκτέλεση
    └── set_fact → dynamic, κατά εκτέλεση