Ansible uri Module: API Requests และ HTTP Calls ใน Playbook

Ansible uri module ใช้ส่ง HTTP/HTTPS request จาก Playbook ไปยัง REST API, Webhook หรือ Web Service โดยตรง รองรับ GET, POST, PUT, PATCH, DELETE และ method อื่น ๆ พร้อมกำหนด headers, body, authentication และตรวจสอบ status code — ทั้งหมดนี้ทำได้โดยไม่ต้องรัน command: curl ซึ่งไม่ idempotent

บทความนี้ครอบคลุม parameters หลัก, การส่ง GET และ POST request, การใช้ authentication, การอ่าน response และ pattern สำหรับ integration กับ API ภายนอกใน deployment workflow

uri Module พื้นฐาน — GET Request

uri module ต้องการแค่ url parameter เป็นอย่างน้อย ค่า default ของ method คือ GET โดย module จะ fail อัตโนมัติถ้า HTTP status code เป็น 4xx หรือ 5xx เว้นแต่จะระบุ status_code ที่ยอมรับเอง

---
- name: Basic uri module usage
  hosts: localhost
  tasks:
    # GET request พื้นฐาน
    - name: Check API health endpoint
      uri:
        url: https://api.example.com/health
        method: GET
        return_content: true
      register: health_check

    - name: Show response
      debug:
        msg:
          - "Status: {{ health_check.status }}"
          - "Body: {{ health_check.content }}"

    # ตรวจสอบ status code เฉพาะเจาะจง
    - name: Verify API returns 200
      uri:
        url: https://api.example.com/v1/status
        method: GET
        status_code: 200

    # ยอมรับหลาย status code
    - name: Check resource (200 or 404 accepted)
      uri:
        url: https://api.example.com/v1/users/123
        method: GET
        status_code: [200, 404]
      register: user_check

POST Request — ส่ง JSON Body

ใช้ body และ body_format: json เพื่อส่ง JSON payload ในการสร้าง resource หรือ trigger action ผ่าน REST API — module จะ set Content-Type: application/json ให้อัตโนมัติ

---
- name: POST request examples
  hosts: localhost
  vars:
    api_base: https://api.example.com/v1
    auth_token: "{{ vault_api_token }}"

  tasks:
    # POST JSON body
    - name: Create new user via API
      uri:
        url: "{{ api_base }}/users"
        method: POST
        headers:
          Authorization: "Bearer {{ auth_token }}"
          Content-Type: application/json
        body_format: json
        body:
          username: "{{ new_username }}"
          email: "{{ new_email }}"
          role: developer
        status_code: 201
      register: create_user_result

    - name: Show created user ID
      debug:
        msg: "Created user ID: {{ create_user_result.json.id }}"

    # POST form data
    - name: Submit form data
      uri:
        url: https://api.example.com/token
        method: POST
        body_format: form-urlencoded
        body:
          grant_type: client_credentials
          client_id: "{{ client_id }}"
          client_secret: "{{ vault_client_secret }}"
        status_code: 200
      register: token_result

Headers และ Authentication

กำหนด custom headers ผ่าน headers parameter สำหรับ Basic Authentication ใช้ url_username และ url_password โดยตรง หรือใช้ Bearer token ใน Authorization header

---
- name: Authentication examples
  hosts: localhost
  vars:
    api_url: https://api.example.com

  tasks:
    # Basic Authentication
    - name: GET with Basic Auth
      uri:
        url: "{{ api_url }}/protected/resource"
        method: GET
        url_username: "{{ api_user }}"
        url_password: "{{ vault_api_password }}"
        force_basic_auth: true
        return_content: true
      register: protected_response

    # Bearer Token
    - name: GET with Bearer Token
      uri:
        url: "{{ api_url }}/v1/data"
        method: GET
        headers:
          Authorization: "Bearer {{ vault_bearer_token }}"
          Accept: application/json
          X-Request-ID: "ansible-{{ ansible_date_time.epoch }}"
        return_content: true
      register: data_response

    # API Key ใน header
    - name: GET with API Key
      uri:
        url: "{{ api_url }}/v2/reports"
        method: GET
        headers:
          X-API-Key: "{{ vault_api_key }}"
          Accept: application/json
        status_code: 200
      register: reports_response

อ่านและใช้ Response Data

เมื่อ API ตอบกลับเป็น JSON ใช้ .json property ของ registered variable เพื่อเข้าถึงข้อมูลโดยตรง หรือใช้ .content สำหรับ raw response text

---
- name: Reading response data
  hosts: localhost
  tasks:
    - name: Get server list from API
      uri:
        url: https://api.example.com/v1/servers
        method: GET
        headers:
          Authorization: "Bearer {{ vault_token }}"
        return_content: true
      register: servers_response

    # เข้าถึง JSON fields โดยตรง
    - name: Show server count
      debug:
        msg: "Total servers: {{ servers_response.json.total }}"

    # วนลูปบน JSON array
    - name: Show each server
      debug:
        msg: "Server: {{ item.name }} ({{ item.ip }})"
      loop: "{{ servers_response.json.servers }}"

    # ใช้ response data ใน task ถัดไป
    - name: Get details for first server
      uri:
        url: "https://api.example.com/v1/servers/{{ servers_response.json.servers[0].id }}"
        method: GET
        headers:
          Authorization: "Bearer {{ vault_token }}"
      register: server_detail
      when: servers_response.json.total > 0

PUT และ DELETE — จัดการ Resource

ใช้ PUT สำหรับ update resource ที่มีอยู่แล้ว และ DELETE สำหรับลบ — ทั้งสองมักใช้ใน idempotent workflow ที่ต้องการ manage state ของ resource ภายนอก

---
- name: PUT and DELETE examples
  hosts: localhost
  vars:
    api_url: https://api.example.com/v1
    resource_id: "{{ target_resource_id }}"

  tasks:
    # PUT — update resource ทั้งหมด
    - name: Update resource configuration
      uri:
        url: "{{ api_url }}/configs/{{ resource_id }}"
        method: PUT
        headers:
          Authorization: "Bearer {{ vault_token }}"
        body_format: json
        body:
          name: "{{ config_name }}"
          value: "{{ config_value }}"
          enabled: true
        status_code: 200
      register: update_result

    # PATCH — update เฉพาะ fields
    - name: Patch resource status
      uri:
        url: "{{ api_url }}/servers/{{ resource_id }}"
        method: PATCH
        headers:
          Authorization: "Bearer {{ vault_token }}"
        body_format: json
        body:
          status: maintenance
        status_code: 200

    # DELETE — ลบ resource
    - name: Remove old resource
      uri:
        url: "{{ api_url }}/configs/old-config-123"
        method: DELETE
        headers:
          Authorization: "Bearer {{ vault_token }}"
        status_code: [200, 204, 404]   # 404 = ไม่มีอยู่แล้ว = ok

SSL และ Timeout

ควบคุมพฤติกรรม SSL verification และ timeout เพื่อรองรับ API ที่ใช้ self-signed certificate หรือ internal endpoint ที่ response ช้า

---
- name: SSL and timeout configuration
  hosts: localhost
  tasks:
    # disable SSL verification (ไม่แนะนำ production — ใช้เฉพาะ internal/testing)
    - name: Call internal API with self-signed cert
      uri:
        url: https://internal-api.company.local/health
        method: GET
        validate_certs: false
        return_content: true

    # กำหนด timeout
    - name: Call slow API with longer timeout
      uri:
        url: https://api.example.com/reports/generate
        method: POST
        headers:
          Authorization: "Bearer {{ vault_token }}"
        body_format: json
        body:
          type: monthly
        timeout: 120    # 120 วินาที (default 30)
        status_code: 200

    # ใช้ CA certificate ของ internal PKI
    - name: Call internal API with custom CA
      uri:
        url: https://internal-api.company.local/v1/data
        method: GET
        ca_path: /etc/ssl/certs/company-ca.crt
        return_content: true

Pattern: Webhook Notification และ API Integration ใน Deploy

ตัวอย่าง Playbook ที่ใช้ uri module ส่ง webhook notification และ update deployment status ผ่าน API ระหว่าง deploy application

---
- name: Deploy with API integration
  hosts: appservers
  vars:
    deploy_api: https://deploy-tracker.company.internal/api
    slack_webhook: "{{ vault_slack_webhook_url }}"
    app_version: "{{ deploy_version }}"

  tasks:
    # แจ้ง deployment เริ่มต้นผ่าน Slack
    - name: Notify deployment start
      uri:
        url: "{{ slack_webhook }}"
        method: POST
        body_format: json
        body:
          text: ":rocket: Starting deployment of v{{ app_version }} to {{ inventory_hostname }}"
        status_code: 200
      delegate_to: localhost

    # Register deployment ใน tracking API
    - name: Create deployment record
      uri:
        url: "{{ deploy_api }}/deployments"
        method: POST
        headers:
          Authorization: "Bearer {{ vault_deploy_token }}"
        body_format: json
        body:
          app: myapp
          version: "{{ app_version }}"
          server: "{{ inventory_hostname }}"
          status: in_progress
        status_code: 201
      register: deploy_record
      delegate_to: localhost

    # ... tasks การ deploy จริง ...

    # Update status เป็น success
    - name: Mark deployment as successful
      uri:
        url: "{{ deploy_api }}/deployments/{{ deploy_record.json.id }}"
        method: PATCH
        headers:
          Authorization: "Bearer {{ vault_deploy_token }}"
        body_format: json
        body:
          status: success
          completed_at: "{{ ansible_date_time.iso8601 }}"
        status_code: 200
      delegate_to: localhost

    # แจ้ง Slack ว่า deploy สำเร็จ
    - name: Notify deployment success
      uri:
        url: "{{ slack_webhook }}"
        method: POST
        body_format: json
        body:
          text: ":white_check_mark: Deployed v{{ app_version }} to {{ inventory_hostname }} successfully"
        status_code: 200
      delegate_to: localhost

สรุป

uri module เป็นทางมาตรฐานสำหรับส่ง HTTP request จาก Ansible Playbook รองรับทุก HTTP method, custom headers, JSON/form body, Basic Auth, Bearer token และ SSL configuration ผ่าน parameters ที่ชัดเจนและ idempotent กว่าการใช้ command: curl

Pattern ที่ควรจำ: ใช้ return_content: true เมื่อต้องการอ่าน response body, ใช้ .json property เข้าถึงข้อมูล JSON โดยตรง, ระบุ status_code เป็น list เมื่อต้องการยอมรับหลาย code และใช้ delegate_to: localhost สำหรับ API call ที่ไม่จำเป็นต้องรันบน remote server เพื่อประหยัด connection overhead