ansible笔记(32):过滤器(二)

  • A+
所属分类:ansible  运维技术

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

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

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

 

之前已经总结过一些过滤器的用法,这篇文章我们继续来认识一些其他的过滤器。

 

在实际工作中,经常需要调用别人的接口,别人的接口会返回我们需要的数据,有时候,返回的数据就是json格式的,比如,公司为某些域名配置了CDN,当我们需要分析这些域名的访问日志时,则需要从CDN厂商获取到对应的日志,通常情况下,CDN服务商会暴露一个接口给我们,我们调用这个接口,即可获取到对应域名的日志列表,然后根据列表下载所有的日志,从而达到我们的目的,我们先一起来看一段示例数据,如下数据是我调用了CDN厂商接口后,返回的一段json格式的数据,如下

这段json数据并没有很高的可读性,因为它并没有进行任何缩进和换行,如果你想让这段数据有更高的可读性,则可以将这段数据所在的文件当做变量文件引入到playbook中,然后输出对应的变量即可,示例如下

如上例所示,"/testdir/ansible/wsCdnLogList"就是上述json数据所在的文件,它位于ansible主机中,我们使用include_vars模块,将此文件当做变量文件引入了playbook中,在总结变量时我们提到过,变量文件的格式可以是yaml格式的,也可以是json格式的,上例就是将json格式的数据文件当做变量文件使用的,并且,将此文件的json数据赋值给了testvar变量,然后使用debug模块输出了testvar变量的值,那么,我们执行一下上例的playbook,可以发现,json数据已经被格式化为了有一定可读性的json文本输出在了控制台中,输出信息如下:

其实,json是yaml的子集,yaml是json的超集,yaml格式的数据和json格式的数据是可以互相转换的,所以,对于ansible来说,当我们把上例中的json数据文件当做变量文件引入时,就好像引入了一个我们定义好的yaml格式的变量文件一样,对于ansible来说是没有区别的,而且,即使在变量文件中使用yaml格式定义了变量,在使用debug模块输出变量信息时,ansible也会自动将yaml格式的数据转化为json格式后进行输出,细心如你一定已经在前面的文章中发觉到这一点了,那么,我们把上述json数据转换成yaml的格式,同时列出上述数据的json格式与yaml格式,你可以根据自己的使用习惯,选择阅读哪种格式的数据,以便你能够更好的理解这段数据的含义,yaml格式如下

从上述信息可以看出,cdn厂商返回的j数据是一个日志列表,这个日志列表中一共有两个对象,对象的属性有"domainName"和 "files",很明显,cdn厂商将日志按照域名进行了划分,返回了对应域名下的所有日志, "files"属性是一个列表,列表中列出了对应域名中的所有日志文件的信息,第一个域名的files列表中只有一个日志文件,第二个域名的files列表中一共有两个日志文件。

 

此刻,如果我们想要获取到整个列表中的所有日志文件的logUrl,我们该怎么办呢?

没错,聪明如你一定想到了,我们可以通过with_subelements循环,获取到当前整个大列表中的所有日志的logUrl属性,前文已经总结过了with_subelements的用法,此处不再赘述,如果你忘记了它的用法,请回顾前文,此处直接写出示例,如下:

其实,除了使用with_subelements,我们还有另外一种方法,就是使用过滤器,有一个名为json_query的过滤器,可以帮助我们解决上述问题。

 

我们先来看几个关于json_query的小示例,等熟悉了json_query过滤器以后,再回过头来通过json_query解决上面的问题,小示例如下

假设我们现在有一段简单的json数据,如下:

上述json数据的yaml格式如下:

从上述示例可以看出,一共有两个用户,两个用户的名字分别为tom和jerry,年龄分别为18和20,如果我们想要通过json_query过滤器获取到上述json中的所有user的name,则可以使用如下方法:

上例的"/testdir/ansible/testvarfile"文件就是上述示例数据所在的文件,它位于ansible主机中,我们将这段数据当做变量赋值给了testvar变量,之后,使用json_query过滤器对这个变量进行了处理,json_query('users[*].name')表示找到users列表中所有元素的name属性,执行上例playbook后,debug模块的输出信息如下:

如我们所愿,我们找到了所有用户的name属性,它们被放在了一个列表中展示了出来,你一定已经会举一反三了,查找user列表中的所有元素的age属性的值,则可以使用如下方法

 

我们再来看一段数据,这段数据位于ansible主机的/testdir/ansible/testvarfile1文件中,此处不再将如下yaml数据转换成json格式,在如下示例中,两种格式没有任何区别,示例数据如下

从上述示例可以看出,一共有两个用户,除了姓名和年龄属性,每个用户还有爱好属性,爱好属性是一个列表,如果,我们想要获取到所有的爱好,改怎样使用json_query来完成呢?示例如下:

没错,上例表示,获取到users列表中所有hobby列表的所有项,正如你所看到的,当数据结构中存在列表时,我们可以使用"列表名[*]"获取到列表下面的所有项,那么,我们来执行一下上例的playbook,执行后debug模块输出结果如下:

返回给我们的数据是一个json列表,这个列表中嵌套了两个列表,正是上述示例数据中两个用户的"爱好列表",如果你想要将上例嵌套的列表拉平后输出,则可以使用之前总结的循环进行操作,此处不再赘述。

 

在上述示例中,我们都是获取到users列表中的所有用户的信息,但是如果我们想要根据条件获取到某个用户的某些信息,该怎么办呢?比如,我想要获取到tom的爱好,则可以使用如下方法:

上例中,json_query('test.users[?name==`tom`].hobby[*]')表示只查找users列表中name属性等于tom的hobby信息,你肯定发现了,上例中,我们使用了"反引号"将tom引起来了,这是因为当你在添加查询条件时,对需要为对应的值添加引号,但是,上例中msg的值的外侧已经存在一对双引号,双引号内又有一对单引号,所以,为了不让引号之间互相冲突,此处使用反引号将tom引起,除了使用反引号,也可以如下方法,实现相同的效果:

如上例所示,我们在debug任务中使用vars关键字定义了一个只有当前debug任务能够使用的变量,从而避免了多层引号嵌套时所产生的冲突问题。

 

我们也可以同时获取到用户的姓名、年龄两个属性的值,当需要同时获取多个属性值时,需要通过键值对的方式调用属性,示例如下:

如上例所示 ,json_query('test.users[*].{uname:name,uage:age}')表示找到users列表中所有用户的name值和age值,如你所见,uname和uage是我自定义的名称,你也可以随意定义,但是,name和age必须用数据中的属性的键名对应,执行上例playbook后,debug模块输出信息如下:

如上所示,用户的姓名和年龄都按照我们定义的方式输出了。

 

好了,说了这么多,json_query过滤器的用法你肯定已经掌握了,所以,我们回过头来,使用json_query来解决一下文章最开始的问题,我们的目标是,使用json_query过滤器找到cdn厂商返回的json数据中的所有日志的logUrl,那么我们可以怎么编写playbook呢?示例如下 :

上例playbook的执行效果我就不粘贴了,快动手试试吧。

 

希望这篇文章能够帮助到你,加油~

 

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

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

目前评论:3   其中:访客  2   博主  1

    • avatar echo 6

      一看就会 一学就懂 一做就做错系列 :lol:

      • avatar 怒风 3

        又一个优秀的知识讲解,感谢博主!很详细很通俗,连我都能看懂,其他同学肯定都没问题啦~

          • avatar 朱双印 Admin

            @怒风 快速阅读完成并迅速捧场~~~666~~~