在实际工作中,经常需要调用别人的接口,别人的接口会返回我们需要的数据,有时候,返回的数据就是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: all
remote_user: root
gather_facts: no
tasks:
- include_vars:
file: "/testdir/ansible/wsCdnLogList"
name: testvar
- debug:
msg: "{{ testvar }}"
结果如下:
[root@ansible-master ansible]# ansible-playbook if.yml
PLAY [all] **************************************************************************************
TASK [include_vars] *****************************************************************************
ok: [192.168.174.144]
ok: [192.168.174.145]
TASK [debug] ************************************************************************************
ok: [192.168.174.144] => {
"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"
}
]
}
]
}
}
ok: [192.168.174.145] => {
"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"
}
]
}
]
}
}
PLAY RECAP **************************************************************************************
192.168.174.144 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.174.145 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@ansible-master ansible]#
其实,json是yaml的子集,yaml是json的超集,yaml格式的数据和json格式的数据是可以互相转换的,所以,对于ansible来说,当我们把上例中的json数据文件当做变量文件引入时,就好像引入了一个我们定义好的yaml格式的变量文件一样,对于ansible来说是没有区别的,而且,即使在变量文件中使用yaml格式定义了变量,在使用debug模块输出变量信息时,ansible也会自动将yaml格式的数据转化为json格式后进行输出
如果我想获取到所有的logUrl,可以
tasks:
- include_vars:
file: "/testdir/ansible/wsCdnLogList"
name: testvar
- debug:
msg: "{{ item.1.logUrl }}"
with_subelements:
- "{{testvar.logs}}"
- files
其实,除了使用with_subelements,我们还有另外一种方法,就是使用过滤器,有一个名为json_query的过滤器,可以帮助我们解决上述问题。
这是一段简单的json:
{
"users": [
{
"name": "tom",
"age": 18
},
{
"name": "jerry",
"age": 20
}
]
}
转换成yml:
---
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') }}"
注:注意json_query的使用方法
当数据结构中存在列表时,我们可以使用”列表名[*]”获取到列表下面的所有项,查询某一个时可以使用下面的语句:
tasks:
- include_vars:
file: "/testdir/ansible/testvarfile1"
name: testvar
- debug:
msg: "{{ testvar | json_query('test.users[?name==`tom`].hobby[*]') }}"
所以,为了不让引号之间互相冲突,此处使用反引号将tom引起
一些常见的过滤器:
---
- hosts: test70
remote_user: root
gather_facts: no
tasks:
######################################################################
#在调用shell模块时,如果引用某些变量时需要添加引号,则可以使用quote过滤器代替引号
#示例如下,先看示例,后面会有注解
- shell: "echo {{teststr | quote}} > /testdir/testfile"
vars:
teststr: "a\nb\nc"
#上例中shell模块的写法与如下写法完全等效
#shell: "echo '{{teststr}}' > /testdir/testfile"
#没错,如你所见,quote过滤器能够代替引号
#上例中,如果不对{{teststr}}添加引号,则会报错,因为teststr变量中包含"\n"转义符
######################################################################
#ternary过滤器可以实现三元运算的效果 示例如下
#如下示例表示如果name变量的值是John,那么对应的值则为Mr,否则则为Ms
#简便的实现类似if else对变量赋值的效果
- debug:
msg: "{{ (name == 'John') | ternary('Mr','Ms') }}"
vars:
name: "John"
######################################################################
#basename过滤器可以获取到一个路径字符串中的文件名
- debug:
msg: "{{teststr | basename}}"
vars:
teststr: "/testdir/ansible/testfile"
######################################################################
#获取到一个windows路径字符串中的文件名,2.0版本以后的ansible可用
- debug:
msg: "{{teststr | win_basename}}"
vars:
teststr: 'D:\study\zsythink'
######################################################################
#dirname过滤器可以获取到一个路径字符串中的路径名
- debug:
msg: "{{teststr | dirname}}"
vars:
teststr: "/testdir/ansible/testfile"
######################################################################
#获取到一个windows路径字符串中的文件名,2.0版本以后的ansible可用
- debug:
msg: "{{teststr | win_dirname}}"
vars:
teststr: 'D:\study\zsythink'
######################################################################
#将一个windows路径字符串中的盘符和路径分开,2.0版本以后的ansible可用
- debug:
msg: "{{teststr | win_splitdrive}}"
vars:
teststr: 'D:\study\zsythink'
#可以配合之前总结的过滤器一起使用,比如只获取到盘符,示例如下
#msg: "{{teststr | win_splitdrive | first}}"
#可以配合之前总结的过滤器一起使用,比如只获取到路径,示例如下
#msg: "{{teststr | win_splitdrive | last}}"
######################################################################
#realpath过滤器可以获取软链接文件所指向的真正文件
- debug:
msg: "{{ path | realpath }}"
vars:
path: "/testdir/ansible/testsoft"
######################################################################
#relpath过滤器可以获取到path对于“指定路径”来说的“相对路径”
- debug:
msg: "{{ path | relpath('/testdir/testdir') }}"
vars:
path: "/testdir/ansible"
######################################################################
#splitext过滤器可以将带有文件名后缀的路径从“.后缀”部分分开
- debug:
msg: "{{ path | splitext }}"
vars:
path: "/etc/nginx/conf.d/test.conf"
#可以配置之前总结的过滤器,获取到文件后缀
#msg: "{{ path | splitext | last}}"
#可以配置之前总结的过滤器,获取到文件前缀名
#msg: "{{ path | splitext | first | basename}}"
######################################################################
#to_uuid过滤器能够为对应的字符串生成uuid
- debug:
msg: "{{ teststr | to_uuid }}"
vars:
teststr: "This is a test statement"
######################################################################
#bool过滤器可以根据字符串的内容返回bool值true或者false
#字符串的内容为yes、1、True、true则返回布尔值true,字符串内容为其他内容则返回false
- debug:
msg: "{{ teststr | bool }}"
vars:
teststr: "1"
#当和用户交互时,有可能需要用户从两个选项中选择一个,比如是否继续,
#这时,将用户输入的字符串通过bool过滤器处理后得出布尔值,从而进行判断,比如如下用法
#- debug:
# msg: "output when bool is true"
# when: some_string_user_input | bool
######################################################################
#map过滤器可以从列表中获取到每个元素所共有的某个属性的值,并将这些值组成一个列表
#当列表中嵌套了列表,不能越级获取属性的值,也就是说只能获取直接子元素的共有属性值。
- vars:
users:
- name: tom
age: 18
hobby:
- Skateboard
- VideoGame
- name: jerry
age: 20
hobby:
- Music
debug:
msg: "{{ users | map(attribute='name') | list }}"
#也可以组成一个字符串,用指定的字符隔开,比如分号
#msg: "{{ users | map(attribute='name') | join(';') }}"
######################################################################
#与python中的用法相同,两个日期类型相减能够算出两个日期间的时间差
#下例中,我们使用to_datatime过滤器将字符串类型转换成了日期了类型,并且算出了时间差
- debug:
msg: '{{ ("2016-08-14 20:00:12"| to_datetime) - ("2012-12-25 19:00:00" | to_datetime) }}'
#默认情况下,to_datatime转换的字符串的格式必须是“%Y-%m-%d %H:%M:%S”
#如果对应的字符串不是这种格式,则需要在to_datetime中指定与字符串相同的时间格式,才能正确的转换为时间类型
- debug:
msg: '{{ ("20160814"| to_datetime("%Y%m%d")) - ("2012-12-25 19:00:00" | to_datetime) }}'
#如下方法可以获取到两个日期之间一共相差多少秒
- debug:
msg: '{{ ( ("20160814"| to_datetime("%Y%m%d")) - ("20121225" | to_datetime("%Y%m%d")) ).total_seconds() }}'
#如下方法可以获取到两个日期“时间位”相差多少秒,注意:日期位不会纳入对比计算范围
#也就是说,下例中的2016-08-14和2012-12-25不会纳入计算范围
#只是计算20:00:12与08:30:00相差多少秒
#如果想要算出连带日期的秒数差则使用total_seconds()
- debug:
msg: '{{ ( ("2016-08-14 20:00:12"| to_datetime) - ("2012-12-25 08:30:00" | to_datetime) ).seconds }}'
#如下方法可以获取到两个日期“日期位”相差多少天,注意:时间位不会纳入对比计算范围
- debug:
msg: '{{ ( ("2016-08-14 20:00:12"| to_datetime) - ("2012-12-25 08:30:00" | to_datetime) ).days }}'
######################################################################
#使用base64编码方式对字符串进行编码
- debug:
msg: "{{ 'hello' | b64encode }}"
#使用base64编码方式对字符串进行解码
- debug:
msg: "{{ 'aGVsbG8=' | b64decode }}"
#######################################################################
#使用sha1算法对字符串进行哈希
- debug:
msg: "{{ '123456' | hash('sha1') }}"
#使用md5算法对字符串进行哈希
- debug:
msg: "{{ '123456' | hash('md5') }}"
#获取到字符串的校验和,与md5哈希值一致
- debug:
msg: "{{ '123456' | checksum }}"
#使用blowfish算法对字符串进行哈希,注:部分系统支持
- debug:
msg: "{{ '123456' | hash('blowfish') }}"
#使用sha256算法对字符串进行哈希,哈希过程中会生成随机"盐",以便无法直接对比出原值
- debug:
msg: "{{ '123456' | password_hash('sha256') }}"
#使用sha256算法对字符串进行哈希,并使用指定的字符串作为"盐"
- debug:
msg: "{{ '123456' | password_hash('sha256','mysalt') }}"
#使用sha512算法对字符串进行哈希,哈希过程中会生成随机"盐",以便无法直接对比出原值
- debug:
msg: "{{ '123123' | password_hash('sha512') }}"
#使用sha512算法对字符串进行哈希,并使用指定的字符串作为"盐"
- debug:
msg: "{{ '123123' | password_hash('sha512','ebzL.U5cjaHe55KK') }}"
#如下方法可以幂等的为每个主机的密码生成对应哈希串
#有了之前总结的过滤器用法作为基础,你一定已经看懂了
- debug:
msg: "{{ '123123' | password_hash('sha512', 65534|random(seed=inventory_hostname)|string) }}"