第一步创建ansible自定义模块路径
1 2 cd /data/db/playbooks/ mkdir -p library
vim ansible.cfg
增加如下内容:
1 2 [defaults] library = ./library
下面我们开始第一个模块开发
创建第一个模块 vim library/info.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 from ansible.module_utils.basic import *module = AnsibleModule( argument_spec = dict (), ) output="hello word!" result = dict (module='myinfo' ,stdout=output,changed=False ,rc=0 ) module.exit_json(**result)
1 2 3 4 5 6 7 8 9 10 ansible -i inventory/devlop linux-node1 -m myinfo linux-node1 | SUCCESS => { "changed" : false, "module" : "myinfo" , "rc" : 0 , "stdout" : "hello word!" , "stdout_lines" : [ "hello word!" ] }
创建一个带参数的脚本 vim library/myinfo_args.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 from ansible.module_utils.basic import *module = AnsibleModule( argument_spec = dict ( msg=dict (required=True ), ), ) msg = module.params['msg' ] result = dict (module='myinfo_args' ,stdout=msg,changed=False ,rc=0 ) module.exit_json(**result)
执行验证
1 2 3 4 5 6 7 8 9 10 ansible -i inventory/devlop linux-node1 -m myinfo_args -a "msg='new word'" linux-node1 | SUCCESS => { "changed" : false, "module" : "myinfo_args" , "rc" : 0 , "stdout" : "new word" , "stdout_lines" : [ "new word" ] }
来个不带参数的的执行
1 2 3 4 5 ansible -i inventory/devlop linux-node1 -m myinfo_args linux-node1 | FAILED! => { "changed" : false, "msg" : "missing required arguments: msg" }
自己实现一个shell模块 vim library/myshell.py
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 from ansible.module_utils.basic import AnsibleModuleimport commandsdef main (): """ run shell """ changed = False module = AnsibleModule( argument_spec = dict ( cmd = dict (type ='str' , required=True ), ), ) cmd = module.params['cmd' ] code,output = commands.getstatusoutput(cmd) if code == 0 : result = dict (stdout=output,changed=changed,rc=0 ) module.exit_json(**result) else : result = dict (msg=output,rc=code) module.fail_json(**result) if __name__ == '__main__' : main()
执行一个正确的命令
1 2 3 4 5 6 7 8 9 ansible -i inventory/devlop linux-node1 -m myshell -a cmd='pwd' linux-node1 | SUCCESS => { "changed" : false, "rc" : 0 , "stdout" : "/home/niu" , "stdout_lines" : [ "/home/niu" ] }
1 2 3 4 5 6 ansible -i inventory/devlop linux-node1 -m myshell -a cmd='pws' linux-node1 | FAILED! => { "changed" : false, "msg" : "sh: pws: command not found" , "rc" : 32512 }
如果不定义: result = dict(msg=output,rc=code)
ansible 会有一个默认的返回,输出类似下面的情况。
1 2 3 4 5 6 7 8 ansible -i inventory/devlop linux-node1 -m myshell -a cmd='pws' linux-node1 | FAILED! => { "changed" : false, "module_stderr" : "Shared connection to linux-node1 closed.\r\n" , "module_stdout" : "\r\nTraceback (most recent call last):\r\n File \"/home/niu/.ansible/tmp/ansible-tmp-1578648957.53-161256530271090/AnsiballZ_myshell.py\", line 113, in <module>\r\n _ansiballz_main()\r\n File \"/home/niu/.ansible/tmp/ansible-tmp-1578648957.53-161256530271090/AnsiballZ_myshell.py\", line 105, in _ansiballz_main\r\n invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\r\n File \"/home/niu/.ansible/tmp/ansible-tmp-1578648957.53-161256530271090/AnsiballZ_myshell.py\", line 48, in invoke_module\r\n imp.load_module('__main__', mod, module, MOD_DESC)\r\n File \"/tmp/ansible_myshell_payload_XylgIF/__main__.py\", line 40, in <module>\r\n File \"/tmp/ansible_myshell_payload_XylgIF/__main__.py\", line 33, in main\r\nUnboundLocalError: local variable 'result' referenced before assignment\r\n" , "msg" : "MODULE FAILURE\nSee stdout/stderr for the exact error" , "rc" : 1 }
参数解释 argument_spec 支持的参数
例子:
1 2 3 4 5 6 7 module = AnsibleModule( argument_spec = dict { name = dict (type ='str' , required=True ), cwd = dict (type ='str' , required=False ), shell = dict (type ='bool' , default=True ), } )
官方的ping模块分析 模块路径:https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/system/ping.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 from ansible.module_utils.basic import AnsibleModuledef main (): module = AnsibleModule( argument_spec=dict ( data=dict (type ='str' , default='pong' ), ), supports_check_mode=True ) if module.params['data' ] == 'crash' : raise Exception("boom" ) result = dict ( ping=module.params['data' ], ) module.exit_json(**result) if __name__ == '__main__' : main()
1 2 3 4 5 6 7 8 9 10 11 12 ansible -i inventory/devlop linux-node1 -m ping linux-node1 | SUCCESS => { "changed" : false, "ping" : "pong" } ansible -i inventory/devlop linux-node1 -m ping -a "data=abcd" linux-node1 | SUCCESS => { "changed" : false, "ping" : "abcd" }
ansible模块中的输出定制 changed: 平时我们使用别人的模块,会发现changed字段,有的时候是true,有的时候是false,其实changed并不代表什么,ansible里面一致认为的是对系统进行了更改的changed为true,未更改的为false,其实只是一个记录的值而已,要改变chnged的值,返回的字典里面只要changed=Fasle就好了result = dict(changed=False,stdout=ouput)
。
ansible模块中的退出状态处理
正常退出:module.exit_jons
错误退出:module.fail_json
错误退出比较不一样的是,你要传递的参数是msg
: result = dict(msg=output,rc=code)
报错汇总 1 ERROR! this task 'myinfo_args' has extra params, which is only allowed in the following modules: shell, win_shell, include_vars, add_host, raw, include_role, meta, set_fact, include, import_tasks, script, import_role, include_tasks, group_by, command, win_command
命令执行错了 ansible -i inventory/devlop linux-node1 -m myinfo_args -a 'new word'
正确的命令:ansible -i inventory/devlop linux-node1 -m myinfo_args -a "msg='new word'"
参考文档 Ansible模块开发-自定义模块