分析ansible源码模块中test-module是如何实现自定义模块测试的

分析ansible源码模块中test-module是如何实现自定义模块测试的,第1张

分析ansible源码模块中test-module是如何实现自定义模块测试的

1.为什么会有这篇文章的介绍?

在ansible文档中,有一篇介绍用户自定义模块的文章,链接地址如下:开发模块。但是测试的时候总会出现异常,后面的 *** 作无法继续,所以我看看怎么测试模块。


2.有两种自定义模块。

1> 不传参数的,如下 # ansible -i hosts hostgroup -m ping -k  2> 传递参数的, 如下 # ansible -i hsots hostgroup -m shell -a 'uptime' -k

Ansible的文档也给出了两个相应的定制模块的例子。

1> 不传参数的     #!/usr/bin/python     import datetime     import json     date = str(datetime.datetime.now())     print json.dumps({         "time" : date     })

2>传递的参数

#!/usr/bin/python # import some python modules that we'll use.  These are all # available in Python's core import datetime import sys import json import os import shlex # read the argument string from the arguments file args_file = sys.argv[1] args_data = file(args_file).read() # for this module, we're going to do key=value style arguments # this is up to each module to decide what it wants, but all # core modules besides 'command' and 'shell' take key=value # so this is highly recommended arguments = shlex.split(args_data) for arg in arguments:     # ignore any arguments without an equals in it     if "=" in arg:         (key, value) = arg.split("=")         # if setting the time, the key 'time'         # will contain the value we want to set the time to         if key == "time":             # now we'll affect the change.  Many modules             # will strive to be 'idempotent', meaning they             # will only make changes when the desired state             # expressed to the module does not match             # the current state.  Look at 'service'             # or 'yum' in the main git tree for an example             # of how that might look.             rc = os.system("date -s \"%s\"" % value)             # always handle all possible errors             #             # when returning a failure, include 'failed'             # in the return data, and explain the failure             # in 'msg'.  Both of these conventions are             # required however additional keys and values             # can be added.             if rc != 0:                 print json.dumps({                     "failed" : True,                     "msg"    : "failed setting the time"                 })                 sys.exit(1)             # when things do not fail, we do not             # have any restrictions on what kinds of             # data are returned, but it's always a             # good idea to include whether or not             # a change was made, as that will allow             # notifiers to be used in playbooks.             date = str(datetime.datetime.now())             print json.dumps({                 "time" : date,                 "changed" : True             })             sys.exit(0) # if no parameters are sent, the module may or # may not error out, this one will just # return the time date = str(datetime.datetime.now()) print json.dumps({     "time" : date })


不管有没有参数,如何在模块写好之后测试自己写的模块是否正确?

Ansible的文档给出了一种检测模块的方法:


测试模块

ansible的源代码检查中有一个有用的测试脚本


# 下载测试自定义模块的脚本 1. 克隆ansible源码到本地 # git clone git://github.com/ansible/ansible.git --recursive 2. source脚本中设定的环境变量到当前会话 # source ansible/hacking/env-setup 3. 赋予脚本执行权限 # chmod +x ansible/hacking/test-module 由于第一步在克隆的时候 *** 作就失败了 索性直接将源码全部clone到本地  *** 作如下 # git clone https://github.com/ansible/ansible.git


3.测试模块

1>没有参数传递的用户定义的模块执行模式

例如,如果脚本名为timetest.py,执行命令如下

#ansible/hacking/test-module-m./timetest.py

* including generated source, if any, saving to: /root/.ansible_module_generated * this may offset any line numbers in tracebacks/debuggers! *********************************** RAW OUTPUT {"time": "2016-04-03 02:09:41.516592"} *********************************** PARSED OUTPUT {     "time": "2016-04-03 02:09:41.516592" }

2>具有参数传递执行模式的用户定义模块

例如,如果您的脚本名称为timetest.py,传递的参数为time="March1422:10",则执行命令如下

#ansible/hacking/test-module-m./timetest.py-a"time=\"3月14日12:23\""


带参数的此位置的执行失败报告如下

[root@ManagerAnsible sourceCode_tmp]# ansible/hacking/test-module -m ../modules/timetest_params.py -a "time=\"March 14 12:23\"" * including generated source, if any, saving to: /root/.ansible_module_generated * this may offset any line numbers in tracebacks/debuggers! *********************************** RAW OUTPUT Mon Mar 14 12:23:00 UTC 2016 {"changed": true, "time": "2016-03-14 12:23:00.000262"} *********************************** INVALID OUTPUT FORMAT Mon Mar 14 12:23:00 UTC 2016 {"changed": true, "time": "2016-03-14 12:23:00.000262"} Traceback (most recent call last):   File "ansible/hacking/test-module", line 167, in runtest     results = json.loads(out)   File "/usr/local/python27/lib/python2.7/json/__init__.py", line 339, in loads     return _default_decoder.decode(s)   File "/usr/local/python27/lib/python2.7/json/decoder.py", line 364, in decode     obj, end = self.raw_decode(s, idx=_w(s, 0).end())   File "/usr/local/python27/lib/python2.7/json/decoder.py", line 382, in raw_decode     raise ValueError("No JSON object could be decoded") ValueError: No JSON object could be decoded


从上面的错误可以追溯到json.loads对象中167行ansible/hacking/test-module脚本失败。

    try:         print("***********************************")         print("RAW OUTPUT")         print(out)         print(err)         results = json.loads(out)    # 第167行     except:         print("***********************************")         print("INVALID OUTPUT FORMAT")         print(out)         traceback.print_exc()         sys.exit(1)     print("***********************************")     print("PARSED OUTPUT")     print(jsonify(results,format=True))

至于为什么会出现这个问题,文章后面会有解决方法。......



首先看timetest.py文件(有几行注释比较多)

这篇课文的前两行我不太明白

args_file=sys.argv[1]

args_data=file(args_file)。阅读()

# 接受一个参数 args_file = sys.argv[1] # 打开这个参数 file <<>> open args_data = file(args_file).read()  //开始纳闷了开始纳闷了开始纳闷了

然后跟踪这个文件ansible/hacking/test-module。

有兴趣在test-module中加入中文评论的朋友可以参考文末已经上传的附件。


解决了两个问题:

问题1:

安全/黑客/测试模块

有以下功能

Parse#接受命令行参数

Write_argsfile#将命令行传递的参数写入指定的文件。

Boilerplate_module#写入。/timetest.py文件添加到命令行上默认指定的模块文件中。

Runtest#执行foot并打开参数文件。

总结

Boilerplate_module这个函数:将用户定义的模块写入文件~/。ansible_module_generated。

Write_argsfile此函数:将用户传递的参数写入文件~/。ansible_test_module_arguments。

运行这个函数:执行脚本和传递的参数~/。ansible_module_generated~/。ansible_测试_模块_参数


问题2:

修改文档中的timetest.py代码。

修改前 rc = os.system("date -s \"%s\"" % value) 修改后 import commands rc, output = commands.getstatusoutput('date -s \"%s\"' % value)

其实有两件事让我想到了这里的原因:

1.原因:

首先,看一下timetest.py代码的摘录。

rc = os.system("date -s \"%s\"" % value) if rc != 0:

rc得到的是os.system的命令执行结果还是os.system的返回值?

我想你能理解第二行的if语句。


原因二:

ansible/hacking/测试模块文件

def runtest( modfile, argspath):     """Test run a module, piping it's output for reporting."""     os.system("chmod +x %s" % modfile)     invoke = "%s" % (modfile)     if argspath is not None:         invoke = "%s %s" % (modfile, argspath)     cmd = subprocess.Popen(invoke, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)     (out, err) = cmd.communicate()     try:         print("***********************************")         print("RAW OUTPUT")         print(out)         print(err)         results = json.loads(out)     except:         print("***********************************")         print("INVALID OUTPUT FORMAT")         print(out)         traceback.print_exc()         sys.exit(1)     print("***********************************")     print("PARSED OUTPUT")     print(jsonify(results,format=True))

这个函数的正确返回结果必须是json格式,timetest.py文件有两个打印;第一次打印是os.system的执行结果;第二个是printjson.dumps的结果,显然这是两行打印不可能是json。

那我举个例子来说明。

# 对timetest.py简写成如下格式 import os, datetime, json os.system('date -s %s' % 3) date = str(datetime.datetime.now()) print json.dumps({                 "time" : date,                 "changed" : True             })              # 那么test-module中的out就相当于上面执行结果的相加 "Mon Mar 14 03:00:00 UTC 2016" + "{"changed": true, "time": "2016-03-14 03:00:00.013835"}" 以上这种格式你是无法进行json.loads成json对象的 所以也就是报错的原因.


文章的最后是如何使用用户自定义模块。第一部分介绍如何测试模块,下一部分是如何正确使用自定义模块。

(1)通过ansible-help|grepmodule

  -m MODULE_NAME, --module-name=MODULE_NAME                         module name to execute (default=command)   -M MODULE_PATH, --module-path=MODULE_PATH                         specify path(s) to module library (default=None)

用-M指定自定义模块的路径.


(2)由ANSIBLE_LIBRARY变量指定。


<<好在我的Google里很多文章都没有用前两种方式解决。如果有朋友有解决的版本,请告诉我>:>


③我用了最后一个笨办法:

当前python版本为源码安装方式 2.7版本 python的安装路径为/usr/local/python27 python模块包路径为/usr/local/python27/lib/python2.7/site-packages/ansible/modules 其中有core(核心包)和extras(扩展包)两个目录 那么自定义模块 应该属于扩展包吧 于是做如下 *** 作 # cd /usr/local/python27/lib/python2.7/site-packages/ansible/modules/extras # mkdir zhengys # cp ~/demo/ansible/modules/* ./ 也就是把自定义的模块都放置与extras/zhengys目录下 就可以使用了


下载地址:http://pan.baidu.com/s/1kVQwgej


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/778767.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-03
下一篇 2022-05-03

发表评论

登录后才能评论

评论列表(0条)

保存