概述
Ansible 提供loop
、with_<lookup>
和until
关键字来多次执行任务。重复轮询步骤直到达到特定结果,达到简化playbook的目的。比如创建多个用户,修改多个文件、目录的权限。
loop在ansible2.5被引入。大多数情况下建议使loop,但是目前loop还不能完全替代with_*。
loopup、with_*
lookup和with_*的比较
- with_<lookup>的<lookup>填什么内容?取决于你要是用什么lookup plugins,其实这里的<lookup>是填写插件名称。例如with_items,items就是一个lookup plugin。可以用以下命令查找可用插件和插件相关文档:
查看可用lookup plugins列表:ansible-doc -t lookup -l
查看lookup plugins帮助文档:ansible-doc -t lookup {lookup plugin name}
- loop等同于with_list。是简单循环的最佳选择。
- loop只接受列表的输入,不支持字符串的输入。所以需要确保使用query作为输入,而不是lookup。
query是ansible2.5引入的新的jinja2函数,该函数始终返回一个列表。
默认情况下lookup返回一个字符串,可以使用wantlist=True强制lookup返回列表。
#loop输入列表示例
loop: "{{ query('inventory_hostnames', 'all') }}"
loop: "{{ lookup('inventory_hostnames', 'all', wantlist=True) }}"
- 此文档介绍了,可转换为loop的with_*使用方法:Migrating from with_X to loop
- with_items更改为loop时需要注意。因为with_items执行了隐式单级展平。您可能需要使用flatten过滤去来匹配确切结果。
- 任何需要在loop中使用lookup的with_*语句,都不应该使用wantlist=True转换为loop关键字(直接使用query)。例如不要像如下这么做:
loop: "{{ lookup('fileglob', '*.txt', wantlist=True) }}"
标准循环
简单列表遍历
重复的任务可以写成一个简单的字符串列表上的标准循环。比如创建用户的两种写法,前者是不用循环,后者是使用循环:
- name: Add user testuser1
ansible.builtin.user:
name: "testuser1"
state: present
groups: "wheel"
- name: Add user testuser2
ansible.builtin.user:
name: "testuser2"
state: present
groups: "wheel"
- name: Add several users
ansible.builtin.user:
name: "{{ item }}"
state: present
groups: "wheel"
loop:
- testuser1
- testuser2
遍历哈希列表
- name: Add several users
ansible.builtin.user:
name: "{{ item.name }}"
state: present
groups: "{{ item.groups }}"
loop:
- { name: 'testuser1', groups: 'wheel' }
- { name: 'testuser2', groups: 'root' }
遍历字典
- name: Using dict2items
ansible.builtin.debug:
msg: "{{ item.key }} - {{ item.value }}"
loop: "{{ tag_data | dict2items }}"
vars:
tag_data:
Environment: dev
Application: payment
使用循环注册变量
当在循环时使用register注册变量时,变量的数据结构会和非循环时的不同。循环时变量的数据结构会包含一个results列表。如下:
- name: Register loop output as a variable
ansible.builtin.shell: "echo {{ item }}"
loop:
- "one"
- "two"
register: echo
{
"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"
}
]
}
until-重试任务直到满足条件
- name: Retry a task until a certain condition is met
ansible.builtin.shell: /usr/bin/foo
register: result
until: result.stdout.find("all systems go") != -1
retries: 5
delay: 10
此任务最多运行 5 次,每次尝试之间有 10 秒的延迟。如果任何尝试的结果在其标准输出中显示“all systems go”,则任务成功。“重试次数”的默认值为 3,“延迟”的默认值为 5。
当您运行任务until并将结果注册为变量时,注册的变量将包含一个名为“attempts”的键,它记录了该任务的重试次数。