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

简介:

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

在ansible文档中有一篇介绍用户自定义模块的文章 链接地址如下Developing Modules,但是在使用测试的时候总是有异常,无法继续进行下面的操作,于是就看了下是如何进行测试模块的.


2. 自定义模块分为两种情况

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

ansible的文档上也给了两个对应的自定义模块的示例

1
2
3
4
5
6
7
8
9
10
1 > 不传参数的
     #!/usr/bin/python
 
     import  datetime
     import  json
 
     date  =  str (datetime.datetime.now())
     print  json.dumps({
         "time"  : date
     })

2> 传递参数的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#!/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的文档上给了一种检测模块的方式:


Testing Modules

There’s a useful test script in the source checkout for ansible


1
2
3
4
5
6
7
8
9
10
11
12
13
# 下载测试自定义模块的脚本
 
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

1
2
3
4
5
6
7
8
9
10
11
12
*  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="March 14 22:10",那么执行命令如下所示

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


带参数的这个地方执行失败 报错如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[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


从上面的报错可以追踪到ansible/hacking/test-module脚本的167行在json.loads对象的时候失败.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
     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).read()

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

于是又对这个文件ansible/hacking/test-module进行追踪

我对test-module添加了中文注释 有兴趣的朋友可以参考下 已经上传文章末尾到附件中.



解决了两个问题:

问题1:

ansible/hacking/test-module

有以下几个函数

parse # 接受命令行参数.

write_argsfile # 将命令行传递的参数写入到指定的文件中.

boilerplate_module # 将./timetest.py文件的内容全部写入到命令行-o默认指定的模块文件

runtest # 执行脚并打开参数本文件

总结下

boilerplate_module这个函数:将用户自定义的模块写入到~/.ansible_module_generated这个文件中

write_argsfile这个函数:将用户传递的参数写入到~/.ansible_test_module_arguments这个文件中

runtest这个函数:执行脚本和传递的参数~/.ansible_module_generated ~/.ansible_test_module_arguments


问题2:

修改文档中timetest.py代码

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

其实有两处才让我想到是这里的原因:

原因1:

首先看timetest.py代码中 摘取一段

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

这个rc到底是获取os.system的命令执行结果还是获取os.system的返回值呢?

想必第二行的if语句你就弄明白.


原因2:

ansible/hacking/test-module文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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的执行结果;第二处便是print json.dumps的结果,显然这是两行打印 无法进行json

那么我就举个列子来说明下吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 对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 |grep module

1
2
3
4
   - 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好多文章也都没有解决,如果哪位朋友有解决的版本 也请告知>>


(3)我使用了最后一种比较笨的方式:

1
2
3
4
5
6
7
8
9
10
当前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





     本文转自zys467754239 51CTO博客,原文链接:http://blog.51cto.com/467754239/1759873,如需转载请自行联系原作者



相关文章
|
3月前
|
数据采集 算法 测试技术
【硬件测试】基于FPGA的1024QAM基带通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍了基于FPGA的1024QAM基带通信系统的硬件测试版本,包含testbench、高斯信道模块和误码率统计模块。系统新增ila在线数据采集和vio在线SNR设置模块,支持不同SNR条件下的性能测试。1024QAM调制将10比特映射到复平面上的1024个星座点之一,实现高效数据传输。硬件测试结果表明,在SNR=32dB和40dB时,系统表现出良好的性能。Verilog核心程序展示了各模块的连接与功能实现。
89 7
|
2月前
|
数据采集 移动开发 算法
【硬件测试】基于FPGA的QPSK调制+软解调系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文基于FPGA实现QPSK调制与软解调系统,包含Testbench、高斯信道、误码率统计模块,并支持不同SNR设置。硬件版本新增ILA在线数据采集和VIO在线SNR设置功能,提供无水印完整代码及测试结果。通过VIO分别设置SNR为6dB和12dB,验证系统性能。配套操作视频便于用户快速上手。 理论部分详细解析QPSK调制原理及其软解调实现过程,涵盖信号采样、相位估计、判决与解调等关键步骤。软解调通过概率估计(如最大似然法)提高抗噪能力,核心公式为*d = d_hat / P(d_hat|r[n])*,需考虑噪声对信号点分布的影响。 附Verilog核心程序代码及注释,助力理解与开发。
89 5
|
3月前
|
数据采集 算法 数据安全/隐私保护
【硬件测试】基于FPGA的MSK调制解调系统系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文基于FPGA实现MSK调制解调系统,采用Verilog开发,包含同步模块、高斯信道模拟、误码率统计等功能。相比仿真版本,新增ILA数据采集与VIO在线SNR设置模块。通过硬件测试验证,展示不同SNR(如10dB和16dB)下的性能表现。研究聚焦软件无线电领域,优化算法复杂度以适应硬件限制,利用MSK恒定包络、相位连续等特性提升频谱效率。核心代码实现信号生成、调制解调、滤波及误码统计,提供完整的硬件设计与分析方案。
134 19
|
3月前
|
数据采集 算法 数据安全/隐私保护
【硬件测试】基于FPGA的4ASK调制解调通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍了基于FPGA的4ASK调制解调系统的硬件测试版本,该系统包括testbench、高斯信道模块和误码率统计模块,并新增了ILA在线数据采集和VIO在线SNR设置功能。通过VIO设置不同SNR(如15dB和25dB),实现了对系统性能的实时监测与调整。4ASK是一种通过改变载波幅度表示数据的数字调制方式,适用于多种通信场景。FPGA平台的高效性和灵活性使其成为构建高性能通信系统的理想选择。
105 17
|
3月前
|
SQL 缓存 PHP
MBTI十六型人格职业性格测试源码完整版
MBTI十六型人格职业性格测试源码完整版
325 11
|
3月前
|
数据采集 算法 数据安全/隐私保护
【硬件测试】基于FPGA的16QAM调制+软解调系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文基于之前开发的16QAM调制与软解调系统,增加了硬件测试功能。该系统包含FPGA实现的16QAM调制、软解调、高斯信道、误码率统计模块,并新增了ILA在线数据采集和VIO在线SNR设置模块。通过硬件测试,验证了不同SNR条件下的系统性能。16QAM软解调通过比较接收信号采样值与16个调制点的距离,选择最近的调制点来恢复原始数据。核心Verilog代码实现了整个系统的功能,包括SNR设置、信号处理及误码率统计。硬件测试结果表明系统在不同SNR下表现良好,详细操作步骤可参考配套视频。
102 13
|
3月前
|
数据采集 算法 数据安全/隐私保护
【硬件测试】基于FPGA的4FSK调制解调通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文基于之前的文章《基于FPGA的4FSK调制解调系统》,增加了ILA在线数据采集模块和VIO在线SNR设置模块,实现了硬件测试版本。通过VIO设置不同SNR(如10dB和20dB),并展示了ILA采集的数据结果。四频移键控(4FSK)是一种数字调制方法,利用四个不同频率传输二进制数据,具有较高的频带利用率和抗干扰性能。输入的二进制数据分为两组,每组两个比特,对应四个频率f1、f2、f3、f4,分别代表二进制组合00、01、10、11。调制过程中选择相应频率输出,并进行幅度调制以增强抗干扰能力。接收端通过带通滤波器提取信号并还原为原始二进制数据。
83 7
|
3月前
|
数据采集 算法 数据处理
【硬件测试】基于FPGA的256QAM基带通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍了基于FPGA的256QAM基带通信系统的硬件测试版本,包含testbench、高斯信道模块和误码率统计模块。系统新增ila在线数据采集和vio在线SNR设置模块,支持不同信噪比(如30dB和40dB)的仿真测试,并提供配套操作视频。256QAM调制方案每个符号携带8比特信息,通过复数值星座图映射实现高效传输。Verilog代码展示了核心模块设计,包括SNR设置、数据处理和ILA测试分析,确保系统在实际硬件环境中的稳定性和性能。
55 2
|
4月前
|
数据采集 算法 数据安全/隐私保护
【硬件测试】基于FPGA的16QAM基带通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍了基于FPGA的16QAM基带通信系统硬件测试版本。该系统在仿真基础上增加了ILA在线数据采集和VIO在线SNR设置模块,支持不同信噪比(如15dB、25dB)的测试。16QAM是一种正交幅度调制方式,通过两路4ASK信号叠加实现,每个符号包含4比特信息。系统采用正交调幅法生成16QAM信号,并通过DAC转换为模拟信号。解调时使用正交相干解调,经低通滤波器恢复电平信号。开发板内完成发射与接收,无需定时同步模块。代码可移植至其他开发板,具体步骤见配套文档。
72 2
|
4月前
|
数据采集 算法 测试技术
【硬件测试】基于FPGA的2ASK调制解调系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍基于FPGA的2ASK调制解调系统,涵盖仿真效果、理论知识、Verilog核心程序及开发板使用说明。系统包含testbench、高斯信道模块和误码率统计模块,支持不同SNR设置。硬件测试版本增加了ILA在线数据采集和VIO在线SNR设置功能。2ASK调制通过改变载波振幅传输二进制信号,FPGA实现包括系统设计、Verilog编码、仿真测试和硬件部署。详细操作步骤见配套视频,代码适用于多种开发板,提供移植方法。
75 1