Ansible系列基础篇 1.7.2、PlayBook之循环
一、循环定义
循环可迭代对象,重复处理每条信息。
基础示例:
--- - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "{{item}}" with_items: - 1 - 2 - 3 # 也可以 with_items: [1,2,3]
使用内置变量循环,示例如下:
--- - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "{{item}}" with_items: "{{groups.ungrouped}}"
复杂字段的循环,示例如下:
--- - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "{{item.test1}}" with_items: - { test1: a, test2: b } - { test1: c, test2: d }
循环结果的存储与读取,通过register,把模块执行的结果存储到变量中,命令的结果,以列表形式存在returnvalue.results,示例如下:
--- - hosts: test70 gather_facts: no tasks: - shell: "{{item}}" with_items: - "ls /opt" - "ls /home" register: returnvalue - debug: msg: "{{item.stdout}}" with_items: "{{returnvalue.results}}"
二、循环特殊关键字
2.1、with_list
当处理单层的简单列表时,with_list与with_items没有任何区别,只有在处理上例中的"嵌套列表"时,才会体现出区别,区别就是,with_items会将嵌套在内的小列表"拉平",拉平后循环处理所有元素,而with_list则不会"拉平"嵌套的列表,with_list只会循环的处理列表(最外层列表)中的每一项。
with_items的嵌套的列表(序列中的序列),示例如下:
# 结果为 1, 2, 3, a, b
# 每个循环的列表项,也展开
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
- debug:
msg: "{{item}}"
with_items:
- [ 1, 2, 3 ]
- [ a, b ]
使用with_list:
# 结果为 [1, 2, 3], [a, b]
# 外层列表循环,每个项的列表内容不循环
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
- debug:
msg: "{{item}}"
with_list:
- [ 1, 2, 3 ]
- [ a, b ]
2.2、with_flattened
该关键字与with_items效果完全相同
2.3、with_together
两列表一一对应聚合,示例如下:
# 结果为: [1, a], [2, b], [3, c] --- - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "{{ item }}" with_together: - [ 1, 2, 3 ] - [ a, b, c ]
如果两列表长度不一致,一一对应时,无数据的,用null补齐。
2.4、with_cartesian
示例需求:需要在目标主机的测试目录中创建a、b、c三个目录,这三个目录都有相同的子目录,它们都有test1和test2两个子目录。
linux命令实现:mkdir -p {a,b,c}/{test1,test2}
ansible实现,用到关键字 with_cartesian ,实现交叉循环,和笛卡尔乘积一样,示例如下:
代码结果:[a, test1], [a, test2], [b, test1], [b, test2], [c, test1], [c, test2]
--- - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "/testdir/testdir/{{ item.0 }}/{{ item.1 }}" with_cartesian: - [ a, b, c ] - [ test1, test2 ]
2.5、with_indexed_items
功能“:在循环处理列表时为列表中的每一项添加"数字索引","索引"从0开始。
代码结果: [0, test1], [1, test2], [2, test3]
--- - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "index is : {{ item.0 }} , value is {{ item.1 }}" with_indexed_items: - test1 - test2 - test3
多嵌套时,展开情况:
实例一,结果:[0, test1], [1, test2], [2, test3], [3, test4], [4, test5]
--- - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "index is : {{ item.0 }} , value is {{ item.1 }}" with_indexed_items: - [ test1, test2 ] - [ test3, test4, test5 ]
实例二,结果:[0, test1], [1, test2], [2, test3], [3, [test4, test5]]
当多加了一层嵌套以后,"with_indexed_items"并不能像"with_flattened"一样将嵌套的列表"完全拉平",第二层列表中的项如果仍然是一个列表,"with_indexed_items"则不会拉平这个列表,而是将其当做一个整体进行编号。
--- - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "{{ item }}" with_indexed_items: - [ test1, test2 ] - [ test3, [ test4, test5 ] ]
2.6、with_sequence
功能:按照数字递增\递减方式,进行循环。
实例结果:1, 2, 3, 4, 5
--- - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "{{ item }}" with_sequence: start=1 end=5 stride=1
下例中count=5表示数字序列默认从1开始,到5结束,默认步长为1,效果与上例相同。
--- - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "{{item}}" with_sequence: count=5
下例执行结果:6, 4 ,2
--- - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "{{item}}" with_sequence: start=6 end=2 stride=-2
格式化数据:
--- - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "{{item}}" with_sequence: start=2 end=6 stride=2 format="number is %0.2f"
2.7、with_random_choice
功能:从列表的多个值中随机返回一个值。
--- - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "{{item}}" with_random_choice: - 1 - 2 - 3 - 4 - 5
2.8、with_dict
--- - hosts: test70 remote_user: root gather_facts: no vars: users: alice: female bob: male tasks: - debug: msg: "{{item}}" with_dict: "{{users}}"
示例执行结果:
TASK [debug] *************************************
ok: [test70] => (item={'value': u'male', 'key': u'bob'}) => {
"changed": false,
"item": {
"key": "bob",
"value": "male"
},
"msg": {
"key": "bob",
"value": "male"
}
}
ok: [test70] => (item={'value': u'female', 'key': u'alice'}) => {
"changed": false,
"item": {
"key": "alice",
"value": "female"
},
"msg": {
"key": "alice",
"value": "female"
}
}
with_dict具体使用方式如下:
--- - hosts: test70 remote_user: root gather_facts: no vars: users: alice: female bob: male tasks: - debug: msg: "User name: {{item.key}} , User's gender: {{item.value}} " with_dict: "{{users}}"
2.9、with_subelements
处理一个像上例中一样的复合结构的字典数据,在处理这个字典的同时,需要指定一个子元素,这个子元素的值必须是一个列表,之后,"with_subelements"会将子元素的列表中的每一项作为一个整体,将其他子元素作为一个整体,然后将两个整体组合成item。
--- - hosts: test70 remote_user: root gather_facts: no vars: users: - name: bob gender: male hobby: - Skateboard - VideoGame - name: alice gender: female hobby: - Music tasks: - debug: msg: "{{ item }}" with_subelements: - "{{users}}" - hobby
执行结果:
TASK [debug] ***********************************************************
ok: [test70] => (item=({u'gender': u'male', u'name': u'bob'}, u'Skateboard')) => {
"changed": false,
"item": [
{
"gender": "male",
"name": "bob"
},
"Skateboard"
],
"msg": [
{
"gender": "male",
"name": "bob"
},
"Skateboard"
]
}
ok: [test70] => (item=({u'gender': u'male', u'name': u'bob'}, u'VideoGame')) => {
"changed": false,
"item": [
{
"gender": "male",
"name": "bob"
},
"VideoGame"
],
"msg": [
{
"gender": "male",
"name": "bob"
},
"VideoGame"
]
}
ok: [test70] => (item=({u'gender': u'female', u'name': u'alice'}, u'Music')) => {
"changed": false,
"item": [
{
"gender": "female",
"name": "alice"
},
"Music"
],
"msg": [
{
"gender": "female",
"name": "alice"
},
"Music"
]
}
--- - hosts: test70 remote_user: root gather_facts: no vars: users: - name: bob gender: male hobby: - Skateboard - VideoGame - name: alice gender: female hobby: - Music tasks: - debug: msg: "{{ item.0.name }} 's hobby is {{ item.1 }}" with_subelements: - "{{users}}" - hobby
执行结果:
"msg": "bob 's hobby is Skateboard"
"msg": "bob 's hobby is VideoGame"
"msg": "alice 's hobby is Music"
2.10、with_file
功能:获取到这些文件的内容。
--- - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "{{ item }}" with_file: - /testdir/testdir/a.log - /opt/testfile
2.11、with_fileglob
功能:匹配文件名称。
- 只会匹配指定目录中的文件,而不会匹配指定目录中的目录。
--- - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "{{ item }}" with_fileglob: - /testdir/*
# 这个列表中有两项,第一项表示匹配"/testdir"目录下的文件,第二项表示匹配"/opt"目录下,以"test"开头,以". 任意3个字符"结尾的文件,比如"testa.123"或者"testfile.yml" --- - hosts: test70 remote_user: root gather_facts: no tasks: - debug: msg: "{{ item }}" with_fileglob: - /testdir/* - /opt/test*.???