Condition & Loop

Condition & Loop #

Playbook yang hanya berjalan secara linear dari atas ke bawah tanpa variasi hanya berguna untuk skenario yang sangat sederhana. Di dunia nyata, kamu perlu task yang berjalan hanya dalam kondisi tertentu — install package A hanya di Ubuntu, skip task tertentu jika service sudah berjalan — dan task yang mengulang aksi untuk banyak item. when dan loop adalah dua mekanisme Ansible untuk menangani kebutuhan ini.

Kondisi dengan when #

when adalah kondisi yang menentukan apakah sebuah task akan dieksekusi. Task hanya dijalankan jika kondisi when bernilai true:

- name: Install paket khusus Ubuntu
  apt:
    name: ubuntu-advantage-tools
    state: present
  when: ansible_distribution == "Ubuntu"   # Hanya jalan di Ubuntu

- name: Install paket khusus RHEL
  dnf:
    name: rhel-system-roles
    state: present
  when: ansible_distribution == "RedHat"   # Hanya jalan di RHEL

Kondisi dalam when adalah ekspresi Jinja2 yang dievaluasi menjadi true atau false. Kamu bisa menggunakan semua variabel Ansible yang tersedia — facts, variabel inventory, variabel yang di-register dari task sebelumnya.


Kondisi Berbasis Facts #

Facts yang dikumpulkan Ansible menyediakan informasi lengkap tentang managed node — sistem operasi, versi kernel, arsitektur, jumlah memori, dan banyak lagi:

# Kondisi berdasarkan OS
- name: Install nginx (Debian-based)
  apt:
    name: nginx
    state: present
  when: ansible_os_family == "Debian"

- name: Install nginx (RedHat-based)
  dnf:
    name: nginx
    state: present
  when: ansible_os_family == "RedHat"

# Kondisi berdasarkan versi OS
- name: Aktifkan fitur yang hanya ada di Ubuntu 22.04+
  command: /opt/app/enable-new-feature
  when:
    - ansible_distribution == "Ubuntu"
    - ansible_distribution_major_version | int >= 22

# Kondisi berdasarkan memori
- name: Aktifkan swap (hanya untuk server dengan RAM < 2GB)
  command: /usr/local/bin/setup-swap.sh
  when: ansible_memtotal_mb < 2048

Kondisi Kompleks: AND, OR, NOT #

Kondisi when mendukung operator logika untuk ekspresi yang lebih kompleks:

# AND — semua kondisi harus terpenuhi (gunakan list)
- name: Deploy konfigurasi khusus
  template:
    src: special.conf.j2
    dest: /etc/app/special.conf
  when:
    - env == "production"           # Kondisi 1
    - ansible_distribution == "Ubuntu"  # Kondisi 2
    - app_version | version_compare('2.0', '>=')  # Kondisi 3
  # Semua tiga kondisi harus true

# OR — salah satu kondisi terpenuhi
- name: Restart service untuk distro tertentu
  systemd:
    name: myapp
    state: restarted
  when: ansible_distribution == "Ubuntu" or ansible_distribution == "Debian"

# NOT — kondisi kebalikan
- name: Skip setup monitoring di environment dev
  include_tasks: setup-monitoring.yml
  when: env != "development"

# Kombinasi AND dan OR
- name: Task khusus untuk production Ubuntu atau staging RedHat
  command: /opt/app/special-setup
  when: >
    (env == "production" and ansible_os_family == "Debian") or
    (env == "staging" and ansible_os_family == "RedHat")    

Kondisi Berbasis Hasil Task Sebelumnya #

Hasil task yang disimpan dengan register sangat sering digunakan sebagai kondisi:

- name: Cek apakah file konfigurasi lama ada
  stat:
    path: /etc/app/old-config.conf
  register: old_config

- name: Backup konfigurasi lama jika ada
  copy:
    src: /etc/app/old-config.conf
    dest: /etc/app/old-config.conf.bak
    remote_src: true
  when: old_config.stat.exists     # Jalankan hanya jika file ada

- name: Cek apakah database sudah diinisialisasi
  command: psql -U postgres -c "SELECT tablename FROM pg_tables WHERE schemaname='public'"
  register: db_tables
  changed_when: false

- name: Inisialisasi database jika kosong
  command: python manage.py migrate
  when: db_tables.stdout_lines | length == 0

Loop Dasar #

Saat kamu perlu menjalankan task yang sama untuk beberapa item, gunakan loop:

# Tanpa loop — repetitif dan sulit di-maintain
- name: Install nginx
  apt:
    name: nginx
    state: present

- name: Install postgresql
  apt:
    name: postgresql
    state: present

- name: Install redis
  apt:
    name: redis-server
    state: present

# Dengan loop — lebih bersih
- name: Install semua package yang diperlukan
  apt:
    name: "{{ item }}"
    state: present
  loop:
    - nginx
    - postgresql
    - redis-server

Loop dengan Dictionary #

Loop bisa mengiterasi atas list of dictionaries untuk task yang membutuhkan beberapa parameter per item:

- name: Buat beberapa user sistem
  user:
    name: "{{ item.name }}"
    groups: "{{ item.groups }}"
    shell: "{{ item.shell | default('/bin/bash') }}"
    state: present
  loop:
    - name: deployer
      groups: sudo
      shell: /bin/bash
    - name: monitor
      groups: monitoring
      shell: /bin/false
    - name: backup
      groups: backup

- name: Buat beberapa direktori dengan permission berbeda
  file:
    path: "{{ item.path }}"
    state: directory
    owner: "{{ item.owner }}"
    mode: "{{ item.mode }}"
  loop:
    - path: /opt/app
      owner: deployer
      mode: "0755"
    - path: /var/log/app
      owner: deployer
      mode: "0755"
    - path: /etc/app/secrets
      owner: root
      mode: "0700"

loop_control: Label yang Lebih Informatif #

Secara default, output loop menampilkan seluruh nilai item yang bisa panjang dan sulit dibaca. Gunakan loop_control untuk menampilkan label yang lebih bersih:

- name: Deploy konfigurasi per virtual host
  template:
    src: "templates/vhost.conf.j2"
    dest: "/etc/nginx/sites-available/{{ item.domain }}.conf"
  loop:
    - domain: app.example.com
      port: 8080
      upstream: app-backend
    - domain: api.example.com
      port: 8081
      upstream: api-backend
  loop_control:
    label: "{{ item.domain }}"   # Tampilkan hanya domain, bukan seluruh dict

# Output dengan loop_control:
# TASK [Deploy konfigurasi per virtual host] *****
# changed: [web-01] => (item=app.example.com)
# changed: [web-01] => (item=api.example.com)

# Output tanpa loop_control (lebih berantakan):
# changed: [web-01] => (item={'domain': 'app.example.com', 'port': 8080, ...})

Kombinasi Loop dan when #

Loop dan when bisa dikombinasikan — kondisi dievaluasi untuk setiap iterasi:

- name: Install optional features berdasarkan konfigurasi
  apt:
    name: "{{ item.package }}"
    state: present
  loop:
    - package: nginx
      enabled: true
    - package: varnish
      enabled: false    # Package ini akan di-skip
    - package: redis-server
      enabled: true
  when: item.enabled    # Jalankan hanya untuk item dengan enabled: true

Ringkasan #

  • when menentukan apakah task dieksekusi — kondisi dievaluasi sebagai ekspresi Jinja2.
  • Gunakan list untuk kondisi AND (semua harus terpenuhi), operator or untuk kondisi OR, dan not untuk negasi.
  • Facts (ansible_distribution, ansible_os_family, dll.) adalah sumber kondisi yang paling umum — tersedia di semua managed node.
  • Hasil task yang disimpan dengan register bisa digunakan sebagai kondisi untuk task berikutnya.
  • loop untuk mengulang task terhadap banyak item — lebih bersih dari task yang diulang secara manual.
  • Loop bisa mengiterasi list of dictionaries untuk task yang membutuhkan beberapa parameter per item.
  • loop_control.label untuk menampilkan output yang lebih bersih saat menggunakan loop dengan dictionary kompleks.
  • when di dalam loop dievaluasi per item — kamu bisa skip item tertentu berdasarkan nilai propertinya.

← Sebelumnya: Notify & Listen   Berikutnya: Scope & Precedence →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact