一.简述:
在使用ansible做配置管理工作中,经常会遇到很多的task都需要重复的引用某一个模块比如:一次同步N个文件,创建N个用户等,按照之前的文档来看就需要写N个task,尽管功能可以实现,但代码量会非常大/臃肿。对于这种情况,ansible是可以通过循环(loop)方式处理。
二.使用方式:
1. 标准loops(with_items):
应用环境比较常见,如同时copy 操作主机的aaaa和bbbb文件到被操作主机上:
---
- hosts: test
tasks:
- name: test
copy: src=/tmp/{{ item }} dest=/tmp/{{ item }}
with_items: #也可以直接写成- ['aaaa', 'bbbb']
- aaaa #同样,也支持变量(with_items: "{{somelist}}")
- bbbb
另外,with_items还支持python的字典类型:
tasks:
- name: test
debug: msg="{{ item.key }}======= {{ item.var }}"
with_items:
- {key: 'aaaa', var: 'bbbb'}
- {key: 'bbbb', var: 'cccc'}
2. 嵌套循环(with_nested):
主要实现一对多或者多对多的情况,如ab组合ac组合等:
tasks:
- name: test
debug: msg="{{ item[0] }}--{{ item[1] }}---{{ item[2] }}"
with_nested:
- ['aaaa', 'bbbb'] #同样支持变量
- ['cccc', 'dddd', 'eeee']
- ['ffff', 'gggg']
3. 数据并行循环(with_together):
如上面嵌套循环,with_together可以实现aaaa cccc ffff 并行的集合循环:
tasks:
- name: test
debug: msg="{{ item[0] }}--{{ item[1] }}---{{ item[2] }}"
with_together:
- ['aaaa', 'bbbb']
- ['cccc', 'dddd', 'eeee']
- ['ffff', 'gggg']
4. hash表循环(with_dict):
ansible1.5版本以上支持,主要针对hash结构的数据进行循环,这里套用官方的例子:
---
- hosts: test
vars:
users: #定义users变量
alice: #用户 名字 telephone
name: Alice Appleworth
telephone: 123-456-7890
bob:
name: Bob Bananarama
telephone: 987-654-3210
tasks:
- name: test #打印出每个用户的名字和电话
debug: msg="User {{ item.key }} is {{ item.value.name }} ({{ item.value.telephone }})"
with_dict: "{{ users }}"
变量也可直接定义为json格式:
- hosts: test
vars:
users: {"alice":{'name':'ace','telephone':'123-123'},"bob":{'name':'boe','telephone':'321-321'}}
可以通过with_subelements对子元素进行循环,参考http://docs.ansible.com/ansible/playbooks_loops.html
5. 文件列表循环(with_fileglob):
个人理解with_fileglob就是针对文件名进行匹配,然后进行操作:
tasks:
- name: test
debug: msg="file------>{{ item }}"
with_fileglob:
/tmp/a*.yaml #匹配/tmp/目录下以a开头yaml结尾的文件debug处理
其实就是使用python的glob模块模糊匹配(glob.glob('/tmp/a*.yaml'))
6. 整数循环(with_sequence):
可以针对一个数字范围安装升序进行循环,可以指定起始值、终止值,以及一个可选的递增值,数字值可以被指定为10进制,16进制(0x3f8)或者八进制(0600):
---
- hosts: all
tasks:
- bug: msg="file------user{{ item }}"
with_sequence: start=4 end=16 stride=2 #从4开始到16以2递增
- user: name=usertest{{ item }} state=present groups=evens #创建用户usertest(1到4)
with_sequence: count=4 #从1到4
7. 随机选择(with_random_choice):
类似于python的random模块功能,即从list中随机选择一个:
tasks:
- name: tes
debug: msg={{ item }}
with_random_choice:
- aa
- bbb
- ccc
8. 条件循环(until):
可判断循环的结果是否达到设置的条件,当达到时,结束循环,当未达到时,可设置循环的次数,及一次循环和下次循环的间隔时间,当达到循环次数还未达到设置的条件时,fatal failed退出:
tasks:
- name: tes
shell: tail -10 /var/log/messages
register: error
until: error.stdout.find('error') != -1 #检测结果是否包含‘error’信息,存在时(!=-1)退出循环
retries: 5 循环次数
delay: 3 间隔时间
9. 第一个匹配的文件(with_first_found):
这个参数跟上面文件循环的区别在于,只获取第一个匹配的文件,另外:不能使用通配符的匹配(如*):
tasks:
- name: tes
debug: msg={{ item }}
with_first_found: #匹配当前目录下或tmp目录下的dddd.yaml
- “dddd.yaml”
- "/tmp/dddd.yaml"
#还有一种可以指定路径的方式:
tasks:
- name: tes
debug: msg={{ item }}
with_first_found:
- files:
- "ddd.yaml"
- "dddd.yaml"
paths:
- /tmp
- /root
10. 循环中变量赋值:
之前已经了解过通过register可以在task直接进行赋值,register不仅可以用于单一的task中赋值临时存储,也支持接受多个task的结果作为变量临时存储,例如:
tasks:
- name: tes
shell: "{{ item }}" #循环执行hostnaem和uptime命令
with_items:
- hostname
- uptime
register: ret 然后将两者结果赋值给ret变量
- name: test
debug: msg="{% for i in ret.results %} --{{ i.stdout }} {% endfor %}" #打印变量结果
执行结果如下:
其他一些方法参考:http://docs.ansible.com/ansible/playbooks_loops.html
----------------------------------------------------------------------------------------------
深耕运维行业多年,擅长linux、容器云原生、运维自动化等方面。
承接各类运维环境部署、方案设计/实施、服务代运维工作,欢迎沟通交流 !