ansible源文档地址

有时候你想多次重复一个任务。 在计算机编程中,这叫做循环。 常见的 Ansible 循环包括使用文件模块更改几个文件和 / 或目录的所有权,使用用户模块创建多个用户,并重复一个轮询步骤,直到达到某个结果。 为创建循环提供了两个关键字: loopwith_<lookup>

注意

  • 我们增加在Ansible2.5版本中中加了loop。它还没有完全取代with_<lookup>, 但我们推荐在大多数场景下使用它。
  • 我们并舍弃with_<lookup>用法--在可预见的未来,这种语法仍然有效。
  • 我们正在寻求改进loop语法,关注这个页面和changelog来获取更新。

对比 loop and with_*

  • with_关键字依赖Lookup Plugins插件--尽管item也是一个lookup插件。
  • loop关键字等价于with_list,是使用简单遍历时的最佳选择。
  • loop关键字不再接收一个字符串作为输入,查看 Ensuring list input for loop: query vs. lookup
  • 通常来说,任何包含在 从with_X迁移到loop中的 with_*用法都可以替换成loop
  • 需要注意的是,在将with_items 替换成 loop时,由于with_items 执行单层隐式扁平化遍历,在使用loop作为输出时,你需要结合 flatten(1)一起使用。举例说明,下面两种方式的输出结果相同:
with_items:
- 1
- [2,3]
- 4

你需要像这样使用:

loop: "{{ [1, [2,3] ,4] | flatten(1) }}"
  • 任何依赖 lookup 插件的with_*语句不应该被转换成loop关键字。举例说明,不建议使用下面的场景:
loop: "{{ lookup('fileglob', '*.txt', wantlist=True) }}"

保持这样的格式会更简洁。

with_fileglob: '*.txt'

标准loop

遍历一个简单的列表

重复的任务可以通过简单的字符串列表写成标准的loop形式。你可以在任务里使用列表:

- name: add several users
user:
name: "{{ item }}"
state: present
groups: "wheel"
loop:
- testuser1
- testuser2

你可以使用一个变量文件或者在你的剧本中使用var定义列表,然后在任务里通过列表名称引用即可:

loop: "{{ somelist }}"

上面例子中的任何一个都相当于:

- name: add user testuser1
user:
name: "testuser1"
state: present
groups: "wheel" - name: add user testuser2
user:
name: "testuser2"
state: present
groups: "wheel"

您可以直接将列表传递给某些插件作为参数。 大多数打包模块如yum 包管理器apt包管理器都具有这种功能。 如果可用,将列表传递给参数要比在任务上循环要好。 例如:

- name: optimal yum
yum:
name: "{{ list_of_packages }}"
state: present - name: non-optimal yum, slower and may cause issues with interdependencies
yum:
name: "{{ item }}"
state: present
loop: "{{ list_of_packages }}"

查看 模块文档 ,看看是否可以将列表传递给任何特定模块的参数。

遍历哈希列表

如果你有一个哈希列表,你可以在循环中引用子键。例如:

- name: add several users
user:
name: "{{ item.name }}"
state: present
groups: "{{ item.groups }}"
loop:
- { name: 'testuser1', groups: 'wheel' }
- { name: 'testuser2', groups: 'root' }

当将条件句与循环结合时,When语句将为每个项分别处理。 有关示例,请参见 When 语句

遍历字典

若要遍历字典, 请使用 dict2items 字典过滤器

- name: create a tag dictionary of non-empty tags
set_fact:
tags_dict: "{{ (tags_dict|default({}))|combine({item.key: item.value}) }}"
loop: "{{ tags|dict2items }}"
vars:
tags:
Environment: dev
Application: payment
Another: "{{ doesnotexist|default() }}"
when: item.value != ""

在这里,我们不想设置空标记,因此我们创建了一个只包含非空标记的字典。

用循环注册变量

你可以将loop的输出注册为变量,例如:

- shell: "echo {{ item }}"
loop:
- "one"
- "two"
register: echo

当使用循环注册时,放置在变量中的数据结构将包含一个 results 属性,该属性是来自模块的所有响应的列表。 这与直接注册而不循环时返回的数据结构不同:

{
"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 }}"

在迭代过程中,当前项的结果将被放置在变量中:

- shell: echo "{{ item }}"
loop:
- one
- two
register: echo
changed_when: echo.stdout != "one"

复杂的loops

遍历嵌套列表

你可以使用 Jinja2表达式来遍历复杂的列表,例如,循环可以组合嵌套的列表:

- name: give users access to multiple databases
mysql_user:
name: "{{ item[0] }}"
priv: "{{ item[1] }}.*:ALL"
append_privs: yes
password: "foo"
loop: "{{ ['alice', 'bob'] | product(['clientdb', 'employeedb', 'providerdb'])|list }}"

尝试一个任务知道满足条件为止

在 1.4版本中引入

你可以使用 until 关键字重试一个任务,直到满足某个条件为止:

- shell: /usr/bin/foo
register: result
until: result.stdout.find("all systems go") != -1
retries: 5
delay: 10

此任务最多运行5次,每次尝试之间延迟10秒。 如果任何尝试的结果在其标准输出中具有“ all systems go” ,则任务成功。 “ retries”的默认值为3,“ delay”为5。

若要查看单个重试的结果,请使用-vv 运行此剧本。

当您使用 until 运行任务并将结果注册为变量时,注册的变量将包含一个名为“ attempts”的键,该键记录任务的重试次数。

注意

如果要重试任务,则必须设置 until 参数。 如果没有定义 until,则强制重试参数的值为1。

主机清单的循环

为了遍历你的主机清单,或者仅仅是主机清单的一个子集,你可以使用一个常规的循环来遍历可以播放的批处理或者分组变量:

# 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 }}"

还有一个特定的查找插件主机清单中主机名,可以这样使用:

# 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') }}"

关于更多信息可以在模式中找到目标主机和组

使用querylookup确保列表输入

Loop 关键字需要一个列表作为输入,但是 lookup 关键字默认返回一个逗号分隔值字符串。 2.5引入了一个新的 Jinja2函数,命名为调用查找插件,它总是返回一个列表,当使用 loop 关键字时,它提供了一个更简单的界面和更可预测的查找插件输出。

您可以使用 wantlist=true 强制查找返回一个要循环的列表,或者您可以改用 query。

这些例子做了同样的事情:

loop: "{{ query('inventory_hostnames', 'all') }}"

loop: "{{ lookup('inventory_hostnames', 'all', wantlist=True) }}"

为loops添加控制

在 2.1版本中引入

loop_control 关键字可以让您以有用的方式管理循环。

用label限制loop输出

在 2.2版本中引入

当循环遍历复杂的数据结构时,任务的控制台输出可能是巨大的。 要限制显示的输出,使用循环控制的 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 }}"

此任务的输出将仅显示每个项的 name 字段,而不是多行{{ item }}变量的全部内容。

注意

这是为了使控制台输出更具可读性,而不是保护敏感数据。 如果循环中有敏感数据,请在任务上设置 no_log: yes 以防止泄露。

loop中的暂停

在 2.2版本中引入

若要控制任务循环中每个项目执行之间的时间(以秒为单位) ,请使用带循环控制的 pause 指令loop_control:

# 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跟踪进度

在 2.5版本中引入

若要跟踪您在循环中的位置,请使用 index_var 指令和 loop_control。 这个指令指定一个包含当前循环索引的变量名:

- name: count our fruit
debug:
msg: "{{ item }} with index {{ my_idx }}"
loop:
- apple
- banana
- pear
loop_control:
index_var: my_idx

通过loop_var定义内部和外部变量名

在 2.1版本中引入

可以使用 include 任务嵌套两个循环任务。 但是,默认情况下,Ansible 为每个循环设置循环变量项。 这意味着内部的嵌套循环将覆盖外部循环中 item 的值。 您可以使用 loop_var loop_control 为每个循环指定变量的名称:

# main.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

注意

如果 Ansible 检测到当前循环正在使用一个已经定义的变量,它将引发一个错误以使任务失败。

扩展loop变量

在 2.8 版本中引入

从 ansible 2.8开始,你可以使用扩展选项来获得扩展循环信息来进行循环控制。 此选项将公开以下信息。

Variable Description
ansible_loop.allitems 循环中所有项的列表
ansible_loop.index 循环的当前迭代的索引。(索引从1开始)
ansible_loop.index0 循环的当前迭代的索引。(索引从0开始)
ansible_loop.revindex 倒序循环的当前迭代的索引。(索引到1结束)
ansible_loop.revindex0 倒序循环的当前迭代的索引。(索引到0结束)
ansible_loop.first 如果第一次迭代则为True,否则是False
ansible_loop.last 如果最后一次迭代则为True,否则是False
ansible_loop.length 循环中的项数
ansible_loop.previtem 循环上一次迭代中的项。在第一次迭代中这个变量未定义
ansible_loop.nextitem 循环下一次迭代中的项。在最后一次迭代中这个变量未定义
loop_control:
extended: yes

访问loop_var

在 2.8 版本中引入

从 ansible2.8你可以得到提供的值的名称循环控制。循环变量使用安塞循环变量

对于角色作者,编写允许循环的角色,而不是口述所需的循环变量值,您可以通过以下方式收集该值:

"{{ lookup('vars', ansible_loop_var) }}"

从 with_X 迁移到 loop

随着 Ansible 2.5的发布,推荐的循环执行方式是使用新的 loop 关键字,而不是使用 with_x 样式的循环。

在许多情况下,循环语法更好地使用过滤器,而不是更复杂地使用query 或者 lookup

下面的示例将展示如何将许多常见的样式循环转换为循环和过滤器。

with_list

with_listloop替换。

- name: with_list
debug:
msg: "{{ item }}"
with_list:
- one
- two - name: with_list -> loop
debug:
msg: "{{ item }}"
loop:
- one
- two

with_items

with_itemsloopflatten 过滤器替换。

- name: with_items
debug:
msg: "{{ item }}"
with_items: "{{ items }}" - name: with_items -> loop
debug:
msg: "{{ item }}"
loop: "{{ items|flatten(levels=1) }}"

with_indexed_items

with_indexed_itemsloop, flatten过滤器 和 loop_control.index_var替换。

- name: with_indexed_items
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
with_indexed_items: "{{ items }}" - name: with_indexed_items -> loop
debug:
msg: "{{ index }} - {{ item }}"
loop: "{{ items|flatten(levels=1) }}"
loop_control:
index_var: index

with_flattened

with_flattenedloopflatten 过滤器替换。

- name: with_flattened
debug:
msg: "{{ item }}"
with_flattened: "{{ items }}" - name: with_flattened -> loop
debug:
msg: "{{ item }}"
loop: "{{ items|flatten }}"

with_together

with_togetherloopzip过滤器替换。

- name: with_together
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
with_together:
- "{{ list_one }}"
- "{{ list_two }}" - name: with_together -> loop
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
loop: "{{ list_one|zip(list_two)|list }}"

with_dict

with_dictloopdictsort 或者 dict2items 过滤器替换。

- name: with_dict
debug:
msg: "{{ item.key }} - {{ item.value }}"
with_dict: "{{ dictionary }}" - name: with_dict -> loop (option 1)
debug:
msg: "{{ item.key }} - {{ item.value }}"
loop: "{{ dictionary|dict2items }}" - name: with_dict -> loop (option 2)
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
loop: "{{ dictionary|dictsort }}"

with_sequence

with_sequencelooprange 函数, format 过滤器替换。

- name: with_sequence
debug:
msg: "{{ item }}"
with_sequence: start=0 end=4 stride=2 format=testuser%02x - name: with_sequence -> loop
debug:
msg: "{{ 'testuser%02x' | format(item) }}"
# range is exclusive of the end point
loop: "{{ range(0, 4 + 1, 2)|list }}"

with_subelements

用循环和子元素过滤器代替子元素过滤器。

- name: with_subelements
debug:
msg: "{{ item.0.name }} - {{ item.1 }}"
with_subelements:
- "{{ users }}"
- mysql.hosts - name: with_subelements -> loop
debug:
msg: "{{ item.0.name }} - {{ item.1 }}"
loop: "{{ users|subelements('mysql.hosts') }}"

with_nested/with_cartesian

with_nestedwith_cartesianloopproduct 过滤器替换。

- name: with_nested
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
with_nested:
- "{{ list_one }}"
- "{{ list_two }}" - name: with_nested -> loop
debug:
msg: "{{ item.0 }} - {{ item.1 }}"
loop: "{{ list_one|product(list_two)|list }}"

with_random_choice

with_random_choicerandom 过滤器替换,不在需要loop

- name: with_random_choice
debug:
msg: "{{ item }}"
with_random_choice: "{{ my_list }}" - name: with_random_choice -> loop (No loop is needed here)
debug:
msg: "{{ my_list|random }}"
tags: random

ansible playbook loop 翻译的更多相关文章

  1. ansible playbook模式及语法

    一.什么是playbook及其组成 什么是playbook playbook 翻译过来就是"剧本" playbook的组成 play:定义的是主机的角色 task:定义的是具体执行 ...

  2. Ansible Playbook 初识

    Ansible Playbook 基本概述与使用案例 主机规划 添加用户账号 说明: 1. 运维人员使用的登录账号: 2. 所有的业务都放在 /app/ 下「yun用户的家目录」,避免业务数据乱放: ...

  3. Ansible playbook 编程

    Ansible playbook 编程详解与各种小案例 主机规划 添加用户账号 说明: 1. 运维人员使用的登录账号: 2. 所有的业务都放在 /app/ 下「yun用户的家目录」,避免业务数据乱放: ...

  4. Ansible playbook API 开发 调用测试

    Ansible是Agentless的轻量级批量配置管理工具,由于出现的比较晚(13年)基于Ansible进行开发的相关文档较少,因此,这里通过一些小的实验,结合现有资料以及源码,探索一下Ansible ...

  5. ansible playbook实践(四)-如何调试写好的playbook文件

    有时,我们写了一个长长,功能很强悍的yaml文件,但是,我们有可能会担心,写的yaml文件是否正确,是否有漏洞危机,毕竟是要修改线上的机器,那么,有可能我们可以从以下几个检查维度来进行,确保在大规模应 ...

  6. ansible playbook批量改ssh配置文件,远程用户Permission denied

    最近手里的数百台服务器需要改/etc/ssh/sshd_config的参数,禁止root直接登陆,也就是说 [root@t0 ~]# cat /etc/ssh/sshd_config | grep R ...

  7. ansible笔记(11):初识ansible playbook(二)

    ansible笔记():初识ansible playbook(二) 有前文作为基础,如下示例是非常容易理解的: --- - hosts: test211 remote_user: root tasks ...

  8. ansible笔记(10):初识ansible playbook

    ansible笔记():初识ansible playbook 假设,我们想要在test70主机上安装nginx并启动,我们可以在ansible主机中执行如下3条命令 ansible test70 -m ...

  9. Ansible playbook 批量修改服务器密码 先普通后root用户

    fsckzy   Ansible playbook 批量修改服务器密码 客户的需求:修改所有服务器密码,密码规则为Rfv5%+主机名后3位 背景:服务器有CentOS6.7,SuSE9.10.11,r ...

随机推荐

  1. BUAA_2020_OO_第一单元总结

    三次作业,三次成长 第一次作业--幂函数求导总结 作业思路和心得 第一次作业的要求只有x的指数这样的幂函数加减组成表达式,对表达式进行求导,而且没有格式错误的检查,所以难度感觉还不是很高.不过由于我寒 ...

  2. Git入门操作(一)

    最近真正用到了Git,感觉还是需要好好整理一下最最基础用法,与萌新共享.^_^ 关于Git的基础介绍,这里不再赘述,下面撸代码了(主要是命令行的操作,属于linux操作系统的,可能没听过,但记住就好了 ...

  3. 将图片base64格式转换为file对象并读取(两种方式读取)

    两种方式读取,一种URL.createObjectURL,另一种fileReader   var base64 = ` data:image/jpeg;base64,/9j/4AAQSkZJRgABA ...

  4. spring 事务源码赏析(一)

    在本系列中,我们会分析:1.spring是如何开启事务的.2.spring是如何在不影响业务代码的情况下织入事务逻辑的.3.spirng事务是如何找到相应的的业务代码的.4.spring事务的传播行为 ...

  5. flask中的表单文件上传

    在表单中上传文件时,一定要加入 enctype="multipart/form-data" 属性 为什么要加入这个属性呢: enctype就是encodetype就是编码类型的意思 ...

  6. 模块 face_recognition 人脸识别

    face_recognition 人脸识别 api 说明 1 load_image_file 将img文件加载到numpy 数组中 2 face_locations 查找图像中所有面部和所有面部特征的 ...

  7. CentOS 编译安装 Emacs 并配置

    Linux 中 CentOS 系列一向以稳定为目标,然而也会存在版本太旧的问题,Emacs 就是其中的一个,目前 Emacs 都发行到 25.2 了,而 CentOS 上的 Emacs 版本却还是 2 ...

  8. 深入解读ES6系列(三)

    ES6字符串 哈喽小伙伴们,爱说'废'话的Z又回来了,欢迎来到Super IT曾的博客时间,上一节说了函数,解构赋值和数组的五大将,这一节我们继续我们知识的海洋,一起奋斗不秃头!不足的欢迎提问留言. ...

  9. PTA数据结构与算法题目集(中文) 7-3

    PTA数据结构与算法题目集(中文)  7-3 树的同构 给定两棵树T1和T2.如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是“同构”的.例如图1给出的两棵树就是同构的,因为我们把其中一 ...

  10. 家庭版记账本app开发之关于(数据库查找出数据)圆饼图的生成

    这次完成的主要的怎样从数据库中调出数据.之后通过相关的数据,生成想要的圆饼图.以方便用户更加直观的看见关于账本的基本情况. 在圆饼图生成中用到了一些外部资源 具体的import如下: import c ...