ansible笔记(35):循环(八)

栏目: 服务器 · 发布时间: 6年前

内容简介:所属分类:ansible
  • A+

所属分类:ansible 运维技术

在本博客中,ansible是一个系列文章,我们会尽量以通俗易懂的方式总结ansible的相关知识点。

ansible系列博文直达链接:ansible轻松入门系列

"ansible系列"中的每篇文章都建立在前文的基础之上,所以, 请按照顺序阅读这些文章,否则有可能在阅读中遇到障碍。

上一篇文章中我们提到过,ansible官网推荐了新的方式操作循环,那么这篇文章中,我就就来聊聊这种新的方式,以便能够更好的从老版本的使用习惯过渡过来。

在2.5版本之前的ansible中,大多数人习惯使用"with_X"风格的关键字操作循环,从2.6版本开始,官方开始推荐使用"loop"关键字代替"with_X"风格的关键字,我们先来看一个小示例,使用loop关键字进行最简单的列表循环,示例如下:

---
- hosts: test70
  remote_user: root
  gather_facts: no
  tasks:
  - debug:
      msg: "{{ item }}"
    loop:
    - teststr1
    - teststr2

上例使用"loop"关键字,替换了之前总结的"with_list"这种"with_X"风格的关键字,它们的效果是完全相同的。

在总结lookup插件的用法时,已经详细的描述过,我们可以使用"loop"关键字配合对应的"lookup"插件,替换更多的、具有更复杂功能的"with_X"风格的关键字,比如,使用loop关键字和dict插件替换"with_dict"关键字,示例如下

---
- hosts: test70
  remote_user: root
  gather_facts: no
  vars:
    users:
      alice: female
      bob: male
  tasks:
  - debug:
      msg: "{{item.key}} is {{item.value}}"
    loop: "{{ lookup('dict',users) }}"

这个示例在上一篇文章中已经解释过,此处不再赘述。

上例使用了"loop加lookup"的方式,完成了循环操作,而在2.6版本的官网手册中,官方开始推荐使用"loop加filter"的方式来替代"loop加lookup"的方式,什么意思呢?我们来看一个小例子,如下:

---
- hosts: test70
  remote_user: root
  gather_facts: no
  vars:
    users:
      alice: female
      bob: male
  tasks:
  - debug:
      msg: "{{item.key}} is {{item.value}}"
    loop: "{{ users | dict2items }}"

如上例所示,在使用loop关键字操作对应的字典变量users时,并没有借助dict插件,而是借助了一个名为dict2items的过滤器,前文已经总结了过滤器的使用方法,但是并没有介绍dict2items过滤器的用法,那么此处正好介绍一下dict2items过滤器的使用方法,dict2items过滤器是在2.6版本中新加入的过滤器,它可以把一个字典格式的数据进行转换处理,具体会进行怎样的转换处理呢?我们来看个小示例,如下

users是一个字典格式的变量,它的结构是这样的
    users:
      alice: female
      bob: male
当users字典被dict2items转换处理以后,会变成如下模样
    users:
    - key: alice
      value: female
    - key: bob
      value: male

这就是dict2items过滤器的作用,看到上述转换后的数据格式,你是不是觉得似曾相识?

没错,字典数据经过"dict2items"处理后,与字典数据经过"with_dict"处理后的格式完全相同(可以参考前文的"with_dict"总结),

经过上述描述,你应该已经明白了,无论是"with_X"、"loop加lookup"还是"loop加filter",都是使用不同的方式,实现相同的功能而已,只是在2.6版本的ansible中,官方开始推荐使用"loop加filter"的方式操作循环。

那么我们就来总结一下这种新的使用方式,由于之前已经总结过各种"with_X"关键字的使用方法,所以此处直接列出各种"with_x"关键字对应的新的使用方式。

with_list

#loop可以替代with_list,当处理嵌套的列表时,列表不会被拉平
---
- hosts: test70
  remote_user: root
  gather_facts: no
  vars:
    testlist:
    - a
    - [b,c]
    - d
  tasks:
  - debug:
      msg: "{{item}}"
    loop: "{{testlist}}"

with_flattened

#flatten过滤器可以替代with_flattened,当处理多层嵌套的列表时,列表中所有的嵌套层级都会被拉平
#示例如下,flatten过滤器的用法在前文中已经总结过,此处不再赘述
---
- hosts: test70
  remote_user: root
  gather_facts: no
  vars:
    testlist:
    - a
    - [b,c]
    - d
  tasks:
  - debug:
      msg: "{{item}}"
    loop: "{{testlist | flatten}}"

with_items

#flatten过滤器(加参数)可以替代with_items,当处理多层嵌套的列表时,只有列表中的第一层会被拉平
---
- hosts: test70
  remote_user: root
  gather_facts: no
  vars:
    testlist:
    - a
    - [b,c]
    - d
  tasks:
  - debug:
      msg: "{{item}}"
    loop: "{{testlist | flatten(levels=1)}}"

直到当前版本的ansible(2.6.2版---2.6.5版),当flatten过滤器配置leves参数处理多层列表时,存在bug

但是为了尽快熟悉新的使用方式,我们暂且忽略这个bug,具体bug可以参考如下链接

https://github.com/ansible/ansible/issues/46343

with_indexed_items

#flatten过滤器(加参数),再配合loop_control关键字,可以替代with_indexed_items
#当处理多层嵌套的列表时,只有列表中的第一层会被拉平,flatten过滤器的bug暂且忽略
#示例如下,之后会对示例进行解释
---
- hosts: test70
  remote_user: root
  gather_facts: no
  vars:
    testlist:
    - a
    - [b,c]
    - d
  tasks:
  - debug:
      msg: "{{index}}--{{item}}"
    loop: "{{testlist | flatten(levels=1)}}"
    loop_control:
      index_var: index

"loop_control"关键字可以用于控制循环的行为,比如在循环时获取到元素的索引。

"index_var"是"loop_control"的一个设置选项,"index_var"的作用是让我们指定一个变量,"loop_control"会将列表元素的索引值存放到这个指定的变量中,比如如下配置

  loop_control:
    index_var: my_idx

上述设置表示,在遍历列表时,当前被遍历元素的索引会被放置到"my_idx"变量中,也就是说,当进行循环操作时,只要获取到"my_idx"变量的值,就能获取到当前元素的索引值,当然,除了"index_var"选项,"loop_control"还有一些其他的选项可以使用,我们之后再进行总结。

with_together

#zip_longest过滤器配合list过滤器,可以替代with_together
---
- hosts: test70
  remote_user: root
  gather_facts: no
  vars:
    testlist1: [ a, b ]
    testlist2: [ 1, 2, 3 ]
    testlist3: [ A, B, C, D ]
  tasks:
  - debug:
      msg: "{{ item.0 }} - {{ item.1 }} - {{item.2}}"
    with_together:
    - "{{testlist1}}"
    - "{{testlist2}}"
    - "{{testlist3}}"
  - debug:
      msg: "{{ item.0 }} - {{ item.1 }} - {{item.2}}"
    loop: "{{ testlist1 | zip_longest(testlist2,testlist3) | list }}"

上例同时写出了"with_together"和对应的新方式的使用方法,以便进行对比。

当多个列表使用"with_together"进行对齐合并时,如果多个列表的长度不同,则使用最长的列表长度进行对齐,由于短列表中的元素数量不够,所以使用"空值"与长列表中的元素进行对齐,zip_longest过滤器也会像"with_together"一样,对列表进行组合,但是还需要借助list过滤器,将组合后的数据列表化,list过滤器的用法已经总结过,如果你忘了,可以回顾前文,当使用zip_longest过滤器代替with_together关键字时,默认也是使用"空值"与长列表中的元素进行对齐,但是也可以指定其他字符串代替"空值",示例如下,表示使用"NoEle"代替"空值",与长列表中的更多的元素进行对齐。

  - debug:
      msg: "{{ item.0 }} - {{ item.1 }} - {{item.2}}"
    loop: "{{ testlist1 | zip_longest(testlist2,testlist3,fillvalue='NoEle') | list }}"

从zip_longest过滤器的名字就可以看出,这个过滤器也是使用最长的列表长度进行对齐的,当多个列表的长度不同时,能不能使用最短的列表长度进行对齐呢?没问题,我们只需要借助另一个过滤器即可,这个过滤器的名字是"zip",示例如下

  - debug:
      msg: "{{ item.0 }} - {{ item.1 }} - {{item.2}}"
    loop: "{{ testlist1 | zip(testlist2,testlist3) | list }}"

zip_longest和zip过滤器在2.3以及以后的版本中可用。

with_nested/with_cartesian

#product过滤器配合list过滤器,可以替代with_nested和with_cartesian
#如果你忘了with_nested和with_cartesian的用法,可以回顾前文
---
- hosts: test70
  remote_user: root
  gather_facts: no
  vars:
    testlist1: [ a, b, c ]
    testlist2: [ 1, 2, 3, 4 ]
  tasks:
  - debug:
      msg: "{{ item.0 }}--{{ item.1 }}"
    loop: "{{ testlist1 | product(testlist2) | list }}"

product过滤器也需要将组合后的数据进行列表化,所以需要借助list过滤器

with_sequence

#range过滤器配合list过滤器可以代替with_sequence
#你可以先回顾一下with_sequence的用法,然后再测试如下示例
---
- hosts: test70
  remote_user: root
  gather_facts: no
  tasks:
  - debug:
      msg: "{{item}}"
    loop: "{{ range(0, 6, 2) | list }}"

上例表示生成数字,数字从0开始,到6结束,步长为2,但是rangge函数的操作范围不会包含结束范围,也就是说不会包含6,换句话说就是,上例会生成0、2、4三个数字,而不会包含6,在总结with_sequence时我们提到过,with_sequence还有格式化的功能,比如如下示例

  - debug:
      msg: "{{item}}"
    with_sequence: start=2 end=6 stride=2 format="number is %0.2f"

如果你想要使用新的方式实现上例的效果,还需要配合format过滤器一起使用,示例如下

  - debug:
      msg: "{{ 'number is %0.2f' | format(item) }}"
    loop: "{{ range(2, 7, 2) | list }}"

with_random_choice

#使用random函数可以替代with_random_choice,由于random函数是随机取出列表中的一个值,并不涉及循环操作,所以并不用使用loop关键字。
---
- hosts: test70
  remote_user: root
  gather_facts: no
  vars:
    testlist: [ a, b, c ]
  tasks:
  - debug:
      msg: "{{ testlist | random }}"

with_dict

#除了上文总结的dict2items过滤器,dictsort过滤器也可以替代with_dict
---
- hosts: test70
  remote_user: root
  gather_facts: no
  vars:
    users:
      d: daisy
      c: carol
      a: alice
      b: bob
      e: ella
  tasks:
  - debug:
      msg: "{{item.key}} -- {{item.value}}"
    loop: "{{ users | dict2items }}"
  - debug:
      msg: "{{item.0}} -- {{item.1}}"
    loop: "{{ users | dictsort }}"

正如dictsort的名字一样,dictsort具有 排序 功能,dictsort会根据键名的字母顺序进行排序

with_subelements

#subelements过滤器可以替代with_subelements
---
- hosts: test70
  remote_user: root
  gather_facts: no
  vars:
    users:
    - name: bob
      gender: male
      hobby:
        - Skateboard
        - VideoGame
    - name: alice
      gender: female
      hobby:
        - Music
  tasks:
  - debug:
      msg: "{{item.0.name}}'s hobby is {{item.1}}"
    with_subelements:
    - "{{users}}"
    - hobby
  - debug:
      msg: "{{item.0.name}}'s hobby is {{item.1}}"
    loop: "{{users | subelements('hobby')}}"

参考之前总结的with_subelements的用法,会更有利于理解上述示例

loop_control

在介绍使用新的方式替换"with_indexed_items"时,我们已经初步的接触到了loop_control关键字,它可以用于控制循环的行为,比如,使用loop_control的index_var选项,就能在遍历列表时,将元素对应的索引写入到指定的变量中,除了index_var选项,loop_control还有一些其他的选项可用,此处我们就来总结一下这些选项。

pause选项

pause选项能够让我们设置每次循环之后的暂停时间,以秒为单位,换句话说就是设置每次循环之间的间隔时间,示例如下

---
- hosts: test70
  remote_user: root
  gather_facts: no
  tasks:
  - debug:
      msg: "{{item}}"
    loop:
    - 1
    - 2
    - 3
    loop_control:
      pause: 10

上例表示每次循环之间间隔10秒

label选项

我们先不解释label选项的作用,我们先来看一个小示例,如下

---
- hosts: test70
  remote_user: root
  gather_facts: no
  vars:
    users:
      alice:
        name: Alice Appleworth
        gender: female
        telephone: 123-456-7890
      bob:
        name: Bob Bananarama
        gender: male
        telephone: 987-654-3210
  tasks:
  - debug:
      msg: "{{item.key}}"
    loop: "{{users | dict2items}}"

执行上例playbook,执行结果如下

ansible笔记(35):循环(八)

从上图可以看出,我们真正需要的部分就是上图中红线标注的部分,也就是debug模块输出的msg信息,上图中蓝线标注的部分我们可能并不关注,但是当我们使用debug模块输出msg信息时,无论我们是否需要获取整个item的信息,debug模块都会将item的整个信息显示出来,当我们处理的数据越复杂,显示的item的信息就越多,显示在屏幕上的、我们不关注的信息就会越多,怎样改善这种情况呢?借助label选项就行了,来看一个小示例:

---
- hosts: test70
  remote_user: root
  gather_facts: no
  vars:
    users:
      alice:
        name: Alice Appleworth
        gender: female
        telephone: 123-456-7890
      bob:
        name: Bob Bananarama
        gender: male
        telephone: 987-654-3210
  tasks:
  - debug:
      msg: "{{item.key}}"
    loop: "{{users | dict2items}}"
    loop_control:
      label: "{{item.key}}"

上述示例与之前的示例的不同之处在于使用了loop_control关键字,并且使用了label选项,label的值为item.key,与msg的值完全相同,那么,执行上例playbook,结果如下

ansible笔记(35):循环(八)

正如你所看到的,整个输出信息变得简洁了,item的信息并没有完全显示出来,而是只显示出了item.key的值,达到了我们想要的效果,这就是label选项的作用,它可以在循环输出信息时,简化输出item的信息。

loop_var选项

loop_var选项的作用我们暂且先不进行介绍,因为如果想要搞明白loop_var选项的作用,最好先搞明白"include_tasks"的用法,但是由于到目前为止,我们还没有总结include的相关用法,所以此处暂且放下,等到我们总结include的用法时,再顺势介绍loop_var选项的作用,会更加事半功倍的让我们去理解它。

这篇文章就总结到这里,希望能够对你有所帮助~~

ansible笔记(35):循环(八)

我的微信公众号

关注"实用运维笔记"微信公众号,当博客中有新文章时,可第一时间得知哦~


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

数据结构教程

数据结构教程

彭波 / 第1版 (2004年3月1日) / 2004-3-1 / 34.00元

精心策划,准确定位 概念清晰,例题丰富 深入浅出,内容翔实 体系合理,重点突出一起来看看 《数据结构教程》 这本书的介绍吧!

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具