ansible学习日记-插件lookup(11)

参考:ansible笔记(35):循环(八)-朱双印博客

前文中,我们总结了一些”过滤器”的使用方法,”过滤器”其实是ansible中的一种”插件”,除了过滤器,ansible中还有很多其他种类的插件,比如我们之前总结的”tests”,也是插件的一种,ansible官网为我们总结了各个插件的作用,并且将这些插件按照功能进行了分类

官网地址如下:

https://docs.ansible.com/ansible/latest/plugins/plugins.html

其实,我们一直都在使用这些插件,比如,我们在清单文件(/etc/ansible/hosts文件)中定义目标主机时,其实就使用到了”Inventory种类的插件”,当我们连接目标主机时,就使用到了”Connection种类的插件”,前文中总结的各种”循环”,在本质上也是一种插件。

刚才提到,前文中总结的”循环”在本质上也是一种插件,这种插件叫做”lookup插件”,这样描述”循环”和”lookup插件”可能不够直观,不如我们先来回忆一些”循环”的使用方法,以便能够更好的描述”循环”和”lookup插件”之间的关系

之前总结过,我们可以使用”with_dict”关键字循环的获取到”字典”中的每个键值对,示例如下

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

执行上例playbook以后,debug模块的输出信息如下

TASK [debug] ***************************************

ok: [test70] => (item={'value': u'male', 'key': u'bob'}) => {

"msg": "bob is male"

}

ok: [test70] => (item={'value': u'female', 'key': u'alice'}) => {

"msg": "alice is female"

}

其实,我们也可以换一种写法,没错,仍然是使用lookup插件,示例如下:

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

 


如你所见,两个示例的区别在于

第一个示例使用”with_dict关键字”处理users字典变量

第二个示例使用”loop关键字”配合”lookup插件”处理users字典变量

上例中,”lookup(‘dict’,users)”表示使用名为’dict’的lookup插件处理users字典变量,没错,’dict’也是一个lookup插件

看完上述两个示例,你一定已经学会了怎样使用lookup插件,没错,lookup插件的用法如下

lookup(‘插件名’,被处理数据或参数)

在2.5版本之前的ansible中,大多数人都会使用以”with_”开头的关键字进行循环操作,从2.5版本开始,官方开始推荐使用”loop”关键字代替”with_xxx”风格的关键字,在推荐使用”loop”关键字的同时,官方认为,loop关键字结合lookup插件的使用方法不够简洁明了,所以官方同时推荐,在使用loop关键字进行循环操作时,最好配合过滤器来处理数据,官方认为这样做会使语法变得更加简洁明了

需要注意,不要错误的以为lookup插件只能实现循环操作,lookup插件有很多,有的lookup插件与”循环操作”完全没有关系,lookup类型的插件的主要作用是访问外部的数据源,比如,获取到外部数据并赋值给某个变量,以便之后使用这些数据,lookup插件的操作都是在ansible主机中进行的,与目标主机没有关系。

如果你想要查看有哪些lookup插件可以使用,可以使用如下命令进行查看

ansible-doc -t lookup -l

上述命令中,”-t”选项用于指定插件类型,”-l”选项表示列出列表

如果你想要单独查看某个插件的使用方法,比如dict插件的使用方法,则可以使用如下命令

ansible-doc -t lookup dict

先来认识一个很常用的lookup插件,file插件

file插件可以获取到指定文件的文件内容(注:文件位于ansible主机中),示例如下

---

- hosts: test70

remote_user: root

gather_facts: no

tasks:

- debug:

msg: "{{ lookup('file','/testdir/testfile') }}"

上例表示获得/testdir/testfile文件中的内容,此文件中的内容为”testfile in test71″,执行上例playbook后debug模块输出如下:

TASK [debug] *******************************

ok: [test70] => {

"msg": "testfile in test71"

}

其他lookup插件:

---
- hosts: test70
  remote_user: root
  gather_facts: no
  tasks:
  #file插件可以获取ansible主机中指定文件的内容
  - debug:
      msg: "{{ lookup('file','/testdir/testfile') }}"
  #env插件可以获取ansible主机中指定变量的值
  - debug:
      msg: "{{ lookup('env','PATH') }}"
  #first_found插件可以获取列表中第一个找到的文件
  #按照列表顺序在ansible主机中查找
  - debug:
      msg: "{{ lookup('first_found',looklist) }}"
    vars:
      looklist:
        - /testdir
        - /tmp/staging
  #当使用with_first_found时,可以在列表的最后添加- skip: true
  #表示如果列表中的所有文件都没有找到,则跳过当前任务,不会报错
  #当不确定有文件能够被匹配到时,推荐这种方式
  - debug:
      msg: "{{item}}"
    with_first_found:
      - /testdir1
      - /tmp/staging
      - skip: true
  #ini插件可以在ansible主机中的ini文件中查找对应key的值
  #如下示例表示从test.ini文件中的testA段落中查找testa1对应的值
  #测试文件/testdir/test.ini的内容如下(不包含注释符#号)
  #[testA]
  #testa1=Andy
  #testa2=Armand
  #
  #[testB]
  #testb1=Ben
  - debug:
      msg: "{{ lookup('ini','testa1 section=testA file=/testdir/test.ini') }}"
  #当未找到对应key时,默认返回空字符串,如果想要指定返回值,可以使用default选项,如下
  #msg: "{{ lookup('ini','test666 section=testA file=/testdir/test.ini default=notfound') }}"
  #可以使用正则表达式匹配对应的键名,需要设置re=true,表示开启正则支持,如下
  #msg: "{{ lookup('ini','testa[12] section=testA file=/testdir/test.ini re=true') }}"
  #ini插件除了可以从ini类型的文件中查找对应key,也可以从properties类型的文件中查找key
  #默认在操作的文件类型为ini,可以使用type指定properties类型,如下例所示
  #如下示例中,application.properties文件内容如下(不包含注释符#号)
  #http.port=8080
  #redis.no=0
  #imageCode = 1,2,3
  - debug:
      msg: "{{ lookup('ini','http.port type=properties file=/testdir/application.properties') }}"
  #dig插件可以获取指定域名的IP地址
  #此插件依赖dnspython库,可使用pip安装pip install dnspython
  #如果域名使用了CDN,可能返回多个地址
  - debug:
      msg: "{{ lookup('dig','www.baidu.com',wantlist=true) }}"
  #password插件可以生成随机的密码并保存在指定文件中
  - debug:
      msg: "{{ lookup('password','/tmp/testpasswdfile') }}"
  #以上插件还有一些参数我们没有涉及到,而且也还有很多插件没有总结,等到用到对应的插件时,再行介绍吧
  #你也可以访问官网的lookup插件列表页面,查看各个插件的用法
  #https://docs.ansible.com/ansible/latest/plugins/lookup.html

新的循环

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

那么我们就来总结一下这种新的使用方式,由于之前已经总结过各种”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,执行结果如下

从上图可以看出,我们真正需要的部分就是上图中红线标注的部分,也就是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,结果如下

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

loop_var选项

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值