内容简介:所属分类:ansible
- A+
所属分类:ansible 运维技术
在本博客中,ansible是一个系列文章,我们会尽量以通俗易懂的方式总结ansible的相关知识点。
ansible系列博文直达链接:ansible轻松入门系列
"ansible系列"中的每篇文章都建立在前文的基础之上,所以, 请按照顺序阅读这些文章,否则有可能在阅读中遇到障碍。
之前已经总结过一些过滤器的用法,这篇文章我们继续来认识一些其他的过滤器。
在实际工作中,经常需要调用别人的接口,别人的接口会返回我们需要的数据,有时候,返回的数据就是json格式的,比如,公司为某些域名配置了CDN,当我们需要分析这些域名的访问日志时,则需要从CDN厂商获取到对应的日志,通常情况下,CDN服务商会暴露一个接口给我们,我们调用这个接口,即可获取到对应域名的日志列表,然后根据列表下载所有的日志,从而达到我们的目的,我们先一起来看一段示例数据,如下数据是我调用了CDN厂商接口后,返回的一段json格式的数据,如下
{"logs":[{"domainName":"asia1.cdn.test.com","files":[{"dateFrom":"2018-09-05-0000","dateTo":"2018-09-05-2359","logUrl":"http://log.testcd.com/log/zsy/asia1.cdn.test.com/2018-09-05-0000-2330_asia1.cdn.test.com.all.log.gz?wskey=XXXXX5a","fileSize":254,"fileName":"2018-09-05-0000-2330_asia1.cdn.test.com.all.log.gz","fileMd5":"error"}]},{"domainName":"image1.cdn.test.com","files":[{"dateFrom":"2018-09-05-2200","dateTo":"2018-09-05-2259","logUrl":"http://log.testcd.com/log/zsy/image1.cdn.test.com/2018-09-05-2200-2230_image1.cdn.test.com.cn.log.gz?wskey=XXXXX1c","fileSize":10509,"fileName":"2018-09-05-2200-2230_image1.cdn.test.com.cn.log.gz","fileMd5":"error"},{"dateFrom":"2018-09-05-2300","dateTo":"2018-09-05-2359","logUrl":"http://log.testcd.com/log/zsy/image1.cdn.test.com/2018-09-05-2300-2330_image1.cdn.test.com.cn.log.gz?wskey=XXXXXfe","fileSize":5637,"fileName":"2018-09-05-2300-2330_image1.cdn.test.com.cn.log.gz","fileMd5":"error"}]}]}
这段json数据并没有很高的可读性,因为它并没有进行任何缩进和换行,如果你想让这段数据有更高的可读性,则可以将这段数据所在的文件当做变量文件引入到playbook中,然后输出对应的变量即可,示例如下
--- - hosts: test70 remote_user: root gather_facts: no tasks: - include_vars: file: "/testdir/ansible/wsCdnLogList" name: testvar - debug: msg: "{{ testvar }}"
如上例所示,"/testdir/ansible/wsCdnLogList"就是上述json数据所在的文件,它位于ansible主机中,我们使用include_vars模块,将此文件当做变量文件引入了playbook中,在总结变量时我们提到过,变量文件的格式可以是yaml格式的,也可以是json格式的,上例就是将json格式的数据文件当做变量文件使用的,并且,将此文件的json数据赋值给了testvar变量,然后使用debug模块输出了testvar变量的值,那么,我们执行一下上例的playbook,可以发现,json数据已经被格式化为了有一定可读性的json文本输出在了控制台中,输出信息如下:
TASK [debug] ******************************************************************** ok: [test70] => { "msg": { "logs": [ { "domainName": "asia1.cdn.test.com", "files": [ { "dateFrom": "2018-09-05-0000", "dateTo": "2018-09-05-2359", "fileMd5": "error", "fileName": "2018-09-05-0000-2330_asia1.cdn.test.com.all.log.gz", "fileSize": 254, "logUrl": "http://log.testcd.com/log/zsy/asia1.cdn.test.com/2018-09-05-0000-2330_asia1.cdn.test.com.all.log.gz?wskey=XXXXX5a" } ] }, { "domainName": "image1.cdn.test.com", "files": [ { "dateFrom": "2018-09-05-2200", "dateTo": "2018-09-05-2259", "fileMd5": "error", "fileName": "2018-09-05-2200-2230_image1.cdn.test.com.cn.log.gz", "fileSize": 10509, "logUrl": "http://log.testcd.com/log/zsy/image1.cdn.test.com/2018-09-05-2200-2230_image1.cdn.test.com.cn.log.gz?wskey=XXXXX1c" }, { "dateFrom": "2018-09-05-2300", "dateTo": "2018-09-05-2359", "fileMd5": "error", "fileName": "2018-09-05-2300-2330_image1.cdn.test.com.cn.log.gz", "fileSize": 5637, "logUrl": "http://log.testcd.com/log/zsy/image1.cdn.test.com/2018-09-05-2300-2330_image1.cdn.test.com.cn.log.gz?wskey=XXXXXfe" } ] } ] } }
其实,json是yaml的子集,yaml是json的超集,yaml格式的数据和json格式的数据是可以互相转换的,所以,对于ansible来说,当我们把上例中的json数据文件当做变量文件引入时,就好像引入了一个我们定义好的yaml格式的变量文件一样,对于ansible来说是没有区别的,而且,即使在变量文件中使用yaml格式定义了变量,在使用debug模块输出变量信息时,ansible也会自动将yaml格式的数据转化为json格式后进行输出,细心如你一定已经在前面的文章中发觉到这一点了,那么,我们把上述json数据转换成yaml的格式,同时列出上述数据的json格式与yaml格式,你可以根据自己的使用习惯,选择阅读哪种格式的数据,以便你能够更好的理解这段数据的含义,yaml格式如下
logs: - domainName: asia1.cdn.test.com files: - dateFrom: 2018-09-05-0000 dateTo: 2018-09-05-2359 fileMd5: error fileName: 2018-09-05-0000-2330_asia1.cdn.test.com.all.log.gz fileSize: 254 logUrl: http://log.testcd.com/log/zsy/asia1.cdn.test.com/2018-09-05-0000-2330_asia1.cdn.test.com.all.log.gz?wskey=XXXXX5a - domainName: image1.cdn.test.com files: - dateFrom: 2018-09-05-2200 dateTo: 2018-09-05-2259 fileMd5: error fileName: 2018-09-05-2200-2230_image1.cdn.test.com.cn.log.gz fileSize: 10509 logUrl: http://log.testcd.com/log/zsy/image1.cdn.test.com/2018-09-05-2200-2230_image1.cdn.test.com.cn.log.gz?wskey=XXXXX1c - dateFrom: 2018-09-05-2300 dateTo: 2018-09-05-2359 fileMd5: error fileName: 2018-09-05-2300-2330_image1.cdn.test.com.cn.log.gz fileSize: 5637 logUrl: http://log.testcd.com/log/zsy/image1.cdn.test.com/2018-09-05-2300-2330_image1.cdn.test.com.cn.log.gz?wskey=XXXXXfe
从上述信息可以看出,cdn厂商返回的j数据是一个日志列表,这个日志列表中一共有两个对象,对象的属性有"domainName"和 "files",很明显,cdn厂商将日志按照域名进行了划分,返回了对应域名下的所有日志, "files"属性是一个列表,列表中列出了对应域名中的所有日志文件的信息,第一个域名的files列表中只有一个日志文件,第二个域名的files列表中一共有两个日志文件。
此刻,如果我们想要获取到整个列表中的所有日志文件的logUrl,我们该怎么办呢?
没错,聪明如你一定想到了,我们可以通过with_subelements循环,获取到当前整个大列表中的所有日志的logUrl属性,前文已经总结过了with_subelements的用法,此处不再赘述,如果你忘记了它的用法,请回顾前文,此处直接写出示例,如下:
tasks: - include_vars: file: "/testdir/ansible/wsCdnLogList" name: testvar - debug: msg: "{{ item.1.logUrl }}" with_subelements: - "{{testvar.logs}}" - files
其实,除了使用with_subelements,我们还有另外一种方法,就是使用过滤器,有一个名为json_query的过滤器,可以帮助我们解决上述问题。
我们先来看几个关于json_query的小示例,等熟悉了json_query过滤器以后,再回过头来通过json_query解决上面的问题,小示例如下
假设我们现在有一段简单的json数据,如下:
{ "users": [ { "name": "tom", "age": 18 }, { "name": "jerry", "age": 20 } ] }
上述json数据的yaml格式如下:
--- users: - name: tom age: 18 - name: jerry age: 20
从上述示例可以看出,一共有两个用户,两个用户的名字分别为tom和jerry,年龄分别为18和20,如果我们想要通过json_query过滤器获取到上述json中的所有user的name,则可以使用如下方法:
--- - hosts: test70 remote_user: root gather_facts: no tasks: - include_vars: file: "/testdir/ansible/testvarfile" name: testvar - debug: msg: "{{ testvar | json_query('users[*].name') }}"
上例的"/testdir/ansible/testvarfile"文件就是上述示例数据所在的文件,它位于ansible主机中,我们将这段数据当做变量赋值给了testvar变量,之后,使用json_query过滤器对这个变量进行了处理,json_query('users[*].name')表示找到users列表中所有元素的name属性,执行上例playbook后,debug模块的输出信息如下:
TASK [debug] ***************************************** ok: [test70] => { "msg": [ "tom", "jerry" ] }
如我们所愿,我们找到了所有用户的name属性,它们被放在了一个列表中展示了出来,你一定已经会举一反三了,查找user列表中的所有元素的age属性的值,则可以使用如下方法
- debug: msg: "{{ testvar | json_query('users[*].age') }}"
我们再来看一段数据,这段数据位于ansible主机的/testdir/ansible/testvarfile1文件中,此处不再将如下yaml数据转换成json格式,在如下示例中,两种格式没有任何区别,示例数据如下
--- test: users: - name: tom age: 18 hobby: - Skateboard - VideoGame - name: jerry age: 20 hobby: - Music
从上述示例可以看出,一共有两个用户,除了姓名和年龄属性,每个用户还有爱好属性,爱好属性是一个列表,如果,我们想要获取到所有的爱好,改怎样使用json_query来完成呢?示例如下:
--- - hosts: test70 remote_user: root gather_facts: no tasks: - include_vars: file: "/testdir/ansible/testvarfile1" name: testvar - debug: msg: "{{ testvar | json_query('test.users[*].hobby[*]') }}"
没错,上例表示,获取到users列表中所有hobby列表的所有项,正如你所看到的,当数据结构中存在列表时,我们可以使用"列表名[*]"获取到列表下面的所有项,那么,我们来执行一下上例的playbook,执行后debug模块输出结果如下:
TASK [debug] ************************************* ok: [test70] => { "msg": [ [ "Skateboard", "VideoGame" ], [ "Music" ] ] }
返回给我们的数据是一个json列表,这个列表中嵌套了两个列表,正是上述示例数据中两个用户的"爱好列表",如果你想要将上例嵌套的列表拉平后输出,则可以使用之前总结的循环进行操作,此处不再赘述。
在上述示例中,我们都是获取到users列表中的所有用户的信息,但是如果我们想要根据条件获取到某个用户的某些信息,该怎么办呢?比如,我想要获取到tom的爱好,则可以使用如下方法:
tasks: - include_vars: file: "/testdir/ansible/testvarfile1" name: testvar - debug: msg: "{{ testvar | json_query('test.users[?name==`tom`].hobby[*]') }}"
上例中,json_query('test.users[?name==`tom`].hobby[*]')表示只查找users列表中name属性等于tom的hobby信息,你肯定发现了,上例中,我们使用了"反引号"将tom引起来了,这是因为当你在添加查询条件时,对需要为对应的值添加引号,但是,上例中msg的值的外侧已经存在一对双引号,双引号内又有一对单引号,所以,为了不让引号之间互相冲突,此处使用反引号将tom引起,除了使用反引号,也可以如下方法,实现相同的效果:
tasks: - include_vars: file: "/testdir/ansible/testvarfile1" name: testvar - debug: msg: "{{ testvar | json_query(querystring) }}" vars: querystring: "test.users[?name=='tom'].age"
如上例所示,我们在debug任务中使用vars关键字定义了一个只有当前debug任务能够使用的变量,从而避免了多层引号嵌套时所产生的冲突问题。
我们也可以同时获取到用户的姓名、年龄两个属性的值,当需要同时获取多个属性值时,需要通过键值对的方式调用属性,示例如下:
tasks: - include_vars: file: "/testdir/ansible/testvarfile1" name: testvar - debug: msg: "{{ testvar | json_query('test.users[*].{uname:name,uage:age}') }}"
如上例所示 ,json_query('test.users[*].{uname:name,uage:age}')表示找到users列表中所有用户的name值和age值,如你所见,uname和uage是我自定义的名称,你也可以随意定义,但是,name和age必须用数据中的属性的键名对应,执行上例playbook后,debug模块输出信息如下:
TASK [debug] ************************************** ok: [test70] => { "msg": [ { "uage": 18, "uname": "tom" }, { "uage": 20, "uname": "jerry" } ] }
如上所示,用户的姓名和年龄都按照我们定义的方式输出了。
好了,说了这么多,json_query过滤器的用法你肯定已经掌握了,所以,我们回过头来,使用json_query来解决一下文章最开始的问题,我们的目标是,使用json_query过滤器找到cdn厂商返回的json数据中的所有日志的logUrl,那么我们可以怎么编写playbook呢?示例如下 :
--- - hosts: test70 remote_user: root gather_facts: no vars_files: - /testdir/ansible/wsCdnLogList tasks: - debug: msg: "{{item}}" with_items: "{{ logs | json_query('[*].files[*].logUrl') }}"
上例playbook的执行效果我就不粘贴了,快动手试试吧。
希望这篇文章能够帮助到你,加油~
我的微信公众号
关注"实用运维笔记"微信公众号,当博客中有新文章时,可第一时间得知哦~
以上所述就是小编给大家介绍的《ansible笔记(32):过滤器(二)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Node.js硬实战:115个核心技巧
【美】Alex R. Young、【美】Marc Harter / 承竹、慕陶、邱娟、达峰 / 电子工业出版社 / 2017-1 / 109.9
《Node.js 硬实战:115 个核心技巧》是一本面向实战的Node.js 开发进阶指南。作为资深专家,《Node.js 硬实战:115 个核心技巧》作者独辟蹊径,将着眼点放在Node.js 的核心模块和网络应用,通过精心组织的丰富实例,向读者充分展示了Node.js 强大的并发处理能力,读者从中可真正掌握Node 的核心基础与高级技巧。《Node.js 硬实战:115 个核心技巧》总共有三部分......一起来看看 《Node.js硬实战:115个核心技巧》 这本书的介绍吧!