在一个task中循环某个操作
1、标准循环
- name: add several users
user:
name: "{{ item }}"
state: present
groups: "wheel"
loop:
- testuser1
- testuser2
#如果已经在变量文件中,定义了yaml列表,可以这么写
loop: "{{ somelist }}"
note:在2.5 Ansible之前主要使用with_ <lookup>关键字来创建循环,循环关键字基本上类似于with_list,with_items。
我现在也在用,啊哈!
一些ansible插件,类似yum和apt模块可以直接列出引用的选项,比使用loop更好,如下:
- name: optimal yum
yum:
name: "{{list_of_packages}}"
state: present
- name: non optimal yum, not only slower but might cause issues with interdependencies
yum:
name: "{{item}}"
state: present
loop: "{{list_of_packages}}"
迭代的items类型也可以是hash列表,例如:
- name: add several users
user:
name: "{{ item.name }}"
state: present
groups: "{{ item.groups }}"
loop:
- { name: 'testuser1', groups: 'wheel' }
- { name: 'testuser2', groups: 'root' }
2、复杂的循环
有时候你不只是需要一个简单列表,你可以用jinja2表达式创建复杂的列表,例如使用 “netsed" lookup
- name: give users access to multiple databases
mysql_user:
name: "{{ item[0] }}"
priv: "{{ item[1] }}.*:ALL"
append_privs: yes
password: "foo"
loop: "{{ query('nested', [ 'alice', 'bob' ], [ 'clientdb', 'employeedb', 'providerdb' ]) }}"
note: with_ 循环实际上是组合了 with_ + lookup(),甚至是with_items。 loop也可以这么搞,类似上边例子。
3、使用lookup 与 用loop查询
ansible2.5加入了新的函数 query,为lookup插件增加一些益处,当使用新的关键字loop时候。query提供一个更简单的借口和可预测性更好的输出,确保兼容loop。
一些情况中,lookup函数不会返回 loop需要的list,下列的调用是相等的:
loop: "{{ query('nested', ['alice', 'bob'], ['clientdb', 'employeedb', 'providerdb']) }}"
loop: "{{ lookup('nested', ['alice', 'bob'], ['clientdb', 'employeedb', 'providerdb'], wantlist=True) }}"
4、Do-Until循环
- shell: /usr/bin/foo
register: result
until: result.stdout.find("all systems go") != -1
retries: 5
delay: 10
上例 递归执行shell模块,直到“all systems go”在标准输出出现,或者每个10s执行1次,执行5次之后无结果。 retries默认值是3,delay默认值是5。
note:如果until参数没有定义, retries值被强制设置为1。
5、使用loop中的register
- shell: "echo {{ item }}"
loop:
- "one"
- "two"
register: echo
与使用loop和register不同的例子
{
"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"
}
]
}
循环遍历注册的变量来检查结果:
- name: Fail if return code is not 0
fail:
msg: "The command ({{ item.cmd }}) did not have a 0 return code"
when: item.rc != 0
loop: "{{ echo.results }}"
在迭代期间,当前item的结果将被放置在变量中
- shell: echo "{{ item }}"
loop:
- one
- two
register: echo
changed_when: echo.stdout != "one"
6、循环inventory
如果想循环inventory中的hosts或者部分hosts,你可以用loop的ansible_play_batch或者groups变量:
# show all the hosts in the inventory
- debug:
msg: "{{ item }}"
loop: "{{ groups['all'] }}"
#show all the hosts in the current play
- debug:
msg: "{{ item }}"
loop: "{{ ansible_play_batch }}"
使用lookup 插件 inventory_hostname 实现:
# show all the hosts in the inventory
- debug:
msg: "{{ item }}"
loop: "{{ query('inventory_hostnames', 'all') }}"
# show all the hosts matching the pattern, ie all but the group www
- debug:
msg: "{{ item }}"
loop: "{{ query('inventory_hostnames', 'all!www') }}"
7、循环控制
2.0版本你可以使用loops和task includes(不能用playbook includes)。这增加了一次循环一组任务的能力。每次循环,Ansible默认设置循环变量item,这会导致这些嵌套loop覆盖来自“外部”循环的项目的值。从Ansible 2.1开始,loop_control选项可用于指定要用于循环的变量名。
# main.yml
- include: inner.yml
- include_tasks: inner.yml
loop:
- 1
- 2
- 3
loop_control:
loop_var: outer_item
# inner.yml
- debug:
msg: "outer item={{ outer_item }} inner item={{ item }}"
loop:
- a
- b
- c
note:如果Ansible检测到当前循环正在使用已定义的变量,则会引发错误以使任务失败。
当使用复杂的数据结构来循环显示时,可能会出现busy情况,这就是label指令提供帮助的地方
- name: create servers
digital_ocean:
name: "{{ item.name }}"
state: present
loop:
- name: server1
disks: 3gb
ram: 15Gb
network:
nic01: 100Gb
nic02: 10Gb
...
loop_control:
label: "{{ item.name }}"
现在,它将只显示标签字段,而不是每个项目的整个结构,它默认为{{item}}来照常显示内容。
循环控制的另一个选项是暂停,它允许您控制执行任务循环中的项目之间的时间(以秒为单位)。
# main.yml
- name: create servers, pause 3s before creating next
digital_ocean:
name: "{{ item }}"
state: present
loop:
- server1
- server2
loop_control:
pause: 3
如果您需要跟踪您在循环中的位置,可以使用index_var选项来循环控制以指定变量名称以包含当前循环索引。
- name: count our fruit
debug:
msg: "{{ item }} with index {{ my_idx }}"
loop:
- apple
- banana
- pear
loop_control:
index_var: my_idx
8、loops和 includes (2.0版本)
由于loop_control在Ansible 2.0中不可用,因此当使用带有循环的include时,应该使用set_fact保存item的“outer”循环值:
# main.yml
- include_tasks: inner.yml
loop:
- 1
- 2
- 3
# inner.yml
- set_fact:
outer_item: "{{ item }}"
- debug:
msg: "outer item={{ outer_item }} inner item={{ item }}"
loop:
- a
- b
- c
Note