Ansible Conditionals: when statement ให้ Task ทำงานตามเงื่อนไข

Ansible when statement ใช้กำหนดเงื่อนไขให้ task รันเฉพาะเมื่อตรงตามที่ต้องการ — เช่น รันเฉพาะบน Ubuntu, เฉพาะเมื่อไฟล์ยังไม่มี, หรือเฉพาะเมื่อ variable มีค่าที่กำหนด ทำให้ Playbook ทำงานได้บนหลาย OS หรือหลาย environment โดยใช้ไฟล์เดียว

บทความนี้ครอบคลุม syntax พื้นฐานของ when, การใช้ facts ตรวจ OS, การรวมเงื่อนไขด้วย and/or, การใช้ร่วมกับ register, การตรวจ variable และ pattern สำหรับ multi-OS Playbook

when พื้นฐาน

when รับ Jinja2 expression ที่ประเมินเป็น true หรือ false — ถ้า true task จะรัน ถ้า false task จะ skip โดยแสดงสถานะ skipping แทน changed หรือ ok

---
- name: Basic when examples
  hosts: all
  vars:
    env: production
    app_version: "2.5.0"
    debug_mode: false

  tasks:
    # รันเฉพาะเมื่อ env เป็น production
    - name: Enable production optimizations
      command: /opt/myapp/bin/optimize --production
      when: env == "production"

    # รันเฉพาะเมื่อ debug_mode เป็น true
    - name: Enable debug logging
      lineinfile:
        path: /etc/myapp/app.conf
        line: "LOG_LEVEL=debug"
      when: debug_mode

    # รันเฉพาะเมื่อ version ไม่ใช่ latest
    - name: Notify about version
      debug:
        msg: "Running non-latest version: {{ app_version }}"
      when: app_version != "latest"

    # ตรวจ variable มีค่าหรือไม่ (defined และ ไม่ว่าง)
    - name: Run only if deploy_target is set
      debug:
        msg: "Deploying to: {{ deploy_target }}"
      when: deploy_target is defined and deploy_target != ""

when กับ Ansible Facts — ตรวจ OS

Ansible facts ที่ใช้บ่อยที่สุดใน when คือ ansible_os_family และ ansible_distribution เพื่อแยก task ตาม OS — ทำให้ Playbook เดียวรองรับได้ทั้ง Debian-based และ RedHat-based systems

---
- name: OS-specific tasks with when
  hosts: all
  become: true

  tasks:
    # ติดตั้งด้วย apt เฉพาะ Debian/Ubuntu
    - name: Install Nginx on Debian-based systems
      apt:
        name: nginx
        state: present
        update_cache: true
      when: ansible_os_family == "Debian"

    # ติดตั้งด้วย yum/dnf เฉพาะ RedHat/CentOS
    - name: Install Nginx on RedHat-based systems
      yum:
        name: nginx
        state: present
      when: ansible_os_family == "RedHat"

    # ตรวจ distribution เฉพาะเจาะจงมากขึ้น
    - name: Ubuntu-only configuration
      template:
        src: ubuntu-specific.conf.j2
        dest: /etc/nginx/conf.d/ubuntu.conf
      when: ansible_distribution == "Ubuntu"

    # ตรวจ version ด้วย
    - name: Ubuntu 22.04+ specific task
      command: systemctl enable nginx
      when:
        - ansible_distribution == "Ubuntu"
        - ansible_distribution_version is version("22.04", ">=")

รวมเงื่อนไขด้วย and / or

ใช้ list สำหรับ AND conditions (ทุกเงื่อนไขต้องจริง) และใช้ or operator ภายใน expression สำหรับ OR conditions — ไม่ใช้ and keyword ระหว่าง list items

---
- name: Combined conditions
  hosts: all
  vars:
    env: production
    region: asia

  tasks:
    # AND: ใช้ list — ทุก item ต้องเป็น true
    - name: Production Asia deployment
      command: /opt/deploy/asia-prod.sh
      when:
        - env == "production"
        - region == "asia"
        - ansible_os_family == "Debian"

    # OR: ใช้ or keyword ใน expression เดียว
    - name: Run on Ubuntu or Debian
      apt:
        name: curl
        state: present
      when: ansible_distribution == "Ubuntu" or ansible_distribution == "Debian"

    # OR ด้วย in operator (อ่านง่ายกว่า)
    - name: Run on Debian family distributions
      debug:
        msg: "This is a Debian-based system"
      when: ansible_distribution in ["Ubuntu", "Debian", "Mint"]

    # ผสม AND และ OR
    - name: Complex condition
      command: /opt/myapp/tune.sh
      when:
        - env == "production"
        - ansible_os_family == "Debian" or ansible_os_family == "RedHat"

when กับ register — ตรวจผลจาก Task ก่อนหน้า

ใช้ register เก็บผลจาก task แล้วใช้ when ตรวจสอบ — pattern นี้เหมาะสำหรับ task ที่ต้องการตรวจสอบก่อนว่า service ทำงานอยู่, ไฟล์มีอยู่, หรือคำสั่งก่อนหน้าสำเร็จหรือไม่

---
- name: when with register
  hosts: all
  tasks:
    # ตรวจว่า service ทำงานอยู่หรือไม่
    - name: Check if myapp is running
      command: systemctl is-active myapp
      register: myapp_status
      ignore_errors: true
      changed_when: false

    # รันเฉพาะเมื่อ service ไม่ได้ทำงาน
    - name: Start myapp if not running
      service:
        name: myapp
        state: started
      when: myapp_status.rc != 0

    # ตรวจไฟล์ด้วย stat แล้วใช้ when
    - name: Check if config exists
      stat:
        path: /etc/myapp/app.conf
      register: config_file

    - name: Create config if missing
      template:
        src: app.conf.j2
        dest: /etc/myapp/app.conf
      when: not config_file.stat.exists

    # ตรวจ output ของ command
    - name: Get current version
      command: /opt/myapp/bin/myapp --version
      register: current_version
      changed_when: false

    - name: Upgrade only if version is outdated
      command: /opt/upgrade.sh
      when: '"2.5.0" not in current_version.stdout'

ตรวจสอบ Variable — defined, undefined, true, false

Jinja2 มี test ที่ใช้บ่อยสำหรับตรวจสอบ variable ก่อนใช้ — ช่วยป้องกัน error เมื่อ variable อาจไม่ถูก define ใน inventory หรือ vars

---
- name: Variable checking with when
  hosts: all
  tasks:
    # ตรวจว่า variable ถูก define หรือไม่
    - name: Run only if custom_port is defined
      debug:
        msg: "Using custom port: {{ custom_port }}"
      when: custom_port is defined

    # ตรวจว่าไม่ถูก define
    - name: Use default when variable not set
      set_fact:
        custom_port: 8080
      when: custom_port is not defined

    # ตรวจว่า variable เป็น truthy/falsy
    - name: Enable feature only when flag is true
      command: /opt/myapp/enable-feature.sh
      when: feature_enabled | bool

    # ตรวจ string ว่างหรือไม่
    - name: Skip if deploy_key is empty
      command: /opt/deploy.sh
      when: deploy_key is defined and deploy_key | length > 0

    # ใช้ default filter ป้องกัน undefined
    - name: Check with default value
      debug:
        msg: "Environment: {{ env | default('development') }}"
      when: (env | default('development')) != "development"

when กับ loop

เมื่อใช้ when ร่วมกับ loop เงื่อนไขจะถูกประเมินสำหรับแต่ละ item ใน loop — ทำให้ skip เฉพาะ item ที่ไม่ตรงเงื่อนไขได้โดยไม่ต้องหยุด loop ทั้งหมด

---
- name: when with loop
  hosts: all
  vars:
    services:
      - name: nginx
        enabled: true
      - name: myapp
        enabled: true
      - name: legacy-service
        enabled: false

  tasks:
    # รัน task เฉพาะ item ที่ enabled เป็น true
    - name: Start enabled services only
      service:
        name: "{{ item.name }}"
        state: started
      loop: "{{ services }}"
      when: item.enabled

    # ติดตั้ง packages เฉพาะ OS ที่ตรงกัน
    - name: Install OS-specific packages
      package:
        name: "{{ item.name }}"
        state: present
      loop:
        - { name: "nginx", os: "Debian" }
        - { name: "httpd", os: "RedHat" }
        - { name: "curl", os: "all" }
      when: item.os == "all" or item.os == ansible_os_family

Pattern: Multi-OS Playbook

ตัวอย่าง Playbook ติดตั้งและ configure web server บน Ubuntu และ CentOS โดยใช้ when แยกส่วนที่ต่างกัน และใช้ tasks ร่วมกันในส่วนที่เหมือนกัน

---
- name: Cross-platform web server setup
  hosts: all
  become: true

  tasks:
    # Install — แยกตาม OS
    - name: Install Nginx (Debian/Ubuntu)
      apt:
        name: nginx
        state: present
        update_cache: true
      when: ansible_os_family == "Debian"

    - name: Install Nginx (RedHat/CentOS)
      yum:
        name: nginx
        state: present
      when: ansible_os_family == "RedHat"

    # Set nginx config path ตาม OS
    - name: Set nginx config path (Debian)
      set_fact:
        nginx_conf_dir: /etc/nginx/conf.d
      when: ansible_os_family == "Debian"

    - name: Set nginx config path (RedHat)
      set_fact:
        nginx_conf_dir: /etc/nginx/conf.d
      when: ansible_os_family == "RedHat"

    # Deploy config — เหมือนกันทุก OS
    - name: Deploy virtual host config
      template:
        src: vhost.conf.j2
        dest: "{{ nginx_conf_dir }}/mysite.conf"
        owner: root
        group: root
        mode: '0644'
      notify: Reload Nginx

    # Enable site — เฉพาะ Debian ที่ใช้ sites-available/sites-enabled
    - name: Enable site (Debian only)
      file:
        src: /etc/nginx/sites-available/mysite.conf
        dest: /etc/nginx/sites-enabled/mysite.conf
        state: link
      when: ansible_os_family == "Debian"

    # Start service — เหมือนกันทุก OS
    - name: Ensure Nginx is started and enabled
      service:
        name: nginx
        state: started
        enabled: true

  handlers:
    - name: Reload Nginx
      service:
        name: nginx
        state: reloaded

สรุป

when statement เป็นกลไกหลักสำหรับสร้าง Playbook ที่ยืดหยุ่น รองรับการตรวจสอบ OS, variable, ผลจาก task ก่อนหน้า และเงื่อนไขซับซ้อนด้วย AND/OR — task ที่ไม่ตรงเงื่อนไขจะถูก skip โดยอัตโนมัติโดยไม่ทำให้ Playbook error

Pattern ที่ควรจำ: ใช้ list สำหรับ AND conditions, ใช้ or ใน expression เดียวสำหรับ OR conditions, ตรวจ is defined ก่อนใช้ variable ที่อาจไม่มีค่า, ใช้ ansible_os_family แทน ansible_distribution เพื่อรองรับ distro หลายรุ่นในคราวเดียว และระวัง when ใน loop ที่จะประเมินเงื่อนไขทีละ item