ansible 模块
Ansible通过连接到节点并发送称为模块的小型程序来远程执行工作。 这使得它成为一个推式架构,其中配置从Ansible推到没有代理的服务器,这与基于代理的配置管理系统中通常会拉取配置的拉取模型相反。
这些模块映射到资源及其各自的状态 ,这些状态在YAML文件中表示。 它们使您几乎可以管理所有具有可以与之交互的API,CLI或配置文件的内容,包括网络设备,例如负载平衡器,交换机,防火墙,容器协调器,容器本身,甚至虚拟机管理程序或操作系统中的虚拟机实例。公共(例如,AWS,GCE,Azure)和/或私有(例如,OpenStack,CloudStack)云,以及存储和安全设备以及系统配置。
使用Ansible的内置电池模型时,包含了数百个模块,并且剧本中的任何任务都在其后方有一个模块。
标准输出中的JSON 。 YAML文件中声明的配置通过SSH / WinRM或任何其他连接插件通过网络传递,作为要在目标服务器中执行的小脚本。 尽管大多数Ansible模块(Windows PowerShell除外)都是使用Ansible API用Python编写的(这简化了新模块的开发),但是模块可以用任何能够返回JSON的语言编写。模块是扩展Ansible功能的一种方法。 其他选择,例如动态清单和插件,也可以提高Ansible的功能。 了解它们很重要,这样您才能知道何时使用一种而不是另一种。
插件分为几个类别,分别具有不同的目标,例如操作,缓存,回调,连接,过滤器,查找和变量。 最受欢迎的插件是:
- 连接插件:这些插件实现了一种与清单中的服务器进行通信的方式(例如SSH,WinRM,Telnet); 换句话说,自动化代码如何通过网络传输以执行。
- 过滤器插件:这些插件可让您在剧本中操作数据。 这是Ansible所利用的Jinja2功能,可以解决基础架构即代码的问题。
- 查找插件:这些插件从外部来源(例如,env,文件,Hiera,数据库,HashiCorp Vault)获取数据。
Ansible的官方文档是开发插件的好资源。
什么时候应该开发模块?
尽管Ansible随附了许多模块,但仍有可能您的问题尚未解决或问题过于具体(例如,仅在您的组织中有意义的解决方案)。 幸运的是,官方文档为开发模块提供了出色的指导。
重要说明:开始进行新工作之前,请务必检查是否有打开的请求,请在#ansible-devel(IRC / Freenode)上询问开发人员,或搜索开发列表和/或现有工作组以查看模块是否存在或在其中。发展。
您需要一个新模块而不是使用现有模块的迹象包括:
- 常规的配置管理方法(例如,模板,文件,get_url,lineinfile)无法正确解决您的问题。
- 您必须使用命令,外壳程序,过滤器,带有魔术正则表达式的文本处理以及使用curl进行API调用的复杂组合才能实现目标。
- 您的剧本是复杂的,命令性的,非幂等的,甚至是不确定的。
在理想情况下,该工具或服务已经具有用于管理的API或CLI,并且它返回某种结构化数据(JSON,XML,YAML)。
识别好坏书
“做爱,但不要在YAML中创建shell脚本。”
那么,是什么让一部糟糕的剧本呢?
- name
: Read a remote resource
command
:
"curl -v http://xpto/resource/abc"
register
: resource
changed_when
: False
- name
: Create a resource in case it does not exist
command
:
"curl -X POST http://xpto/resource/abc -d '{ config:{ client: xyz, url: http://beta, pattern: *.* } }'"
when
:
"resource.stdout | 404"
# Leave it here in case I need to remove it hehehe
#- name: Remove resource
# command: "curl -X DELETE http://xpto/resource/abc"
# when: resource.stdout == 1
除了非常脆弱之外(如果资源状态在某处包含404,该怎么办?),并要求额外的代码具有幂等性,该剧本在状态改变时也无法更新资源。
用这种方式编写的剧本不尊重许多基础架构即代码原则。 它们不为人类所理解,难以重用和参数化,并且不遵循大多数配置管理工具所鼓励的声明性模型。 它们也不能成为幂等并收敛到声明的状态。
错误的剧本可能会危害您的自动化采用。 它们没有利用配置管理工具来提高速度,而是与基于脚本和命令执行的命令式自动化方法存在相同的问题。 这会创建一个场景,在该场景中,您将使用Ansible作为传递旧脚本的一种方式,将已经拥有的脚本复制到YAML文件中。
这是重写此示例以遵循基础结构即代码原则的方法。
- name
: XPTO
xpto :
name
: abc
state
: present
config :
client
: xyz
url
: http://beta
pattern
:
"*.*"
这种基于自定义模块的方法的优点包括:
- 它是声明性的-资源在YAML中正确表示。
- 这是幂等的。
- 它从声明的状态收敛到当前状态 。
- 它是人类可读的。
- 它很容易参数化或重复使用。
实施自定义模块
让我们以一个开放源代码Java应用服务器WildFly为例,为我们不太好的剧本引入自定义模块:
- name
: Read datasource
command
:
"jboss-cli.sh -c '/subsystem=datasources/data-source=DemoDS:read-resource()'"
register
: datasource
- name
: Create datasource
command
:
"jboss-cli.sh -c '/subsystem=datasources/data-source=DemoDS:add(driver-name=h2, user-name=sa, password=sa, min-pool-size=20, max-pool-size=40, connection-url=.jdbc:h2:mem:demo;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE..)'"
when
: 'datasource.stdout | outcome => failed'
问题:
- 这不是声明性的。
- JBoss-CLI以类似JSON的语法返回纯文本。 因此,这种方法非常脆弱,因为我们需要一种表示法的解析器。 甚至看似简单的解析器也可能太复杂而无法处理许多异常 。
- JBoss-CLI只是一个将请求发送到管理API(端口9990)的接口。
- 发送HTTP请求比打开新的JBoss-CLI会话,连接和发送命令更有效。
- 它没有收敛到期望的状态。 它仅在不存在时创建资源。
为此的自定义模块如下所示:
- name
: Configure datasource
jboss_resource :
name
:
"/subsystem=datasources/data-source=DemoDS"
state
: present
attributes :
driver-name
: h2
connection-url
:
"jdbc:h2:mem:demo;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"
jndi-name
:
"java:jboss/datasources/DemoDS"
user-name
: sa
password
: sa
min-pool-size
: 20
max-pool-size
: 40
该剧本是声明性的,幂等的,更具可读性的,并且无论当前状态如何,都可以收敛到所需状态。
为什么要学习构建自定义模块?
学习如何构建定制模块的充分理由包括:
- 改善现有模块
- 您有不良的剧本,并希望对其进行改进,或者…
- 您没有,但是想要避免有不良的剧本。
- 知道如何构建模块可以大大提高您调试剧本中问题的能力,从而提高生产率。
“……抽象为我们节省了工作时间,但并没有节省我们学习的时间。” — Joel Spolsky, 泄漏抽象定律
自定义Ansible模块101
- stdout中的JSON (JavaScript对象表示法):这就是合同!
- 它们可以用任何语言编写,但是…
- Python通常是最好的选择(或第二好的选择)
- Ansible附带的大多数模块( lib / ansible / modules )都是用Python编写的,应该支持兼容版本。
Ansible方式
- 第一步:
git clone https://github.com/ansible/ansible.git
- 浏览lib / ansible / modules /并阅读现有的模块代码。
- 您的工具是:Git,Python,virtualenv,pdb(Python调试器)
- 有关全面的说明,请参阅官方文档 。
替代方法:将其放在库目录中
library/ # if any custom modules, put them here (optional)
module_utils/ # if any custom module_utils to support modules, put them here (optional)
filter_plugins/ # if any custom filter plugins, put them here (optional)
site.yml # master playbook
webservers.yml # playbook for webserver tier
dbservers.yml # playbook for dbserver tier
roles/
common/ # this hierarchy represents a "role"
library/ # roles can also include custom modules
module_utils/ # roles can also include custom module_utils
lookup_plugins/ # or other types of plugins, like lookup in this case
- 开始更容易。
- 除了Ansible和您最喜欢的IDE /文本编辑器之外,不需要任何其他功能。
- 如果要在内部使用,这是最好的选择。
提示:例如,如果需要修补模块,则可以使用此目录布局覆盖现有模块。
第一步
您可以自己完成操作(包括使用另一种语言),也可以使用AnsibleModule类,因为按照Ansible期望的方式( msg , meta ,将JSON放入stdout( exit_json() , fail_json() )更容易。 has_changed , result ),也更容易处理输入( params [] )和记录其执行( log() , debug() )。
def main
(
) :
arguments
=
dict
( name
=
dict
( required
=
True
,
type
=
'str'
)
,
state
=
dict
( choices
=
[
'present'
,
'absent'
]
, default
=
'present'
)
,
config
=
dict
( required
=
False
,
type
=
'dict'
)
)
module
= AnsibleModule
( argument_spec
= arguments
, supports_check_mode
=
True
)
try :
if module.
check_mode :
# Do not do anything, only verifies current state and report it
module.
exit_json
( changed
= has_changed
, meta
= result
, msg
=
'Fez alguma coisa ou não...'
)
if module.
params
[
'state'
]
==
'present' :
# Verify the presence of a resource
# Desired state `module.params['param_name'] is equal to the current state?
module.
exit_json
( changed
= has_changed
, meta
= result
)
if module.
params
[
'state'
]
==
'absent' :
# Remove the resource in case it exists
module.
exit_json
( changed
= has_changed
, meta
= result
)
except Error
as err:
module.
fail_json
( msg
=
str
( err
)
)
注意: check_mode (“ 空运行”)允许执行剧本或仅验证是否需要更改,但不执行更改。 另外, module_utils目录可用于不同模块之间的共享代码。
对于完整的Wildfly示例,请检查此pull request 。
运行测试
Ansible方式
所述Ansible代码库是大量测试,每次提交触发器在它的持续集成(CI)服务器,构建可发运 ,其包括掉毛,单元测试和集成测试。
对于集成测试,它使用容器和Ansible本身来执行设置和验证阶段。 这是自定义模块的示例代码的测试用例(用Ansible编写):
- name
: Configure datasource
jboss_resource :
name
:
"/subsystem=datasources/data-source=DemoDS"
state
: present
attributes :
connection-url
:
"jdbc:h2:mem:demo;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"
...
register
: result
- name
: assert output message that datasource was created
assert :
that
:
-
"result.changed == true"
-
"'Added /subsystem=datasources/data-source=DemoDS' in result.msg"
另一种选择:将模块与您的角色捆绑在一起
这是一个简单角色内的完整示例 :
分子 + 流浪 + pytest : molecule init
(内角色/)
它提供了更大的灵活性来选择:
- 简化设置
- 如何提升基础架构:例如,Vagrant,Docker,OpenStack,EC2
- 如何验证基础架构测试:Testinfra和Goss
但是您的测试必须使用带有Testinfra或Goss的pytest编写,而不是简单的Ansible。 如果您想了解有关测试Ansible角色的更多信息,请参阅有关使用Molecule的文章。
翻译自: https://opensource.com/article/19/3/developing-ansible-modules
ansible 模块