ansible笔记(12)之循环相关

ansible笔记(12)之循环相关

微信搜索 zze_coding 或扫描 👉 二维码关注我的微信公众号获取更多资源推送:

本来打算自己写一波 ansible 系列的,后来发现一老哥写的太好了,「点击此处直达」,我这里也就边看边对该系列文章做下笔记,方便以后查阅,ansible 入门的话墙裂建议阅读前方链接博文~~~

with_items

with_items 用来进行遍历操作,当要遍历的对象是嵌套结构时,仅会遍历前两层的子元素。

例 1:循环输出 groupall 组中的所有主机别名。

---
- hosts: B
  gather_facts: no
  tasks:
  - debug:
      msg: "{{item}}"
    with_items: {{groups.grouall}}

结果如下:

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [debug] **************************************************************************************************************************
ok: [B] => (item=B) => {
    "msg": "B"
}
ok: [B] => (item=C) => {
    "msg": "C"
}

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

例 2:循环列表。

---
- hosts: B
  gather_facts: no
  tasks:
  - debug:
      msg: "{{item}}"
    with_items:
    - 1
    - 2
    - 3
    # 这里的列表也可写成: with_items: [ 1, 2, 3 ]

结果如下:

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [debug] **************************************************************************************************************************
ok: [B] => (item=1) => {
    "msg": 1
}
ok: [B] => (item=2) => {
    "msg": 2
}
ok: [B] => (item=3) => {
    "msg": 3
}

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

例 3:循环对象。

---
- hosts: B
  gather_facts: no
  tasks:
  - debug:
      msg: "{{item.test1}}"
    with_items:
    - { test1: a, test2: b }
    - { test1: c, test2: d }

结果如下:

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [debug] **************************************************************************************************************************
ok: [B] => (item={u'test1': u'a', u'test2': u'b'}) => {
    "msg": "a"
}
ok: [B] => (item={u'test1': u'c', u'test2': u'd'}) => {
    "msg": "c"
}

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

例 4:在客户机创建 /opt/{a,b,c,d} 文件夹。

---
- hosts: B
  gather_facts: no
  vars:
    dirs:
    - "/opt/a"
    - "/opt/b"
    - "/opt/c"
    - "/opt/d"
  tasks:
  - file:
      path: "{{item}}"
      state: directory
    with_items: "{{dirs}}"

例 5:循环嵌套列表。

---
- hosts: B
  gather_facts: no
  tasks:
  - debug:
      var: item
    with_items:
    - [ a, b, [ c, d ] ]
    - [ 1, 2 ]

结果如下:

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [debug] **************************************************************************************************************************
ok: [B] => (item=a) => {
    "ansible_loop_var": "item", 
    "item": "a"
}
ok: [B] => (item=b) => {
    "ansible_loop_var": "item", 
    "item": "b"
}
ok: [B] => (item=[u'c', u'd']) => {
    "ansible_loop_var": "item", 
    "item": [
        "c", 
        "d"
    ]
}
ok: [B] => (item=1) => {
    "ansible_loop_var": "item", 
    "item": 1
}
ok: [B] => (item=2) => {
    "ansible_loop_var": "item", 
    "item": 2
}

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  

with_flattened

with_flattenedwith_item 不同的是,不管嵌套结构有多少层,它都会直接遍历所有子元素。

看如下示例:

---
- hosts: B
  gather_facts: no
  tasks:
  - debug:
      var: item
    with_flattened:
    - [ a, b, [ c, d ] ]
    - [ 1, 2 ]

结果如下:

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [debug] **************************************************************************************************************************
ok: [B] => (item=a) => {
    "ansible_loop_var": "item", 
    "item": "a"
}
ok: [B] => (item=b) => {
    "ansible_loop_var": "item", 
    "item": "b"
}
ok: [B] => (item=c) => {
    "ansible_loop_var": "item", 
    "item": "c"
}
ok: [B] => (item=d) => {
    "ansible_loop_var": "item", 
    "item": "d"
}
ok: [B] => (item=1) => {
    "ansible_loop_var": "item", 
    "item": 1
}
ok: [B] => (item=2) => {
    "ansible_loop_var": "item", 
    "item": 2
}

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

with_list

with_list 遍历嵌套列表时仅会输出第一层元素,遍历单层结构的对象时效果与 with_item 相同。

例:循环嵌套列表。

---
- hosts: B
  gather_facts: no
  tasks:
  - debug:
      var: item
    with_list: 
      - ['a','b']
      - [1,2]

结果如下:

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [debug] **************************************************************************************************************************
ok: [B] => (item=[u'a', u'b']) => {
    "ansible_loop_var": "item", 
    "item": [
        "a", 
        "b"
    ]
}
ok: [B] => (item=[1, 2]) => {
    "ansible_loop_var": "item", 
    "item": [
        1, 
        2
    ]
}

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

with_together

with_together 可用来对齐合并多个列表的元素,当列表长度不一致时,空缺位用 null 补充。
看如下示例:

---
- hosts: B
  gather_facts: no
  tasks:
  - debug:
      var: item
    with_together:
    - [ 1, 2, 3, 4]
    - [ a, b, c ]

结果如下:

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [debug] **************************************************************************************************************************
ok: [B] => (item=[1, u'a']) => {
    "ansible_loop_var": "item", 
    "item": [
        1, 
        "a"
    ]
}
ok: [B] => (item=[2, u'b']) => {
    "ansible_loop_var": "item", 
    "item": [
        2, 
        "b"
    ]
}
ok: [B] => (item=[3, u'c']) => {
    "ansible_loop_var": "item", 
    "item": [
        3, 
        "c"
    ]
}
ok: [B] => (item=[4, None]) => {
    "ansible_loop_var": "item", 
    "item": [
        4, 
        null
    ]
}

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  

with_cartesian

with_cartesian 可以将多个列表做笛卡尔积形式的组合,with_nested 的效果与它相同。

例:在客户机 /opt 目录下创建此结构的目录:mkdir {a,b,c}/{1,2,3} -p

---
- hosts: B
  gather_facts: no
  tasks:
  - file:
      path: "/opt/{{item.0}}/{{item.1}}"
      state: directory
    with_cartesian:
    - [ a, b, c ]
    - [ 1, 2, 3 ]

效果如下:

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [file] ***************************************************************************************************************************
changed: [B] => (item=[u'a', 1])
changed: [B] => (item=[u'a', 2])
changed: [B] => (item=[u'a', 3])
changed: [B] => (item=[u'b', 1])
changed: [B] => (item=[u'b', 2])
changed: [B] => (item=[u'b', 3])
changed: [B] => (item=[u'c', 1])
changed: [B] => (item=[u'c', 2])
changed: [B] => (item=[u'c', 3])

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

with_indexed_items

with_indexed_items 的作用就是在循环处理列表时为列表中的每一项添加数字索引,当要遍历的对象为嵌套结构时,同 with_item 相同仅会遍历到第二层的每一个子元素。

看如下示例:

---
- hosts: B
  gather_facts: no
  tasks:
  - debug:
      var: item
    with_indexed_items:
    - [ a, b ]
    - [ 1, 2 ]

效果如下:

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [debug] **************************************************************************************************************************
ok: [B] => (item=[0, u'a']) => {
    "ansible_loop_var": "item", 
    "item": [
        0, 
        "a"
    ]
}
ok: [B] => (item=[1, u'b']) => {
    "ansible_loop_var": "item", 
    "item": [
        1, 
        "b"
    ]
}
ok: [B] => (item=[2, 1]) => {
    "ansible_loop_var": "item", 
    "item": [
        2, 
        1
    ]
}
ok: [B] => (item=[3, 2]) => {
    "ansible_loop_var": "item", 
    "item": [
        3, 
        2
    ]
}

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

with_sequence

with_sequence 可以用来创建一个遍历的数据源,类似于 Python 中的 range 函数。

例 1:在客户机的 /opt 目录下这些文件:touch test{2,4,6,8,10}

---
- hosts: B
  gather_facts: no
  tasks:
  - file:
      path: /opt/test{{item}}
      state: touch
    with_sequence: start=2 end=10 stride=2
# start:起始值 end:结束值 stride:步长

也可使用此格式:
# with_sequence:
#    start=2
#    end=10
#    stride=2

结果如下:

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [file] ***************************************************************************************************************************
changed: [B] => (item=2)
changed: [B] => (item=4)
changed: [B] => (item=6)
changed: [B] => (item=8)
changed: [B] => (item=10)

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

例 2:输出 1 ~ 5 之间的数字。

---
- hosts: B
  gather_facts: no
  tasks:
  - debug:
      var: item
    with_sequence: count=5
# count 可用来输出连续的序列,默认步长为 1,起始值为 1。

效果如下:

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [debug] **************************************************************************************************************************
ok: [B] => (item=1) => {
    "ansible_loop_var": "item", 
    "item": "1"
}
ok: [B] => (item=2) => {
    "ansible_loop_var": "item", 
    "item": "2"
}
ok: [B] => (item=3) => {
    "ansible_loop_var": "item", 
    "item": "3"
}
ok: [B] => (item=4) => {
    "ansible_loop_var": "item", 
    "item": "4"
}
ok: [B] => (item=5) => {
    "ansible_loop_var": "item", 
    "item": "5"
}

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

例 3:输出 1 ~ 5 之间的数字并保留两位小数。

---
- hosts: B
  gather_facts: no
  tasks:
  - debug:
      var: item
    with_sequence: count=5 format="number is %0.2f"
# format 是一个格式化参数,使用类似于 C 语言中的 printf 函数。

效果如下:

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [debug] **************************************************************************************************************************
ok: [B] => (item=number is 1.00) => {
    "ansible_loop_var": "item", 
    "item": "number is 1.00"
}
ok: [B] => (item=number is 2.00) => {
    "ansible_loop_var": "item", 
    "item": "number is 2.00"
}
ok: [B] => (item=number is 3.00) => {
    "ansible_loop_var": "item", 
    "item": "number is 3.00"
}
ok: [B] => (item=number is 4.00) => {
    "ansible_loop_var": "item", 
    "item": "number is 4.00"
}
ok: [B] => (item=number is 5.00) => {
    "ansible_loop_var": "item", 
    "item": "number is 5.00"
}

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

with_random_choice

使用 with_random_choice 可以从列表的多个值中随机返回一个值。
看如下示例:

---
- hosts: B
  gather_facts: no
  tasks:
  - debug:
      var: item
    with_random_choice:
    - 1
    - 2
    - 3
    - 4
    - 5

效果如下:

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [debug] **************************************************************************************************************************
ok: [B] => (item=5) => {
    "ansible_loop_var": "item", 
    "item": 5
}

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [debug] **************************************************************************************************************************
ok: [B] => (item=2) => {
    "ansible_loop_var": "item", 
    "item": 2
}

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  

with_dict

with_dict 用来以字典的形式遍历对象,遍历对象的属性名将保存在 key 变量中,属性值将保存在 value 变量中。

看如下示例:

---
- hosts: B
  gather_facts: no
  vars:
    users:
      alice: female
      bob: male
  tasks:
  - debug:
      var: item
    with_dict: "{{users}}"

结果如下:

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [debug] **************************************************************************************************************************
ok: [B] => (item={'value': u'male', 'key': u'bob'}) => {
    "ansible_loop_var": "item", 
    "item": {
        "key": "bob", 
        "value": "male"
    }
}
ok: [B] => (item={'value': u'female', 'key': u'alice'}) => {
    "ansible_loop_var": "item", 
    "item": {
        "key": "alice", 
        "value": "female"
    }
}

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

with_subelements

with_subelements 能够遍历对象中指定序列的每一项,并把对象的其它部分作为一个整体,用每一项与对象的其它部分做组合。

看下面示例:

---
- hosts: B
  gather_facts: no
  vars:
    users:
    - name: bob
      hobby:
        - Skateboard
        - VideoGame
    - name: alice
      hobby:
        - Music
  tasks:
  - debug:
      var: item
    with_subelements:
    - "{{users}}"
    - hobby

结果如下:

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [debug] **************************************************************************************************************************
ok: [B] => (item=[{u'name': u'bob'}, u'Skateboard']) => {
    "ansible_loop_var": "item", 
    "item": [
        {
            "name": "bob"
        }, 
        "Skateboard"
    ]
}
ok: [B] => (item=[{u'name': u'bob'}, u'VideoGame']) => {
    "ansible_loop_var": "item", 
    "item": [
        {
            "name": "bob"
        }, 
        "VideoGame"
    ]
}
ok: [B] => (item=[{u'name': u'alice'}, u'Music']) => {
    "ansible_loop_var": "item", 
    "item": [
        {
            "name": "alice"
        }, 
        "Music"
    ]
}

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

with_file

with_file 可以用来遍历指定文件路径列表中每一个文件的内容,这个文件列表路径是 ansible 管理机本地的文件路径,文件路径不支持 glob 通配符。

看下面示例:

---
- hosts: B
  remote_user: root
  gather_facts: no
  tasks:
  - debug:
      var: item
    with_file:
    - file_a
    - file_b

结果如下:

$ cat file_a 
in file a

$ cat file_b
in file b

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [debug] **************************************************************************************************************************
ok: [B] => (item=in file a) => {
    "ansible_loop_var": "item", 
    "item": "in file a"
}
ok: [B] => (item=in file b) => {
    "ansible_loop_var": "item", 
    "item": "in file b"
}

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

with_fileglob

with_fileglob 可以用来遍历指定文件路径列表中每一个文件的内容,这个文件列表路径是 ansible 管理机本地的文件路径,文件路径支持 glob 通配符。

看下面示例:

---
- hosts: B
  remote_user: root
  gather_facts: no
  tasks:
  - debug:
      var: item
    with_fileglob:
    - /opt/file_*

结果如下:

$ cat /opt/file_a 
in /opt/file a

$ cat /opt/file_b
in /opt/file b

$ ansible-playbook test.yml 

PLAY [B] ******************************************************************************************************************************

TASK [debug] **************************************************************************************************************************
ok: [B] => (item=/opt/file_a) => {
    "ansible_loop_var": "item", 
    "item": "/opt/file_a"
}
ok: [B] => (item=/opt/file_b) => {
    "ansible_loop_var": "item", 
    "item": "/opt/file_b"
}

PLAY RECAP ****************************************************************************************************************************
B                          : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://www.zze.xyz/archives/ansible12.html

Buy me a cup of coffee ☕.