ansible采用厨房水槽的方式来实现功能。写这本书的时候,ansible里边大概有300多个模块可用。此外,还有大量的回调插件、查询插件、过滤插件、以及动态库存插件。即便具备这么多功能,仍是有必要添加新功能的须要。python
本章会探索给ansible添加新功能的方法:web
厨房水槽: Kitchen sink, 来源于everything but the kitchen sink。这是二战时期的一个俗语。美国空军战士常常用它来形容他们在敌占区上空所遇到的防空炮火,指敌人炮火猛烈(除了洗碗槽外,各式各样的炮弹齐发)。 如今这个俗语导出使用,能够指"无所不包,包罗万象"。
模块是ansible的马达。它们只提供一种抽象,可让剧本简单明了的启动起来。ansible核心开发团队维护的ansible核心模块大概有150多个,涵盖了云、命令、数据库、文件、网络、包、源控制、系统、工具、web设施等等。另外,还有100多个其余额外模块,主要由社区贡献者维护,它们扩展了这些类别的不少功能。真正神奇就发生在模块代码内部,它们接受传入的参数,而后努力创建预期的结果。docker
ansible中的模块就是传输给远程主机并执行的那点代码。它们可使用远程主机能够执行的任何语言实现。然而,ansible提供了一些很是有用的python语言模块的快捷方式。shell
一个模块的存在就是知足一个需求--须要在主机上完成一些工做。模块,一般但并不老是,指望输入,并返回一些类型的输出。模块同时力图是幂等的,容许一次又一次的运行模块,而不产生负面影响。在ansible中,输入是以命令行参数的形式给到模块,输出是以JSON的形式给到标准输出。输入通常使用空格分隔的key=value语法提供,它是由模块将这些结构分解成可用数据的。若是使用Python, 有一些方便的函数来管理这些,若是使用其余语言,则彻底由模块代码来处理输入。数据库
输出是JSON格式的。惯例规定,在成功的场景中,JSON输出至少要有一个key, changed,这个值是布尔类型,表示模块执行结果是否致使改变。附加数据也能够返回,这些能够定义具体改变了什么,或者给剧本返回一些重要的信息便于后续使用。json
另外,主机事实能够在JSON数据中返回,自动基于模块执行结果建立主机变量。后面咱们会详细看到更多这方面的内容。网络
ansible提供了一种简单的机制来利用来自ansible外部的自定义模块。咱们在第一章已经了解到,ansible会查找不少位置来查找请求的模块。一个这样的路径,第一个路径就是顶级剧本所在目录下面的library/目录。咱们能够将咱们的自定义模块放在这个目录下面,这样咱们就能够在咱们的剧本中使用了。ssh
模块还能够嵌入到角色里边,为角色添加一些可能会依赖的功能。这些模块就只能被包含它们的角色或其余在包含模块的角色以后的其余角色和任务执行。要用角色表达一个模块,就能够将模块放到角色根目录下面的library子目录下面。async
为了演示python实现模块的简单,让咱们建立一个简单的模块。这个模块的目的就是从远程克哦被一个源文件为目标文件,咱们能够从它构建的简单任务。要开始咱们的模块,咱们首先建立模块文件。为了方便访问咱们的新模块,咱们就在工做目录下面建立一个library目录。ide
创建remote_copy.py,其代码以下:
#!/usr/bin/env python # coding=utf-8 import shutil from ansible.module_utils.basic import * def main(): module = AnsibleModule( argument_spec = dict( source = dict(required=True, type="str"), dest = dict(required=True, type="str") ) ) shutil.copy(module.params['source'], module.params['dest']) module.exit_json(changed=True) if __name__ == '__main__': main()
而后创建一个测试剧本:
--- DOCUMENTATION = ''' --- module: remote_copy version_added: future short_description: Copy a file on the remote host description: - The remote_copy module copies a file on the remote host from a given source to a provided destination. options: source: description: - Path to a file on the source file on the remote host required: True dest: description: - Path to the destination on the remote host for the copy required: True author: - Jesse Keating '''
这个字符串的格式彻底是YAML格式的,具备一些包含哈希结构的顶级key, 例如options。
而后咱们可使用ansible-doc来查看模块的文档内容:
ansible-doc -M library/ remote_copy | cat -
注意文档描述必定要用标准的YAML格式,不然查看文档会报错的。
和模块退出附带的数据返回相似,模块还能够直接建立主机事实,经过返回名字为ansible_facts的数据。直接从模块提供事实就消除了使用后续的set_fact任务注册任务返回值的操做。
facts = {'rc_source': module.params['source'], 'rc_dest': module.params['dest']} module.exit_json(changed=True, ansible_facts=facts)
那么在剧情中咱们就能够直接在debug中使用事实中的某个数据了。
- name: show a fact debug: var: rc_dest
而模块若是不返回facts, 那么咱们就须要注册输出,并使用set_fact来为咱们建立事实,就像这样:
- name: do a remote copy remote_copy: source: /tmp/foo dest: /tmp/bar register: mycopy - name: set facts from mycopy set_fact: rc_dest: "{{ mycopy.dest }}"
ansible 1.1以后,支持检查模式,就是一种伪装对系统作修改可是实际上并无改变系统的一种操做模式。检查模式对于测试修改是否真正发生,或者系统状态自从上次ansible运行是否漂移都很是有用。 检查模式依赖于模块是否支持检查模式,并返回数据就像它实际上已经作了改变同样。
为了只是模块支持检查模式,咱们在建立模块对象的时候,须要设置一个参数support_check_mode。
注意设置这个参数能够在定义argument_spec以前,也能够在它以后。这里咱们在argument_spec定义以后:
module = AnsibleModule( argument_spec = dict( source=dict(required=True, type='str'), dest=dict(required=True, type='str') ), supports_check_mode=True )
监测何时检查模式是活动状态很是容易。模块对象就包含一个check_mode属性,若是检查模式是活动状态,这个属性就是True。咱们的模块中,咱们但愿在执行复制以前先看检查模式是否激活。咱们能够简单的将复制行为放入一个if语句里边,避免检查模式是活跃的时候去拷贝了。返回能够发生没有任何改变:
if not module.check_mode: shutil.copy(module.params['source'], module.params['dest'])
那么,如今咱们能够在运行剧本的时候添加一个-C参数来执行。这个参数让剧本执行进行检查模式。 执行完后,看执行的输出好像建立并复制了文件,可是真实却不存在这些文件。
插件是另一种扩展和修改ansible功能的方式。模块是做为任务来执行的,而插件是在其余不少地方利用的。 插件会分解为一些类型,具体依赖于它们在它们能插入ansible执行的什么地方。ansible这些范围的每一个都带有一些插件,终端用户能够建立在这些特定地方的它们本身的功能扩展。
ansible任什么时候间对主机创建链接来执行任务,是使用了一个链接插件。ansible自带了一些链接插件,包括ssh, docker, chroot, local和smart。经过建立链接插件,ansible能够利用附加的链接机制来链接远程主机,这对于链接一些新类型的系统会很是有用,就像网络交换器,或者某天能够链接你的冰箱。 建立链接插件有点超出本书的范围;然而,最简单的起步的方法就是读现有的链接插件的实现。现有插件能够在runner/connection_plugins/里边找到源代码。
和链接插件差很少,ansible用shell插件在shell环境执行一些东西。 每一个shell稍微有所不一样,ansible关心按顺序执行命令、重定向输出、发现错误、以及其余交互。ansible支持几种shell, 包括sh, csh, fish以及powershell。咱们能够经过实现一个新的shell插件添加更多shell。
lookup插件是ansible从主机系统如何访问外部数据源,以及实现语言特性,例如循环构建(with_*)。
回调是放在ansible执行里边的,能够插入一些东西来添加功能。有一些预期的回调点能够注册来在这些点触发用户自定义行为。下面是一些可能触发功能的点:
• runner_on_failed
• runner_on_ok
• runner_on_skipped
• runner_on_unreachable • runner_on_no_hosts
• runner_on_async_poll
• runner_on_async_ok
• runner_on_async_failed
• playbook_on_start
• playbook_on_notify
• playbook_on_no_hosts_matched
• playbook_on_no_hosts_remaining • playbook_on_task_start
• playbook_on_vars_prompt
• playbook_on_setup
• playbook_on_import_for_host
• playbook_on_not_import_for_host • playbook_on_play_start
• playbook_on_stats
ansible运行到达这些装袋的每一个点,任何有代码的插件均可以在这些点上被执行。这就提供了极大的能力去扩展ansible而无需修改基础代码。
回调能够用不少方式利用:
ansible是一个强大的工具,然而,有时候它可能没有提供某些须要的全部功能。并非每个功能都适合由主项目来支持,也不可能集成自定义的专有数据源。出于这些缘由,ansible里边存在能够扩展功能的设施。因为共享模块的基本代码,建立和使用自定义模块变得很容易。不少不一样类型的插件能够建立并和ansible一块儿使用,以各类方式影响操做。超出ansible支持的库存源依然能相对容易和高效的使用。
在全部状况下,都有一种机制来提供模块、插件和库存源,以及依赖于加强功能的剧本和角色,使其无缝分布。