在ansible的playbook中如果发现需要有很多task重复的引用某一个相同的模块时这个时候需要使用loops去编写playbook减少使用某个模块。
标准循环
标准循环关键字:”with_items:”
编写standerloop.yaml的playbook文件分别对远程主机打印one,two这两个值:
---
- gather_facts: Flase
hosts: all
tasks:
-
debug: "msg= \"name -----> {{ item }}\""
name: "debug loops"
with_items:
- one
- two
执行的结果如下:
with_items的值是python list数据结构,可以理解为每个task会循环读取list里面的值,然后key的名称是item,当然list里面也支持python字典形式:
---
- gather_facts: Flase
hosts: all
tasks:
-
debug: "msg=\"name -----> {{ item.key }} vaule -----> {{ item.vaule }}\""
name: "debug loops"
with_items:
- { key: "one", vaule: "VAULE1"}
- { key: "two", vaule: "VAULE2"}
执行结果如下:
嵌套循环
嵌套循环主要实现一对多,多对多的合并
---
-
hosts: all
gather_facts: False
tasks:
- name: debug loops
debug: "msg=\"name -----> {{ item[0] }} vaule -----> {{ item[1] }}\""
with_nested:
- ['Ansible']
- ['test1','test2','test3']
得到的结果如下:
散列loops(对哈希表进行循环)
标准的loop最外层必须是Python的list数据类型,而散列loops直接支持YAML格式的数据变量。散列的loops直接支持YAML格式的数据变量。使用with_dict来循环哈希表中的元素,with_dict是接收一个Python字典(经过yaml.load后)的格式变量:
---
-
hosts: all
gather_facts: False
vars:
user:
Bob_hou:
name: Bob_Hou
shell: bash
Jmilk:
name: Jmilk
shell: zsh
tasks:
-
name: debug loops
debug: "msg=\"name -----> {{item.key }} value -----> {{item.value.name }} shell -----> {{ item.value.shell }}\""
with_dict: "{{ user }}"
输出的结果为:
文件匹配loop
在编写playbook的时候需要针对文件进行操作中最常使用到的循环,例如我们需要对一个目录下指定格式的文件进行处理,这个时候我们直接使用with_fileglob循环去匹配我们需要处理的文件。例如我要寻找playbook中所有的yaml格式的剧本文件,于是编写一个如下的文件匹配循环:
---
-
hosts: all
gather_facts: False
tasks:
-
name: debug loops
debug: "msg=\"files -----> {{ item }}\""
with_fileglob:
-
/root/playbook/*.yaml
with_fileglob这个时候会匹配root/playbook目录下所有以yaml结尾的文件,当作{{ item }} 变量,运行的结果如下:
实际上文件循环是使用python glob模块去做文件模糊匹配:
>>> import glob
>>> print glob.glob('/root/playbook/*.yaml')
['/root/playbook/nginx-116.yaml', '/root/playbook/fileloop.yaml', '/root/playbook/var.yaml', '/root/playbook/standerloop.yaml', '/root/playbook/nestedloop.yaml', '/root/playbook/variable.yaml', '/root/playbook/nginx.yaml', '/root/playbook/hashloop.yaml']
随机选择loop
利用with_random_choice在传入的list中随机选择一个,与使用python random实现原理一样。它有时可以用作一个简化版的负载均衡器,比如作为条件判断。提供的字符串中的其中一个会被随机选中。
---
-
hosts: all
gather_facts: False
tasks:
-
name: debug loops
debug: "msg=\"name -----> {{ item }}\""
with_random_choice:
- "web"
- "devstack"
- "nginx"
执行的结果如下:
条件判断Loops
如我们执行一个task之后,我们想要检测这个task结果是否达到了预想状态,如果没有没有达到预想状态,我们就需要退出整个playbook执行,这个时候可以使用循环检测判断了。
---
-
hosts: all
gather_facts: False
tasks:
-
name: debug loops
shell: cat /root/ansible
register: host
until: host.stdout.startswith("cat")
retries: 5
delay: 5
每5秒执行一次cat /root/ansible结果,然后将结果交给register的host参数,然后判断host.stdout.startswith的内容是否是cat字符串开头,如果条件成立,此task运行完成,如果条件不成立5s后重试,5次还不成立,此task运行失败。这里我选用的目录就是一个假目录,所以最后执行结果会是失败的。
文件优先匹配
如果你想引用一个文件,而该文件是从一组文件中根据给定条件匹配出来的,你可以使用这种模式:
---
-
hosts: all
gather_facts: True
tasks:
-
name: debug loops
debug: "msg=\"files -----> {{item }}\""
with_first_found:
-
"{{ ansible_distribution }}.yaml"
-
"nginx.yaml"
with_first_found会从list里面定义的文件从上往下一个一个的匹配,如果匹配到了item就是该文件。输出结果如下:
register loops循环
register适用于task直接互相传递数据的,一般我们会把register用在单一的task中进行变量临时存储,其实register还可以同时接受多个task的结果当做变量临时存储:
---
-
hosts: all
gather_facts: True
tasks:
-
name: debug loops
shell: "{{ item }}"
with_items:
-
hostname
-
uname
register: ret
- name: display loops
debug: "msg=\"{% for i in ret.results %} {{ i.stdout }} {% endfor %}\""
输出结果如下: