在Ansible中處理條件語句的使用方式

如果您需要根據不同條件執行Ansible任務,那麼您將會受到獎勵。Ansible的when和其他條件語句讓您可以評估條件,例如基於作業系統,或者一個任務是否依賴於前一個任務。

在本教程中,您將學習如何使用Ansible的when和其他條件語句,以便在不搞砸事情的情況下執行任務。

讓我們開始吧!

先決條件

本教程包含實際示例。如果您想跟隨操作,請確保您已準備好以下內容:

  • A remote computer to run commands.
  • 您需要設置一個清單文件,並且已經配置了一個或多個主機以運行Ansible命令和Playbook。本教程將使用一個名為web的清單組。

在Playbook中使用Ansible的when處理多個任務

在Playbook中有多个任务,如果它们都没有特定的条件执行,可能会很麻烦。让我们从在Ansible Playbook中定义Ansible when条件开始这个教程,其中包含多个任务。

1. 在Ansible控制器主机上打开终端。

2. 运行以下命令在您的主目录中创建一个目录,并将其命名为您喜欢的任何名称,并导航到该目录中。

在这个例子中,目录名为ansible_when_condition_demo。该目录将包含您将在Ansible任务中使用的playbook中的when条件。

# 创建一个名为~/ansible_when_condition_demo的目录
mkdir ~/ansible_when_condition_demo
# 将工作目录更改为~/ansible_when_condition_demo
cd ~/ansible_when_condition_demo

3. 在您喜欢的代码编辑器中,在~/ansible_when_condition_demo目录中创建一个YAML文件。在这个例子中,该文件被称为my_playbook.yml。复制并粘贴以下YAML playbook内容到my_playbook.yml文件中。

在下面的两个任务(Task-1Task-2)中,when条件检查每个远程主机所在的操作系统。然后将结果传递给每个任务中的ansible_os_family占位符变量。

如果ansible_os_family占位符的值等于RedHatDebian,那么Ansible将执行以下任务之一来安装Apache。

---
- name: Ansible tasks to work on Ansible When
# 定义Ansible将运行的远程服务器
  hosts: web
  remote_user: ubuntu # 将远程主机设置为ubuntu
  become: true # 以提升的用户身份运行任务(sudo)
  tasks:

# (任务1)检查ansible_os_family是否等于"RedHat",然后在远程节点上安装Apache
    - name: Install Apache on CentOS  Server
      yum: name=httpd  state=present
      become: yes
      when: ansible_os_family == "RedHat"

# (任务2)检查ansible_os_family是否等于"Debian",然后在远程节点上安装Apache
    - name: Install Apache on Ubuntu Server
      apt:name=apache2 state=present
      become: yes
      when: ansible_os_family == "Debian"

4. 现在运行下面的ansible-playbook命令,在现有清单文件中定义的远程主机上执行playbook(my_playbook.yml)中定义的任务。

ansible-playbook my_playbook.yml 

在下面的屏幕截图中,您可以看到:

  • 第一个任务返回了一个OK状态,表示该任务不需要进行任何更改。
  • 第二个任务返回了skipping状态。当条件不满足时,任务将被跳过。
  • 第三个任务返回了一个changed状态,表示远程主机不处于正确的状态(即Apache不存在),并且已被修改以安装Apache。
Invoking the ansible-playbook using ansible-playbook command

5. 使用您喜歡的 SSH 客戶端打開 SSH 會話,連接到 Ansible playbook 的目標遠程主機,以驗證 Apache 是否已安裝並運行。

6. 最後,執行以下service命令來驗證遠程主機上是否已安裝 Apache(status apache2)。

service status apache2

如下所示,您已在遠程機器上安裝了 Apache 服務。

Verifying the Apache service on the remote node

使用 Ansible 的 when 和循環

之前,您根據 Ansible 的 when 條件執行了 Ansible 任務,例如 ansible_os_family。但也許您需要檢查在列表中定義的多個參數的條件。如果是這樣,請嘗試在任務中添加一個 loop

打開之前創建的 my_playbook.yml 文件(在“在 Playbook 中使用 Ansible when 執行多個任務”下的第三步)。將 my_playbook.yml 文件的內容替換為以下代碼。

代碼中的任務(Task-1)運行一個 loop,其中 when 條件檢查項目值是否大於五並返回結果。

---
- name: Ansible tasks to work on Ansible When
# 定義 Ansible 將運行的遠程服務器
  hosts: web
  remote_user: ubuntu   # 使用遠程主機為 ubuntu
  become: true
  tasks:
  #(任務-1)檢查項目值是否大於 5
    - name: Run with items greater than 5
      ansible.builtin.command: echo {{ item }}
      loop: [ 0, 2, 4, 6, 8, 10 ]
      when: item > 5*

現在執行以下命令來執行 playbook,就像之前一樣。

 ansible-playbook my_playbook.yml

以下是當條件為false時返回的任務返回跳過狀態,而當條件為true時返回的已更改狀態。

Checking the when condition for multiple parameters

使用Ansible的when和Ansible的facts

也許您想要添加多個條件來執行任務。如果是這樣,請學習如何在when條件中使用Ansible facts。 Ansible facts允許您添加一個條件語句來根據收集到的事實執行任務,例如您的操作系統、IP地址、連接的文件系統等等。

my_playbook.yml文件的內容替換為下面的代碼。

在下面的代碼中,當以下任一條件為真時,兩個任務(Task-1Task-2)都只會執行(系統關機):

  • distributiondistribtion_major_version都返回true值。
  • os_family的值等於CentOS
---
- name: Ansible When Single task example
  hosts: web
  remote_user: ubuntu
  become: true
  tasks:
# (Task-1): 如果發行版是CentOS且主要版本為6,則關閉遠程節點
    - name: Shut down CentOS 6 systems
      ansible.builtin.command: /sbin/shutdown -t now
      when:
        - ansible_facts['distribution'] == "CentOS"
        - ansible_facts['distribution_major_version'] == "6"
# (Task-2): 如果os_family是CentOS,則關閉遠程節點
    - name: Shut down CentOS flavored systems
      ansible.builtin.command: /sbin/shutdown -t now
      when: ansible_facts['os_family'] == "CentOS"

像之前一樣使用下面的命令執行playbook。

ansible-playbook my_playbook.yml

請注意,由於您使用的是Ubuntu,所以下面的任務都顯示了跳過狀態。只有在CentOS時才執行該任務。

Executing the ansible-playbook with Ansible facts in Ansible when

使用基於已註冊值的Ansible when語句

有時候,您希望根據播放簿中先前任務的結果來執行或跳過一個任務。例如,您可能希望在先前任務升級後配置一個服務。在這種情況下,使用一個已註冊變量。已註冊變量允許您將先前任務的結果註冊為變量並將其作為下一個任務的輸入使用。

1. 創建一個名為/home/ubuntu/hello的空目錄。

2. 將my_playbook.yml文件的內容替換為下面的代碼,該代碼執行以下操作:

第一個任務(Task-1)將/etc/hosts目錄的內容(文件和子目錄)列在內存中,並通過register命令將該結果保存到contents1變量中。

第二個任務(Task-2)將/home/ubuntu/hello目錄的內容(目前為空)列在內存中,並將該列表保存到contents2變量中。

第三個任務(Task-3)檢查並打印“目錄為空”消息,如果contents1contents2變量的已註冊結果為空。

contents1contents2變量的stdout屬性是運行任務命令的結果保存的shell輸出。

---
- name: Ansible When Single task example
  hosts: web
  remote_user: ubuntu
  become: true
  tasks:
#(任務-1):列出 /etc/hosts 目錄中的內容
      - name: List contents of directory and Store in content1
        ansible.builtin.command: ls /etc/hosts
        register: contents1
#(任務-2):列出 /home/ubuntu/hello 目錄中的內容
      - name: List contents of directory and Store in content2
        ansible.builtin.command: ls /home/ubuntu/hello
        register: contents2
#(任務-3):如果 /etc/hosts 或 /home/ubuntu/hello 兩個目錄之中有任一個是空目錄,則顯示 "目錄是空的"
# /etc/hosts 或 /home/ubuntu/hello 是空目錄時,顯示 "目錄是空的"
      - name: Check contents for emptiness for content1 or content2
        ansible.builtin.debug:
          msg: "Directory is empty"
        when: contents1.stdout == "" or contents2.stdout == ""

3. 最後,使用下面的 ansible-playbook 命令執行 playbook。

ansible-playbook my_playbook.yml

如下所示,由於 contents2 變數的註冊結果是空的,第三個任務返回 “目錄是空的” 的訊息。

Running the Ansible playbook for Ansible when based on registered values

在 Ansible 角色中使用 Ansible when

在這個最後的例子中,您將學習如何在 Ansible 角色中使用 Ansible when。Ansible 角色允許您重複使用標準配置並更快地部署。繼續閱讀,了解只有當 Ansible when 條件為真時,任務才會調用 Ansible 角色的方法。

1. 執行以下命令在您的家目錄中創建一個名為 ~/ansible_role_when_demo 的目錄,並將其設置為工作目錄。 ~/ansible_role_when_demo 目錄將保存此示例的演示文件。

# 在您的家目錄中創建一個名為 ~/ansible_role_when_demo 的目錄
mkdir ~/ansible_role_when_demo
# 切換到 ~/ansible_role_when_demo 目錄
cd ~/ansible_role_when_demo

2. 接下來,執行以下命令來創建 ~/ansible_role_when_demo/roles~/ansible_role_when_demo/roles/java/tasks 目錄。

以下是每個目錄的內容:

  • ~/ansible_role_when_demo/roles 目錄將包含您需要部署的角色。

預設情況下,Ansible 在 playbook 所在目錄的 roles/ 目錄或 /etc/ansible/roles 目錄中尋找角色。如果您希望將角色存儲在其他路徑,可以在 playbook 中使用 - role: 參數聲明這些路徑

  • ~/ansible_role_when_demo/roles/java/tasks 文件夾將包含您需要部署角色的 main.yml 文件
# 在~/ansible_role_when_demo目錄下創建一個名為roles的目錄
mkdir -p roles
# 將當前工作目錄更改為~/ansible_role_when_demo/roles目錄
cd roles 
# 創建父目錄(-p)命名為java並創建一個名為tasks的子目錄
mkdir -p java/tasks

現在,在~/ansible_role_when_demo/roles/java/tasks目錄下創建一個名為main.yml的文件,然後將下面的playbook代碼複製並粘貼到main.yml文件中。

下面的playbook在遠程節點上使用apt模塊安裝Java。

---
# 安裝Java(Open Jdk)
- name: Install Java 1.8
  apt: name=openjdk-8-jdk

4. 創建一個您喜歡的名字的另一個YAML文件,並複製/粘貼下面的代碼。對於此示例,文件名為~/ansible_role_when_demo/java-setup.yml

下面的代碼將Ansible的rolejava)部署到僅當遠程用戶為Debian OS時具有管理訪問權限的遠程用戶(ubuntu)。

- name: Java Installation playbook
# 定義將部署套件的遠程服務器
  hosts: myserver
  remote_user: ubuntu   # 使用遠程用戶為ubuntu
  become: true
  tasks:  
  roles:
     - role: java
       # 只有在遠程用戶為Debian OS時執行該任務。
       when: ansible_facts['os_family'] == 'Debian'

5. 執行 tree 命令來驗證所有需要的資料夾和檔案是否存在於 ~/ansible_role_when_demo 目錄中。

Verifying all of the required folders in the ~/ansible_role_when_demo directory

6. 最後,使用下面的 ansible-playbook 命令執行 playbook。 ansible-playbook java-setup.yml

ansible-playbook java-setup.yml

下面的任務返回了一個 changed 狀態,表示已成功在遠程節點上安裝了 Java,因為該節點運行的是 Debian 作業系統。 使用 Ansible 角色和 Ansible when 執行 Ansible playbook

Running the Ansible playbook using Ansible when with Ansible roles

結論

在本教程中,您學習了使用 Ansible 的不同方式,包括使用 when 和其他條件語句。您還學習了如何應用 Ansible when 條件,從基本任務利用 Ansible facts 到部署 Ansible roles

現在,您可以如何在這個新獲得的知識基礎上進一步應用呢?也許可以在應用 Ansible when 條件的同時,使用 Ansible 模板節省配置多個伺服器的時間?

Source:
https://adamtheautomator.com/ansible-when/