本文也属于《Ansible Playbook速成实战》系列。不废话,让我们直接开始!
什么需求?
在《稍微复杂一些的例子》完成后,老板又提出了大胆的的想法:
保存的文件,文件名能不能加上编号?
稍微想一下就知道,为了实现老板这一句话的想法,playbook需要实现以下功能:
- 读取文件列表
- 筛选同类文件,如“info_<数字编号>.log”
- 获取同类文件最大编号
- 用“最大编号+1”生成新文件名
好麻烦……与其费尽心机写出惊世骇俗的YAML,还不如直接写Python实现这些功能。
本例中涉及到的知识点
- 用Python手撮Ansible模块并在playbook中调用
开始整活
1. 创建工作目录
在主目录中增加目录library
和Python文件:
pj/ (主目录)
|- library (!)/
|- my_create_path.py
|- (其他目录/文件略)
带“!”的目录,目录名请与下述保持一致。Ansible会自动从中读取所需内容。
2. 手撮Ansible模块
编辑pj/library/my_create_path.py
,写入所需功能。
import os
import re
from ansible.module_utils.basic import AnsibleModule
## ^ 此乃事情的关键
def create_new_path(pth_info):
## 要求pth_info的内容物:{'dir': xxx, 'prefix': xxx, 'suffix': xxx}
fname_pattern = re.compile(r'^{}(\d+){}$'.format(pth_info['prefix'], pth_info['suffix']))
numbers = []
files = os.listdir(pth_info['dir'])
for file in files:
match = fname_pattern.match(file)
if match:
number = int(match.group(1))
numbers.append(number)
if numbers:
max_number = max(numbers)
next_number = max_number + 1
else:
next_number = 1
## ^ 要是原本目录中没有同类文件则使用编号1
new_filename = f"{pth_info['prefix']}{next_number}{pth_info['suffix']}"
new_path = os.path.join(pth_info['dir'], new_filename)
return new_path
def main():
module = AnsibleModule(argument_spec=dict(pth_info=dict(type='dict', required=True)))
## ^ 不熟悉这种写法的话也可以写成:argument_spec={'pth_info': {'type': 'dict', 'required': True}}
## 这段翻译一下就是:调用该模块时,需要传入名为“pth_info”、类型为“dict”的变量,而且是必须的
## 至于变量“pth_info”里面应该有什么,那就是具体实现功能的函数需要操心的事了
result = create_new_path(module.params['pth_info'])
## ^ 通过“module.params['pth_info']”获取playbook的传入变量
module.exit_json(changed=False, result=result)
if __name__ == '__main__':
main()
3. Playbook中调用手撮的Ansible模块
将以下内容写入用于生成文件名的role。
- name: 生成带编号的文件名
my_create_path:
# ^ 使用手撮模块时,模块名称同PY文件名
pth_info:
# ^ 这个是手撮模块中定义的名称
dir: "/tmp/fetch_from_remote"
prefix: "info_"
suffix: ".log"
# ^ 这3个是手撮模块中“create_new_path”函数要求的
register:
new_filename
delegate_to: localhost
大功告成🎉,接下来就可以通过在保存文件的role中使用{{ new_filename.result }}
作为文件名保存文件了!