Site logo
Tác giả
  • avatar Nguyễn Đức Xinh
    Name
    Nguyễn Đức Xinh
    Twitter
Ngày xuất bản
Ngày xuất bản

Ansible Playbooks Phần 3: Conditionals, Loops và Tags

Phần 3 tập trung vào control flow với Conditionals, Loops và Tags để tạo playbooks linh hoạt và mạnh mẽ.

Phần 3: Conditionals, Loops và Tags:

  • Conditionals (when) cho control flow
  • Loops: simple, dictionaries, nested
  • Loop với conditionals và register
  • Tags cho selective execution
  • Blocks và error handling (block/rescue/always)
  • Ví dụ multi-tier deployment

Conditionals (Điều kiện)

Chạy task chỉ khi điều kiện thỏa mãn sử dụng when.

Basic conditionals

tasks:
  - name: Install Apache on Debian/Ubuntu
    apt:
      name: apache2
      state: present
    when: ansible_os_family == "Debian"

  - name: Install Apache on RedHat/CentOS
    yum:
      name: httpd
      state: present
    when: ansible_os_family == "RedHat"

  - name: Start service only on production
    service:
      name: nginx
      state: started
    when: env == "production"

Multiple conditions với and

tasks:
  - name: Install package on Ubuntu 20.04
    apt:
      name: nginx
      state: present
    when:
      - ansible_distribution == "Ubuntu"
      - ansible_distribution_version == "20.04"

  # Hoặc viết trên một dòng
  - name: Same as above
    apt:
      name: nginx
      state: present
    when: ansible_distribution == "Ubuntu" and ansible_distribution_version == "20.04"

Multiple conditions với or

tasks:
  - name: Install on Debian or Ubuntu
    apt:
      name: nginx
      state: present
    when: ansible_distribution == "Debian" or ansible_distribution == "Ubuntu"

  # Hoặc dùng list
  - name: Install on Debian family
    apt:
      name: nginx
      state: present
    when: ansible_distribution in ["Debian", "Ubuntu"]

Conditions với registered variables

tasks:
  - name: Check if nginx is installed
    command: which nginx
    register: nginx_check
    ignore_errors: yes

  - name: Install nginx if not present
    apt:
      name: nginx
      state: present
    when: nginx_check.rc != 0

  - name: Check disk usage
    shell: df -h / | awk 'NR==2 {print $5}' | sed 's/%//'
    register: disk_usage

  - name: Warning if disk > 80%
    debug:
      msg: "WARNING: Disk usage is {{ disk_usage.stdout }}%"
    when: disk_usage.stdout|int > 80

Conditions với facts

tasks:
  - name: Install specific version on old Ubuntu
    apt:
      name: nginx=1.18.0-0ubuntu1
      state: present
    when:
      - ansible_distribution == "Ubuntu"
      - ansible_distribution_major_version|int < 22

  - name: Set timezone on physical machines
    timezone:
      name: Asia/Ho_Chi_Minh
    when: ansible_virtualization_role != "guest"

Conditions với file checks

tasks:
  - name: Check if config exists
    stat:
      path: /etc/nginx/nginx.conf
    register: config_file

  - name: Backup config if exists
    copy:
      src: /etc/nginx/nginx.conf
      dest: /etc/nginx/nginx.conf.backup
      remote_src: yes
    when: config_file.stat.exists

  - name: Create config if not exists
    copy:
      src: templates/nginx.conf
      dest: /etc/nginx/nginx.conf
    when: not config_file.stat.exists

Conditions với boolean

vars:
  install_monitoring: true
  enable_ssl: false

tasks:
  - name: Install monitoring agent
    apt:
      name: node-exporter
      state: present
    when: install_monitoring

  - name: Configure SSL
    template:
      src: ssl.conf.j2
      dest: /etc/nginx/ssl.conf
    when: enable_ssl | bool

Loops

Lặp qua danh sách items để thực thi task nhiều lần.

Simple loop

- name: Install multiple packages
  apt:
    name: "{{ item }}"
    state: present
  loop:
    - nginx
    - git
    - vim
    - htop
    - curl

Loop với dictionaries

- name: Create multiple users
  user:
    name: "{{ item.name }}"
    state: present
    groups: "{{ item.groups }}"
    shell: "{{ item.shell }}"
  loop:
    - { name: 'john', groups: 'developers', shell: '/bin/bash' }
    - { name: 'jane', groups: 'admins', shell: '/bin/bash' }
    - { name: 'bob', groups: 'developers', shell: '/bin/zsh' }

- name: Create directories with permissions
  file:
    path: "{{ item.path }}"
    state: directory
    owner: "{{ item.owner }}"
    mode: "{{ item.mode }}"
  loop:
    - { path: '/opt/app', owner: 'appuser', mode: '0755' }
    - { path: '/var/log/app', owner: 'appuser', mode: '0755' }
    - { path: '/etc/app', owner: 'root', mode: '0644' }

Loop với variables

vars:
  packages:
    - nginx
    - postgresql
    - redis
  
  users:
    - alice
    - bob
    - charlie

tasks:
  - name: Install packages
    apt:
      name: "{{ item }}"
      state: present
    loop: "{{ packages }}"

  - name: Create users
    user:
      name: "{{ item }}"
      state: present
    loop: "{{ users }}"

Loop với conditionals

- name: Install packages only on Ubuntu
  apt:
    name: "{{ item }}"
    state: present
  loop:
    - nginx
    - apache2
    - mysql-server
  when: ansible_distribution == "Ubuntu"

- name: Create users only in production
  user:
    name: "{{ item }}"
    state: present
  loop:
    - produser1
    - produser2
  when: env == "production"

Loop với register

- name: Check multiple services
  systemd:
    name: "{{ item }}"
  register: service_status
  loop:
    - nginx
    - mysql
    - redis

- name: Display service status
  debug:
    msg: "{{ item.item }} is {{ item.status.ActiveState }}"
  loop: "{{ service_status.results }}"

Nested loops

- name: Create files in multiple directories
  file:
    path: "{{ item.0 }}/{{ item.1 }}"
    state: touch
  loop: "{{ directories | product(files) | list }}"
  vars:
    directories:
      - /tmp/dir1
      - /tmp/dir2
    files:
      - file1.txt
      - file2.txt

Loop control

- name: Install packages with index
  apt:
    name: "{{ item }}"
    state: present
  loop:
    - nginx
    - git
    - vim
  loop_control:
    index_var: idx
    label: "Installing {{ item }}"

- name: Process with pause between iterations
  command: process_item.sh {{ item }}
  loop:
    - item1
    - item2
    - item3
  loop_control:
    pause: 5  # Pause 5 seconds between iterations

Loop until

- name: Wait for service to be ready
  uri:
    url: http://localhost:8080/health
    status_code: 200
  register: health_check
  until: health_check.status == 200
  retries: 10
  delay: 5  # Wait 5 seconds between retries

Tags

Tags giúp chạy selective tasks.

Basic tags

tasks:
  - name: Install nginx
    apt:
      name: nginx
      state: present
    tags:
      - install
      - nginx
      - packages

  - name: Configure nginx
    template:
      src: nginx.conf.j2
      dest: /etc/nginx/nginx.conf
    tags:
      - configure
      - nginx

  - name: Start nginx
    service:
      name: nginx
      state: started
    tags:
      - service
      - nginx

Running with tags

# Chỉ chạy tasks có tag 'install'
ansible-playbook site.yml --tags install

# Chỉ chạy tasks có tag 'nginx'
ansible-playbook site.yml --tags nginx

# Chạy nhiều tags
ansible-playbook site.yml --tags "install,configure"

# Skip tasks có tag 'service'
ansible-playbook site.yml --skip-tags service

# List available tags
ansible-playbook site.yml --list-tags

Special tags

tasks:
  - name: Always run this
    debug:
      msg: "This task always runs"
    tags: always

  - name: Never run this automatically
    debug:
      msg: "This only runs with --tags never"
    tags: never

  - name: Tagged task
    debug:
      msg: "Normal tagged task"
    tags: custom
# Task với tag 'always' sẽ chạy
ansible-playbook site.yml --tags install

# Skip task có tag 'always'
ansible-playbook site.yml --skip-tags always

# Chỉ chạy task có tag 'never'
ansible-playbook site.yml --tags never

Play-level tags

- name: Install packages
  hosts: web
  tags: install
  tasks:
    - name: Install nginx
      apt:
        name: nginx

    - name: Install git
      apt:
        name: git

- name: Configure services
  hosts: web
  tags: configure
  tasks:
    - name: Configure nginx
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf

Block with tags

- name: Installation block
  block:
    - name: Update apt cache
      apt:
        update_cache: yes

    - name: Install packages
      apt:
        name: "{{ item }}"
        state: present
      loop:
        - nginx
        - git
  tags: install

- name: Configuration block
  block:
    - name: Copy configs
      template:
        src: "{{ item }}.j2"
        dest: "/etc/{{ item }}"
      loop:
        - nginx.conf
        - app.conf
  tags: configure

💡 Key Takeaways

  • Conditionals (when) control task execution dựa trên điều kiện
  • Loops iterate qua lists hoặc dictionaries
  • Tags cho phép chạy selective tasks
  • Blocks group tasks và provide error handling
  • Combine conditionals + loops + tags để tạo playbooks mạnh mẽ

🎯 Thực hành

  • Viết playbook với conditionals cho different OS families
  • Sử dụng loops để tạo multiple users và directories
  • Tag tasks theo categories (install, configure, deploy)
  • Implement error handling với block/rescue/always