iT邦幫忙

2025 iThome 鐵人賽

DAY 21
0
DevOps

不爆肝學習 Ansible 的短暫30天系列 第 21

Day21 - Ansible 也有測試要寫!

  • 分享至 

  • xImage
  •  

今日目標

  • 了解 Ansible 測試的重要性與測試策略
  • 掌握 Molecule 測試框架的基本使用

為什麼需要測試 Ansible 程式碼?

寫程式我們都需要透過 Unit Test、Integration Test、E2E Test 等等來確保程式碼的品質,並增加開發的信心度。

所以我們在開發 Ansible Playbook 或 Role 時,也應該要有相對應的測試流程來確保我們的程式碼是正確的。

安裝 Molecule

# 筆者這裡介紹一個最近很夯的 python 套件管理工具 uv
# 首先我們先初始化專案
mkdir -p ansible-molecule-demo
uv init

# 安裝 molecule
uv add molecule

# 驗證 Molecule 是否安裝成功
uv run molecule --version

建立測試專案

uv run molecule init scenario

這會建立以下目錄結構:

ansible-molecule-demo/
├── molecule/
│   └── default/
│       ├── converge.yml        # 測試 playbook
│       ├── create.yml          # 建立環境腳本
|       ├── destroy.yml         # 清理腳本
|       ├── molecule.yml        # Molecule 配置檔
│       └── verify.yml          # 驗證腳本
├── tasks/
│   └── main.yml
├── defaults/
│   └── main.yml
└── meta/
    └── main.yml

測試配置範例

molecule.yml

---
# Dependency management (download roles/collections)
dependency:
  name: galaxy
  options:
    ignore-certs: false
    ignore-errors: false
    role-file: requirements.yml
    requirements-file: requirements.yml


ansible:
  cfg:
    defaults:
      host_key_checking: false
      verbosity: 1
    ssh_connection:
      pipelining: true
  env:
    ANSIBLE_FORCE_COLOR: "1"
    ANSIBLE_LOAD_CALLBACK_PLUGINS: "1"

  executor:
    backend: ansible-playbook
    args:
      ansible_playbook:
        - --diff
        - --force-handlers
        - --inventory=/path/to/inventory.yml
      ansible_navigator:
        - --mode stdout
        - --pull-policy missing
        - --execution-environment-image ghcr.io/ansible/community-ansible-dev-tools:latest

  playbooks:
    create: create.yml
    converge: converge.yml
    destroy: destroy.yml
    cleanup: cleanup.yml
    prepare: prepare.yml
    side_effect: side_effect.yml
    verify: verify.yml

scenario:
  name: default
  test_sequence:
    - dependency
    - cleanup
    - destroy
    - syntax
    - create
    - prepare
    - converge
    - idempotence
    - side_effect
    - verify
    - cleanup
    - destroy

converge.yml

---
# Purpose: bring the instance to the desired state by running the role under test.
# Molecule calls this playbook with `molecule converge`.
- name: Converge
  hosts: all
  gather_facts: true # Disable if your role does not rely on facts
  tasks:
    - name: Apply role under test
      ansible.builtin.include_role:
        name: yournamespace.yourcollection.yourrole

create.yml

---
- name: Create
  hosts: localhost
  connection: local
  gather_facts: false
  # no_log: "{{ molecule_no_log }}"
  tasks:
    # TODO: Developer must implement and populate 'server' variable

    - name: Create instance config
      when: server.changed | default(false) | bool  # noqa no-handler
      block:
        - name: Populate instance config dict  # noqa jinja
          ansible.builtin.set_fact:
            instance_conf_dict: {}
            # instance': "{{ }}",
            # address': "{{ }}",
            # user': "{{ }}",
            # port': "{{ }}",
            # 'identity_file': "{{ }}", }
          with_items: "{{ server.results }}"
          register: instance_config_dict

        - name: Convert instance config dict to a list
          ansible.builtin.set_fact:
            instance_conf: "{{ instance_config_dict.results | map(attribute='ansible_facts.instance_conf_dict') | list }}"

        - name: Dump instance config
          ansible.builtin.copy:
            content: |
              # Molecule managed

              {{ instance_conf | to_json | from_json | to_yaml }}
            dest: "{{ molecule_instance_config }}"
            mode: "0600"

verify.yml

---
# Purpose: assert that the instance really ended up in the expected state.
# Molecule calls this playbook with `molecule verify`.
- name: Verify
  hosts: instance
  gather_facts: false # Quicker, if you do not need facts
  tasks:
    - name: Assert something
      ansible.builtin.assert:
        that: true

destroy.yml

---
- name: Destroy
  hosts: localhost
  connection: local
  gather_facts: false
  # no_log: "{{ molecule_no_log }}"
  tasks:
    # Developer must implement.

    # Mandatory configuration for Molecule to function.

    - name: Populate instance config
      ansible.builtin.set_fact:
        instance_conf: {}

    - name: Dump instance config
      ansible.builtin.copy:
        content: |
          # Molecule managed

          {{ instance_conf | to_json | from_json | to_yaml }}
        dest: "{{ molecule_instance_config }}"
        mode: "0600"
      when: server.changed | default(false) | bool  # noqa no-handler

執行測試

基本測試流程

# 執行完整測試週期
molecule test

# 分階段執行
molecule create      # 建立測試環境
molecule converge    # 執行 playbook
molecule verify      # 執行驗證
molecule destroy     # 清理環境

作業練習時間

練習一:基礎 Molecule 測試

  1. 為現有的 web server Role 建立 Molecule 測試
  2. 撰寫驗證腳本確認 nginx 安裝和運行
  3. 執行完整的測試週期並修正任何問題

明日預告

明天我們來聊聊如何做到多環境的管理


上一篇
Day20 - 自己的模組自己動手做:AnsibleModule
系列文
不爆肝學習 Ansible 的短暫30天21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言