Ansible使用的是Python语言,代码质量还是蛮高的,因此使用Python对其进行二次开发是最方便的,它自己提供的模块和功能基本能覆盖所有日常使用场景,但是如果出现比较复杂同时又紧贴业务的情况,想要对这种复杂功能进行封装,进一步提高效率,就需要对Ansible进行二次开发,来满足这些定制化的需求
Ansible其实被封装成了一个名为ansible的python模块,在安装完成后,能通过pip查看到这个python模块。因此可以通过在python代码里面import这个模块来调用Ansible对外提供的API,典型的就是ansible和ansible-playbook这两个命令,它们就是两个python脚本,通过调用ansible模块来实现所有功能的
所以理论上,可以通过自己编写脚本import这个ansible模块来实现所有的Ansible的功能
下面是官方文档里面的一个老版本的调用示例,2.6及以上版本已经大改了API,这方面文档很少,貌似只能通过看源码来理解,当然大家如果有什么好的文档和链接可以留言
import ansible.runner
runner = ansible.runner.Runner(
module_name='ping',
module_args='',
pattern='web*',
forks=10
)
datastructure = runner.run()
Ansible提供的基础功能单元叫做模块,执行playbook的过程就是,读取playbook中记录的模块调用逻辑,来依次调用各个模块从而完成整个功能。
因此,我们可以通过自定义模块来扩展Ansible的功能
最方便的扩展自定义模块的方式就是——在Ansible的一级目录下面创建个library目录,把自定义的python文件放到里面,这样playbook里面就可以直接使用这个扩展模块。当然也可以在各个role的目录下创建这个library目录,这里面的扩展模块仅供这个role来使用。当然也可以修改Ansible配置文件来指定library的路径,细节可以参考官方文档。
下面是个最简单的模块的例子,它是在官方示例的tomcat-standalone的基础上增加一个自定义模块:hdz_test1
[root@10-10-20-194 tomcat-standalone]# tree
.
├── group_vars
│ └── tomcat-servers
├── hosts
├── library # 增加的library目录
│ ├── hdz_test1.py # 自定义模块的python代码
│ └── __init__.py
├── LICENSE.md
├── README.md
├── roles
│ ├── hdz
│ │ └── tasks
│ │ └── main.yml # 测试自定义模块的playbook配置
│ ├── selinux
│ │ └── tasks
│ │ └── main.yml
│ └── tomcat
│ ├── files
│ │ └── tomcat-initscript.sh
│ ├── handlers
│ │ └── main.yml
│ ├── tasks
│ │ └── main.yml
│ └── templates
│ ├── iptables-save
│ ├── server.xml
│ └── tomcat-users.xml
├── site.retry
└── site.yml
12 directories, 16 files
自定义模块的写法可以参考Ansible源码中定义模块的写法,还是比较容易能看懂的,比如:command模块的代码,示例自定义模块代码:
#!/usr/bin/env python
# -*- coding:UTF-8
"""
Created on 2018/8/9
Author: hdzhang
Description:
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = '''
---
module: hdz_test1
author: hdzhang
short_description: test
version_added: "0.0.1"
description:
- test create file
options:
name:
description:
- name of the create file
required: true
context:
description:
- context of the create file
required: false
default: ""
'''
EXAMPLES = '''
- name: create a file
hdz_test1:
name: "hdz1.txt"
context: "qnmlgb"
'''
RETURN = '''# '''
from ansible.module_utils.basic import AnsibleModule
import datetime
def run_module():
module_args = dict(
name=dict(type='str', required=True),
context=dict(type='str', required=False),
)
module = AnsibleModule(
argument_spec=module_args,
supports_check_mode=True,
add_file_common_args=True,
)
# Gather module parameters in variables
name = module.params.get('name')
context = module.params['context']
result = dict(
changed=False,
stdout='',
stderr='',
rc='',
start='',
end='',
delta='',
)
if module.check_mode:
return result
startd = datetime.datetime.now()
cmd = "echo %s > /root/%s" % (context, name)
rc, out, err = module.run_command(cmd, use_unsafe_shell=True)
endd = datetime.datetime.now()
delta = endd - startd
result = dict(
cmd=cmd,
start=str(startd),
end=str(endd),
delta=str(delta),
rc=rc,
stdout=out.rstrip(b"\r\n"),
stderr=err.rstrip(b"\r\n"),
changed=True,
)
if rc != 0:
module.fail_json(msg='non-zero return code', **result)
module.exit_json(**result)
def main():
run_module()
if __name__ == '__main__':
main()
---
- name: create a file
hdz_test1:
name: "test.txt"
context: "qnmlgb"
待补充
官方开发文档
Ansible经典示例