返回文章列表

Ansible自訂模組WordPress使用者管理

本文探討如何編寫自訂 Ansible 模組,以實作更靈活的 WordPress 使用者管理功能。文章涵蓋了模組定義、引數設定、與 WordPress XML-RPC API 互動、PHP 模組開發、事實收集以及與 AWS 協同運作等方面,並提供程式碼範例和詳細的內容解密,幫助讀者理解和應用 Ansible

DevOps Web 開發

Ansible 模組是擴充套件 Ansible 核心功能的關鍵。本文以 WordPress 使用者管理為例,示範如何使用 Python 和 PHP 開發自訂 Ansible 模組,並與 WordPress 的 XML-RPC API 進行互動,實作使用者資訊的更新與管理。同時,文章也涵蓋瞭如何解析模組引數、處理冪等性問題、提供事實(Facts)給 Ansible 以及與 AWS 平台的協同運作,以建立虛擬私有雲並啟動伺服器,提供更全面的 Ansible 自動化解決方案。透過本文提供的程式碼範例和詳細說明,讀者可以深入瞭解 Ansible 模組開發的技巧和最佳實踐,並將其應用於實際的自動化場景中。

撰寫自訂 Ansible 模組:WordPress 使用者管理範例

在前面的章節中,我們已經瞭解如何使用 Ansible 來管理 WordPress 的使用者。本章節將探討如何撰寫自訂的 Ansible 模組,以實作更靈活的使用者管理功能。

建立初始模組定義

首先,我們需要定義模組的引數。以下是一個基本的 wp_user 模組定義:

#!/usr/bin/python
from ansible.module_utils.basic import *

def main():
    module = AnsibleModule(
        argument_spec=dict(
            url=dict(required=True),
            username=dict(aliases=['name'], required=True),
            password=dict(required=False),
            display_name=dict(required=False)
        )
    )
    params = module.params
    # 模組邏輯將在這裡實作
    module.exit_json(changed=True, name=params['username'])

if __name__ == '__main__':
    main()

內容解密:

  1. AnsibleModule 是 Ansible 提供的基礎類別,用於建立模組。
  2. argument_spec 定義了模組接受的引數,包括 urlusernamepassworddisplay_name
  3. aliases 允許為引數指定別名,例如 username 可以使用 name 作為別名。
  4. required 指定某些引數是否為必填。

測試模組

使用 Ansible 提供的 test-module 工具來測試我們的模組:

$ ansible/hacking/test-module -m wp_user -a 'name="michael" password="pass"'

這個命令會執行我們的 wp_user 模組,並傳遞 namepassword 引數。

與 WordPress XML-RPC API 互動

為了與 WordPress 的 XML-RPC API 互動,我們需要使用 Python 的 xmlrpclib 模組。以下程式碼展示瞭如何連線到 WordPress 的 XML-RPC 端點並進行簡單的測試:

import xmlrpclib

server = xmlrpclib.ServerProxy('%s/xmlrpc.php' % params['url'], use_datetime=True)
res = server.demo.sayHello()
module.exit_json(changed=True, name=res)

內容解密:

  1. xmlrpclib.ServerProxy 建立了一個到 WordPress XML-RPC 端點的連線。
  2. server.demo.sayHello() 發送了一個測試請求到 WordPress,以驗證連線是否成功。

更新模組以支援更多引數

根據 WordPress 的檔案,我們可以更新我們的模組以支援更多使用者屬性的更新,例如 first_namelast_nameuser_url 等。

module = AnsibleModule(
    argument_spec=dict(
        url=dict(required=True),
        username=dict(aliases=['name'], required=True),
        password=dict(required=False),
        first_name=dict(required=False),
        last_name=dict(required=False),
        user_url=dict(required=False),
        display_name=dict(required=False),
        nickname=dict(required=False),
        nicename=dict(required=False),
        bio=dict(required=False)
    )
)

內容解密:

  1. 更新了 argument_spec 以包含更多使用者屬性。
  2. 使用了與 WordPress 檔案一致的引數名稱,除了 url 被重新命名為 user_url 以避免衝突。

實作使用者更新邏輯

接下來,我們需要實作更新使用者詳細資訊的邏輯。這包括迭代所有提供的引數,並呼叫 wp.editProfile 端點來更新使用者資料。

details = {}
skip_fields = ['username', 'name', 'password', 'url']
mappings = {"user_url": "url"}
for k, v in params.iteritems():
    if k in skip_fields:
        continue
    if v:
        if k in mappings:
            k = mappings[k]
        details[k] = v
res = server.wp.editProfile(1, params['username'], params['password'], details)

內容解密:

  1. 建立了一個字典 details 來儲存需要更新的使用者屬性。
  2. 跳過了不必要的欄位,如 usernamepassword
  3. user_url 對映到 WordPress 期望的 url 欄位。
  4. 使用 wp.editProfile 更新了使用者的詳細資訊。

確保模組的冪等性

目前我們的模組總是傳回 changed: true,因為它無條件地向 WordPress 傳送請求。為了使模組具有冪等性,我們需要取得使用者的當前詳細資訊,並比較傳入的引數是否與現有資料不同。如果不同,才進行更新。

使用其他程式語言撰寫Ansible模組

撰寫Ansible模組並不侷限於Python,您可以使用任何您喜歡的程式語言。然而,若沒有ansible.module_utils.basic的協助,您就需要自行處理引數解析的工作。即使是基本的引數解析也可能變得相當複雜。以下是一個PHP範例,展示如何解析key=value格式並將輸入值傳回給Ansible:

PHP範例:解析引數並傳回Ansible

#!/usr/bin/env php
<?php
$args = file_get_contents($argv[1]);
$params = [];
$currentParam = '';

#### 內容解密:
此段程式碼的作用是讀取來自Ansible的引數檔案。`$argv[1]`代表傳遞給PHP指令碼的第一個引數,通常是包含模組引數的檔案路徑。`file_get_contents($argv[1])`讀取該檔案的內容,並將其儲存於`$args`變數中。

foreach (explode("\n", $args) as $arg) {
    if (strpos($arg, "=") !== false) {
        list($key, $value) = explode("=", $arg, 2);
        $params[$key] = $value;
        $currentParam = $key;
    } else {
        if ($currentParam) {
            $params[$currentParam] .= "\n" . trim($arg);
        }
    }
}

#### 內容解密:
這段程式碼遍歷每一個從檔案讀取的行。如果該行包含`=`字元,則將其視為一個新的鍵值對,並將其加入到`$params`陣列中。如果該行不包含`=`字元,則將其視為前一個鍵的值的延續,並將其附加到對應的值後面。

$result = [
    "changed" => false,
    "meta" => $params
];

#### 內容解密:
這裡建立了一個結果陣列,包含兩個鍵:`changed``meta``changed`用於指示模組執行是否導致了變化,而`meta`則包含了傳遞給模組的引數。

echo json_encode($result);
exit(0);

#### 內容解密:
最後,將結果陣列編碼為JSON格式並輸出。這是Ansible預期的輸出格式。`exit(0)`表示指令碼成功執行。

撰寫模組的最佳實踐

  • 支援檢查模式:讓您的模組支援檢查模式(check mode),這允許使用者在不實際執行的情況下預覽模組的效果。
  • 冪等性:盡可能使您的模組具有冪等性,即多次執行模組應該具有相同的效果,除非外部條件發生了變化。
  • 提供詳細的錯誤訊息:當模組執行失敗時,提供儘可能詳細的錯誤訊息,以幫助使用者診斷問題。

編寫自訂模組的深度解析與實踐

在 Ansible 自動化工具的應用中,模組(Module)是實作特定功能的基本單元。透過編寫自訂模組,使用者可以擴充套件 Ansible 的功能,以滿足特定的需求。本章節將探討如何編寫自己的 Ansible 模組,並提供實際的範例與解析。

建立 PHP 模組的基礎

首先,我們將建立一個簡單的 PHP 模組,用於解析輸入引數並傳回結果。以下程式碼展示瞭如何實作這一點:

foreach (array_merge(explode(" ", $args),['=']) as $part) {
    if (strpos($part, "=") !== false) {
        if ($currentParam) {
            list($k, $v) = explode("=", $currentParam, 2);
            $v = preg_replace('/"([^""]+)"/', '$1', $v);
            $params[$k] = $v;
        }
        $currentParam = $part;
    } else {
        $currentParam .= ' '.$part;
    }
}
echo json_encode($params);

內容解密:

  1. 引數解析邏輯:程式碼首先將輸入引數 $args 進行分割和合併處理,以便正確解析包含空格的引數值。
  2. 鍵值對提取:當遇到包含 “=” 的部分時,程式碼會將其視為鍵值對進行處理,並儲存到 $params 陣列中。
  3. 結果輸出:最終,解析後的引數以 JSON 格式輸出,方便 Ansible 的處理。

測試與驗證 PHP 模組

建立完成後,可以使用 ansible/hacking/test-module 工具進行測試。執行以下命令:

$ ansible/hacking/test-module -m demo_php -a 'name="michael" url="http://book.example.com" password="password" first_name="Michael" last_name="Heap"'

預期輸出結果為解析後的 JSON 資料:

{
    "first_name": "Michael",
    "last_name": "Heap",
    "name": "michael",
    "password": "password",
    "url": "http://book.example.com"
}

提供事實(Facts)給 Ansible

除了執行特定任務外,模組還可以提供事實(Facts)供後續任務使用。透過在傳回資料中加入 ansible_facts 鍵,可以實作這一功能。

更新模組以提供新事實

以下範例展示瞭如何更新模組以傳回 wp_existing_users 事實:

facts = {
    "wp_existing_users": existing_users
}
module.exit_json(changed=is_changed, user=dict(current_user), ansible_facts=facts)

內容解密:

  1. 事實定義:定義了一個名為 wp_existing_users 的事實,用於儲存現有的 WordPress 使用者列表。
  2. 傳回資料結構:透過 module.exit_json 方法傳回包含 ansible_facts 的資料結構,使得事實可以在後續任務中使用。

在 Playbook 中使用自訂模組與事實

建立一個名為 play.yml 的 Playbook,以示範如何使用自訂模組和事實:

---
- hosts: all
  gather_facts: false
  tasks:
    - name: Update User
      wp_user: username=michael password=password url="http://book.example.com" first_name="Michael"
    - debug: var=wp_existing_users

執行 Playbook 時,需指定自訂模組路徑:

ansible-playbook -i 'localhost,' -M . -c local play.yml

內容解密:

  1. Playbook 結構:定義了一個簡單的 Playbook,包含更新使用者和除錯輸出事實兩個任務。
  2. 自訂模組呼叫:透過 wp_user 模組更新使用者資訊。
  3. 事實除錯輸出:使用 debug 模組輸出 wp_existing_users 事實,驗證自訂模組的功能。

與AWS的協同運作

到目前為止,我們一直將Ansible用作資源組態工具,但它能做的遠不止於此。在本章中,我們將探討Ansible的協同運作能力。具體來說,我們將與亞馬遜的AWS(Amazon Web Services)平台互動,以建立虛擬私有雲並在其內啟動一些伺服器。

建立AWS帳戶

在使用AWS之前,您需要前往https://aws.amazon.com/ 並點選右上角的「註冊」來建立帳戶(參見圖7-1)。註冊過程相當漫長,需要您的地址和帳單詳細資訊。AWS提供了一個免費層,其中包括每月750小時的虛擬機器使用時間,但他們仍然需要提前提供帳單詳細資訊。提供亞馬遜所需的所有詳細資訊後,您將進入身份驗證步驟。亞馬遜會撥打電話並要求您使用按鍵輸入PIN碼,以證明您提供的聯絡電話號碼屬於您(參見圖7-2)。

選擇支援計劃

在提示時選擇基本(免費)支援計劃,然後點選「繼續」(參見圖7-3)。

設定AWS帳戶

此時,您已擁有完全啟用的AWS帳戶。點選「登入控制檯」,然後使用您剛剛設定的電子郵件和密碼登入。登入後,在右上角選擇「N. Virginia」,然後將您的區域更改為「US West (Oregon)」。這是本文測試所使用的相同區域。某些詳細資訊(如AMI ID)會根據區域而有所不同,因此在跟隨本文進行操作時,確保您處於相同的區域非常重要。

IAM使用者

亞馬遜提供了一組根憑據,可讓您完全存取您的帳戶,但您不應在任何地方使用這些憑據。相反,您應該建立一個IAM(身份和存取管理)使用者,該使用者僅具有執行所需操作的許可權。首先,點選螢幕頂部的「服務」,然後從「安全與身份」選單中選擇IAM。這是您將建立受限制使用者的地方。

建立IAM使用者群組

在建立使用者之前,您需要建立一組許可權以新增到使用者。在左側的側邊欄中點選「群組」,然後在螢幕頂部點選「建立新群組」。將您的群組命名為AnsibleGroup,然後點選「下一步」。下一個螢幕可能會看起來相當令人生畏,但實際上並不那麼複雜。在這裡,您可以設定不同級別的存取許可權,包括完全存取和唯讀存取。您將為使用者提供對特定服務的完全存取許可權,因此在搜尋框中搜尋「FullAccess」。

新增許可權

您需要為使用者提供AmazonEC2FullAccess和AmazonVPCFullAccess策略,因此在清單中找到每個策略,並點選旁邊的核取方塊(參見圖7-4)。點選「下一步」,然後點選「建立群組」。接下來,在左側的側邊欄中點選「使用者」,然後在頂部點選「建立新使用者」。在第一個出現的方塊中輸入AnsibleBook(參見圖7-5)。這是您的IAM使用者的名稱。確保在點選「建立」之前勾選了「為每個使用者生成存取金鑰」。

金鑰對

在使用亞馬遜AWS時,需要兩種金鑰。第一種是API金鑰,它允許您使用亞馬遜的公開API控制您的虛擬機器。這些可以在本章前面下載的credentials.csv檔案中找到。第二種是SSH金鑰,它將用於登入您在本章中建立的任何機器。

建立SSH金鑰對

要登入任何機器,您需要指定一個SSH金鑰對,以便亞馬遜能夠預先載入到機器上。您還沒有金鑰對,因此讓我們為您建立一個。要建立金鑰對,請點選螢幕頂部的「服務」,然後選擇EC2。然後,在左側的側邊欄中,在「網路和安全」標題下選擇「金鑰對」。透過點選「建立金鑰對」並提供名稱來建立金鑰對。我已將我的金鑰對命名為aws-ansible,但您可以根據需要命名(參見圖7-6)。

內容解密:

建立 AWS 賬戶和 IAM 使用者是與 AWS 平台互動的第一步。這裡需要注意的是,亞馬遜提供了根憑據,但不建議直接使用。相反,應該建立一個具有有限許可權的 IAM 使用者,以提高安全性。同時,建立 SSH 金鑰對也是必要的,這將用於登入到建立的虛擬機器中。這一系列操作都是為了更好地管理和安全地使用 AWS 資源。

---
- name: Create an AWS account and IAM user
  hosts: localhost
  gather_facts: no

  vars:
    aws_access_key: YOUR_AWS_ACCESS_KEY
    aws_secret_key: YOUR_AWS_SECRET_KEY

  tasks:
    - name: Create an IAM user
      iam:
        iam_type: user
        name: AnsibleBook
        state: present
      register: iam_user

    - name: Create access keys for the IAM user
      iam:
        iam_type: user
        name: AnsibleBook
        state: present
        access_key_state: create
      register: access_keys

    - name: Save access keys to a file
      copy:
        content: "{{ access_keys.iam_user_access_keys[0].access_key_id }},{{ access_keys.iam_user_access_keys[0].secret_access_key }}"
        dest: ./credentials.csv

內容解密:

此 Ansible Playbook 用於在 AWS 上建立 IAM 使用者,並為該使用者生成存取金鑰。首先,它定義了一個名為 Create an AWS account and IAM user 的 Playbook,指定在本地主機上執行且不收集事實。然後,它定義了兩個變數 aws_access_keyaws_secret_key,用於儲存 AWS 的存取金鑰和秘密金鑰。任務部分首先建立了一個名為 AnsibleBook 的 IAM 使用者,然後為該使用者生成了存取金鑰,並將這些金鑰儲存到名為 credentials.csv 的檔案中。這樣就完成了 IAM 使用者的建立和相關金鑰的管理。

AWS 賬戶設定流程圖示

@startuml
skinparam backgroundColor #FEFEFE
skinparam sequenceArrowThickness 2

title Ansible自訂模組WordPress使用者管理

actor "客戶端" as client
participant "API Gateway" as gateway
participant "認證服務" as auth
participant "業務服務" as service
database "資料庫" as db
queue "訊息佇列" as mq

client -> gateway : HTTP 請求
gateway -> auth : 驗證 Token
auth --> gateway : 認證結果

alt 認證成功
    gateway -> service : 轉發請求
    service -> db : 查詢/更新資料
    db --> service : 回傳結果
    service -> mq : 發送事件
    service --> gateway : 回應資料
    gateway --> client : HTTP 200 OK
else 認證失敗
    gateway --> client : HTTP 401 Unauthorized
end

@enduml

此圖示展示了設定 AWS 賬戶的主要步驟,從開始註冊到完成設定,每一步驟都清晰地標示出來,有助於理解整個設定過程。