天天看點

ansible playbook loop 翻譯

ansible 官方文檔翻譯 playbook loop部分

ansible源文檔位址

有時候你想多次重複一個任務。 在計算機程式設計中,這叫做循環。 常見的 Ansible 循環包括使用檔案子產品更改幾個檔案和 / 或目錄的所有權,使用使用者子產品建立多個使用者,并重複一個輪詢步驟,直到達到某個結果。 為建立循環提供了兩個關鍵字:

loop

with_<lookup>

注意

  • 我們增加在Ansible2.5版本中中加了

    loop

    。它還沒有完全取代

    with_<lookup>

    , 但我們推薦在大多數場景下使用它。
  • 我們并舍棄

    with_<lookup>

    用法--在可預見的未來,這種文法仍然有效。
  • 我們正在尋求改進

    loop

    文法,關注這個頁面和changelog 來擷取更新。

目錄

  • 對比 loop and with_*
  • 标準loop
    • 周遊一個簡單的清單
    • 周遊哈希清單
    • 周遊字典
  • 用循環注冊變量
  • 複雜的loops
    • 周遊嵌套清單
    • 嘗試一個任務知道滿足條件為止
    • 主機清單的循環
  • 使用query或lookup確定清單輸入
  • 為loops添加控制
    • 用label限制loop輸出
    • loop中的暫停
    • 通過index_var跟蹤進度
    • 通過loop_var定義内部和外部變量名
    • 擴充loop變量
    • 通路loop_var
  • 從 with_X 遷移到 loop
    • with_list
    • with_items
    • with_indexed_items
    • with_flattened
    • with_together
    • with_dict
    • with_sequence
    • with_subelements
    • with_nested/with_cartesian
    • with_random_choice

對比

loop

and

with_*

  • with_

    關鍵字依賴Lookup Plugins插件--盡管

    item

    也是一個lookup插件。
  • loop

    關鍵字等價于

    with_list

    ,是使用簡單周遊時的最佳選擇。
  • loop

    關鍵字不再接收一個字元串作為輸入,檢視 Ensuring list input for loop: query vs. lookup
  • 通常來說,任何包含在 從with_X遷移到loop中的

    with_*

    用法都可以替換成

    loop

  • 需要注意的是,在将

    with_items

    替換成

    loop

    時,由于

    with_items

    執行單層隐式扁平化周遊,在使用

    loop

    作為輸出時,你需要結合

    flatten(1)

    一起使用。舉例說明,下面兩種方式的輸出結果相同:
with_items:
  - 1
  - [2,3]
  - 4
           

你需要像這樣使用:

loop: "{{ [1, [2,3] ,4] | flatten(1) }}"
           
  • 任何依賴

    lookup

    插件的

    with_*

    語句不應該被轉換成

    loop

    關鍵字。舉例說明,不建議使用下面的場景:
loop: "{{ lookup('fileglob', '*.txt', wantlist=True) }}"
           

保持這樣的格式會更簡潔。

with_fileglob: '*.txt'
           

标準loop

周遊一個簡單的清單

重複的任務可以通過簡單的字元串清單寫成标準的

loop

形式。你可以在任務裡使用清單:

- name: add several users
  user:
    name: "{{ item }}"
    state: present
    groups: "wheel"
  loop:
     - testuser1
     - testuser2
           

你可以使用一個變量檔案或者在你的劇本中使用

var

定義清單,然後在任務裡通過清單名稱引用即可:

loop: "{{ somelist }}"
           

上面例子中的任何一個都相當于:

- name: add user testuser1
  user:
    name: "testuser1"
    state: present
    groups: "wheel"

- name: add user testuser2
  user:
    name: "testuser2"
    state: present
    groups: "wheel"
           

您可以直接将清單傳遞給某些插件作為參數。 大多數打包子產品如 yum 包管理器和apt包管理器都具有這種功能。 如果可用,将清單傳遞給參數要比在任務上循環要好。 例如:

- name: optimal yum
  yum:
    name: "{{  list_of_packages  }}"
    state: present

- name: non-optimal yum, slower and may cause issues with interdependencies
  yum:
    name: "{{  item  }}"
    state: present
  loop: "{{  list_of_packages  }}"
           

檢視 子產品文檔 ,看看是否可以将清單傳遞給任何特定子產品的參數。

周遊哈希清單

如果你有一個哈希清單,你可以在循環中引用子鍵。例如:

- name: add several users
  user:
    name: "{{ item.name }}"
    state: present
    groups: "{{ item.groups }}"
  loop:
    - { name: 'testuser1', groups: 'wheel' }
    - { name: 'testuser2', groups: 'root' }
           

當将條件句與循環結合時,

When

語句将為每個項分别處理。 有關示例,請參見 When 語句。

周遊字典

若要周遊字典, 請使用

dict2items

字典過濾器:

- name: create a tag dictionary of non-empty tags
  set_fact:
    tags_dict: "{{ (tags_dict|default({}))|combine({item.key: item.value}) }}"
  loop: "{{ tags|dict2items }}"
  vars:
    tags:
      Environment: dev
      Application: payment
      Another: "{{ doesnotexist|default() }}"
  when: item.value != ""
           

在這裡,我們不想設定空标記,是以我們建立了一個隻包含非空标記的字典。

用循環注冊變量

你可以将

loop

的輸出注冊為變量,例如:

- shell: "echo {{ item }}"
  loop:
    - "one"
    - "two"
  register: echo
           

當使用循環注冊時,放置在變量中的資料結構将包含一個 results 屬性,該屬性是來自子產品的所有響應的清單。 這與直接注冊而不循環時傳回的資料結構不同:

{
    "changed": true,
    "msg": "All items completed",
    "results": [
        {
            "changed": true,
            "cmd": "echo \"one\" ",
            "delta": "0:00:00.003110",
            "end": "2013-12-19 12:00:05.187153",
            "invocation": {
                "module_args": "echo \"one\"",
                "module_name": "shell"
            },
            "item": "one",
            "rc": 0,
            "start": "2013-12-19 12:00:05.184043",
            "stderr": "",
            "stdout": "one"
        },
        {
            "changed": true,
            "cmd": "echo \"two\" ",
            "delta": "0:00:00.002920",
            "end": "2013-12-19 12:00:05.245502",
            "invocation": {
                "module_args": "echo \"two\"",
                "module_name": "shell"
            },
            "item": "two",
            "rc": 0,
            "start": "2013-12-19 12:00:05.242582",
            "stderr": "",
            "stdout": "two"
        }
    ]
}
           

對注冊變量進行後續循環以檢查結果如下所示:

- name: Fail if return code is not 0
  fail:
    msg: "The command ({{ item.cmd }}) did not have a 0 return code"
  when: item.rc != 0
  loop: "{{ echo.results }}"
           

在疊代過程中,目前項的結果将被放置在變量中:

- shell: echo "{{ item }}"
  loop:
    - one
    - two
  register: echo
  changed_when: echo.stdout != "one"
           

複雜的loops

周遊嵌套清單

你可以使用 Jinja2表達式來周遊複雜的清單,例如,循環可以組合嵌套的清單:

- name: give users access to multiple databases
  mysql_user:
    name: "{{ item[0] }}"
    priv: "{{ item[1] }}.*:ALL"
    append_privs: yes
    password: "foo"
  loop: "{{ ['alice', 'bob'] | product(['clientdb', 'employeedb', 'providerdb'])|list }}"
           

嘗試一個任務知道滿足條件為止

在 1.4版本中引入

你可以使用 until 關鍵字重試一個任務,直到滿足某個條件為止:

- shell: /usr/bin/foo
  register: result
  until: result.stdout.find("all systems go") != -1
  retries: 5
  delay: 10
           

此任務最多運作5次,每次嘗試之間延遲10秒。 如果任何嘗試的結果在其标準輸出中具有“ all systems go” ,則任務成功。 “ retries”的預設值為3,“ delay”為5。

若要檢視單個重試的結果,請使用

-vv

運作此劇本。

當您使用 until 運作任務并将結果注冊為變量時,注冊的變量将包含一個名為“ attempts”的鍵,該鍵記錄任務的重試次數。

注意

如果要重試任務,則必須設定 until 參數。 如果沒有定義 until,則強制重試參數的值為1。

主機清單的循環

為了周遊你的主機清單,或者僅僅是主機清單的一個子集,你可以使用一個正常的循環來周遊可以播放的批處理或者分組變量:

# show all the hosts in the inventory
- debug:
    msg: "{{ item }}"
  loop: "{{ groups['all'] }}"

# show all the hosts in the current play
- debug:
    msg: "{{ item }}"
  loop: "{{ ansible_play_batch }}"
           

還有一個特定的查找插件主機清單中主機名,可以這樣使用:

# show all the hosts in the inventory
- debug:
    msg: "{{ item }}"
  loop: "{{ query('inventory_hostnames', 'all') }}"

# show all the hosts matching the pattern, ie all but the group www
- debug:
    msg: "{{ item }}"
  loop: "{{ query('inventory_hostnames', 'all:!www') }}"
           

關于更多資訊可以在模式中找到目标主機群組。

使用

query

lookup

確定清單輸入

Loop 關鍵字需要一個清單作為輸入,但是 lookup 關鍵字預設傳回一個逗号分隔值字元串。 2.5引入了一個新的 Jinja2函數,命名為調用查找插件,它總是傳回一個清單,當使用 loop 關鍵字時,它提供了一個更簡單的界面和更可預測的查找插件輸出。

您可以使用

wantlist=true

強制查找傳回一個要循環的清單,或者您可以改用 query。

這些例子做了同樣的事情:

loop: "{{ query('inventory_hostnames', 'all') }}"

loop: "{{ lookup('inventory_hostnames', 'all', wantlist=True) }}"
           

為loops添加控制

在 2.1版本中引入

loop_control 關鍵字可以讓您以有用的方式管理循環。

用label限制loop輸出

在 2.2版本中引入

當循環周遊複雜的資料結構時,任務的控制台輸出可能是巨大的。 要限制顯示的輸出,使用循環控制的 label 指令:

- name: create servers
  digital_ocean:
    name: "{{ item.name }}"
    state: present
  loop:
    - name: server1
      disks: 3gb
      ram: 15Gb
      network:
        nic01: 100Gb
        nic02: 10Gb
        ...
  loop_control:
    label: "{{ item.name }}"
           

此任務的輸出将僅顯示每個項的 name 字段,而不是多行

{{ item }}

變量的全部内容。

注意

這是為了使控制台輸出更具可讀性,而不是保護敏感資料。 如果循環中有敏感資料,請在任務上設定

no_log: yes

以防止洩露。

loop中的暫停

在 2.2版本中引入

若要控制任務循環中每個項目執行之間的時間(以秒為機關) ,請使用帶循環控制的 pause 指令

loop_control

:

# main.yml
- name: create servers, pause 3s before creating next
  digital_ocean:
    name: "{{ item }}"
    state: present
  loop:
    - server1
    - server2
  loop_control:
    pause: 3
           

通過

index_var

跟蹤進度

在 2.5版本中引入

若要跟蹤您在循環中的位置,請使用

index_var

指令和

loop_control

。 這個指令指定一個包含目前循環索引的變量名:

- name: count our fruit
  debug:
    msg: "{{ item }} with index {{ my_idx }}"
  loop:
    - apple
    - banana
    - pear
  loop_control:
    index_var: my_idx
           

通過

loop_var

定義内部和外部變量名

在 2.1版本中引入

可以使用 include 任務嵌套兩個循環任務。 但是,預設情況下,Ansible 為每個循環設定循環變量項。 這意味着内部的嵌套循環将覆寫外部循環中 item 的值。 您可以使用

loop_var

loop_control

為每個循環指定變量的名稱:

# main.yml
- include_tasks: inner.yml
  loop:
    - 1
    - 2
    - 3
  loop_control:
    loop_var: outer_item

# inner.yml
- debug:
    msg: "outer item={{ outer_item }} inner item={{ item }}"
  loop:
    - a
    - b
    - c
           

注意

如果 Ansible 檢測到目前循環正在使用一個已經定義的變量,它将引發一個錯誤以使任務失敗。

擴充loop變量

在 2.8 版本中引入

從 ansible 2.8開始,你可以使用擴充選項來獲得擴充循環資訊來進行循環控制。 此選項将公開以下資訊。

Variable Description

ansible_loop.allitems

循環中所有項的清單

ansible_loop.index

循環的目前疊代的索引。(索引從1開始)

ansible_loop.index0

循環的目前疊代的索引。(索引從0開始)

ansible_loop.revindex

倒序循環的目前疊代的索引。(索引到1結束)

ansible_loop.revindex0

倒序循環的目前疊代的索引。(索引到0結束)

ansible_loop.first

如果第一次疊代則為True,否則是False

ansible_loop.last

如果最後一次疊代則為True,否則是False

ansible_loop.length

循環中的項數

ansible_loop.previtem

循環上一次疊代中的項。在第一次疊代中這個變量未定義

ansible_loop.nextitem

循環下一次疊代中的項。在最後一次疊代中這個變量未定義
loop_control:
  extended: yes
           

通路loop_var

在 2.8 版本中引入

從 ansible2.8你可以得到提供的值的名稱循環控制。循環變量使用安塞循環變量

對于角色作者,編寫允許循環的角色,而不是口述所需的循環變量值,您可以通過以下方式收集該值:

"{{ lookup('vars', ansible_loop_var) }}"
           

從 with_X 遷移到 loop

随着 Ansible 2.5的釋出,推薦的循環執行方式是使用新的 loop 關鍵字,而不是使用

with_x

樣式的循環。

在許多情況下,循環文法更好地使用過濾器,而不是更複雜地使用

query

或者

lookup

下面的示例将展示如何将許多常見的樣式循環轉換為循環和過濾器。

with_list

with_list

loop

替換。

- name: with_list
  debug:
    msg: "{{ item }}"
  with_list:
    - one
    - two

- name: with_list -> loop
  debug:
    msg: "{{ item }}"
  loop:
    - one
    - two
           

with_items

with_items

loop

flatten

過濾器替換。

- name: with_items
  debug:
    msg: "{{ item }}"
  with_items: "{{ items }}"

- name: with_items -> loop
  debug:
    msg: "{{ item }}"
  loop: "{{ items|flatten(levels=1) }}"
           

with_indexed_items

with_indexed_items

loop

,

flatten

過濾器 和

loop_control.index_var

替換。

- name: with_indexed_items
  debug:
    msg: "{{ item.0 }} - {{ item.1 }}"
  with_indexed_items: "{{ items }}"

- name: with_indexed_items -> loop
  debug:
    msg: "{{ index }} - {{ item }}"
  loop: "{{ items|flatten(levels=1) }}"
  loop_control:
    index_var: index
           

with_flattened

with_flattened

loop

flatten

過濾器替換。

- name: with_flattened
  debug:
    msg: "{{ item }}"
  with_flattened: "{{ items }}"

- name: with_flattened -> loop
  debug:
    msg: "{{ item }}"
  loop: "{{ items|flatten }}"
           

with_together

with_together

loop

zip

過濾器替換。

- name: with_together
  debug:
    msg: "{{ item.0 }} - {{ item.1 }}"
  with_together:
    - "{{ list_one }}"
    - "{{ list_two }}"

- name: with_together -> loop
  debug:
    msg: "{{ item.0 }} - {{ item.1 }}"
  loop: "{{ list_one|zip(list_two)|list }}"
           

with_dict

with_dict

loop

dictsort

或者

dict2items

過濾器替換。

- name: with_dict
  debug:
    msg: "{{ item.key }} - {{ item.value }}"
  with_dict: "{{ dictionary }}"

- name: with_dict -> loop (option 1)
  debug:
    msg: "{{ item.key }} - {{ item.value }}"
  loop: "{{ dictionary|dict2items }}"

- name: with_dict -> loop (option 2)
  debug:
    msg: "{{ item.0 }} - {{ item.1 }}"
  loop: "{{ dictionary|dictsort }}"
           

with_sequence

with_sequence

loop

range

函數,

format

過濾器替換。

- name: with_sequence
  debug:
    msg: "{{ item }}"
  with_sequence: start=0 end=4 stride=2 format=testuser%02x

- name: with_sequence -> loop
  debug:
    msg: "{{ 'testuser%02x' | format(item) }}"
  # range is exclusive of the end point
  loop: "{{ range(0, 4 + 1, 2)|list }}"
           

with_subelements

用循環和子元素過濾器代替子元素過濾器。

- name: with_subelements
  debug:
    msg: "{{ item.0.name }} - {{ item.1 }}"
  with_subelements:
    - "{{ users }}"
    - mysql.hosts

- name: with_subelements -> loop
  debug:
    msg: "{{ item.0.name }} - {{ item.1 }}"
  loop: "{{ users|subelements('mysql.hosts') }}"
           

with_nested/with_cartesian

with_nested

with_cartesian

loop

product

過濾器替換。

- name: with_nested
  debug:
    msg: "{{ item.0 }} - {{ item.1 }}"
  with_nested:
    - "{{ list_one }}"
    - "{{ list_two }}"

- name: with_nested -> loop
  debug:
    msg: "{{ item.0 }} - {{ item.1 }}"
  loop: "{{ list_one|product(list_two)|list }}"
           

with_random_choice

with_random_choice

random

過濾器替換,不在需要

loop

- name: with_random_choice
  debug:
    msg: "{{ item }}"
  with_random_choice: "{{ my_list }}"

- name: with_random_choice -> loop (No loop is needed here)
  debug:
    msg: "{{ my_list|random }}"
  tags: random