模塊是一個獨立的, 可以復用的腳本, 它可以被anisible API, Ansible 或者ansible-playbook使用. 在模塊退出之前, 它通過輸出一個json字符串到標准輸出從而反饋信息給ansible. 你可以用任何一種語言去寫一個模塊. 寫好的模塊可以放在ANSIBLE_LIBRARY或者--module-path目錄下. 通常情況下playbook的目錄下的library目錄也可以做為模塊的默認目錄.
1. 模塊的基本開發模式
一個簡單的模塊, 之所以用這個作為例子, 是因為你可以用任何語言去開發自己的模塊, 我們需要了解模塊最基本的開發模式
#!/usr/bin/python import datetime import json date = str(datetime.datetime.now()) print json.dumps({ "time" : date })
模塊測試
git clone git://github.com/ansible/ansible.git --recursive source ansible/hacking/env-setup ansible/hacking/test-module -m ./timetest.py
模塊參數
ansible會自動的把參數保存到一個參數文件中, 所以我們必須讀取並分析這個文件. 這個參數文件只是一個字符串, 所以任何形式的參數都是合法的.
#!/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() 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 key == "time": rc = os.system("date -s \"%s\"" % value) if rc != 0: print json.dumps({ "failed" : True, "msg" : "failed setting the time" }) sys.exit(1) date = str(datetime.datetime.now()) print json.dumps({ "time" : date, "changed" : True }) sys.exit(0) date = str(datetime.datetime.now()) print json.dumps({ "time" : date }) 測試模塊
ansible/hacking/test-module -m ./timetest.py -a "time=\"March 14 12:23\""
二進制模塊
二進制模塊的支持會在ansible2.2中加入, 當ansible發現是二進制模塊是, 它會提供一個json文件argv[1]來保存參數.
提供facts的模塊
setup模塊可以提供很多系統相關的變量, 然而用戶不修改系統模塊也可以添加自定義變量, 只需要在模塊的返回值中加入ansible_facts這個鍵值. 例如:
{ "changed" : True, "rc" : 5, "ansible_facts" : { "leptons" : 5000, "colors" : { "red" : "FF0000", "white" : "FFFFFF" } } }
開發一個site_facts的模塊並且在所有的playbook之前調用是一個較好的習慣,
2. 通用的模塊樣板
如果你使用python來開發自定義模塊, ansible提供了很多強大的快捷方式. 模塊仍然保存在一個文件當中, 但是我們不需要再去處理參數文件. 最好的學習方法是去學習ansible的核心模塊.
from ansible.module_utils.basic import AnsibleModule if __name__ == '__main__': main()
Note: 對於ansible2.1來說, 上面的導入已經不能工作, 必須使用from ansible.module_utils.basic import *
def main(): module = AnsibleModule( argument_spec = dict( state = dict(default='present', choices=['present', 'absent']), name = dict(required=True), enabled = dict(required=True, type='bool'), something = dict(aliases=['whatever']) ) )
AnsibleModule 提供和很多通用的函數來處理返回值, 分析參數並允許你檢查輸入
成功返回
module.exit_json(changed=True, something_else=12345)
失敗退出
module.fail_json(msg="Something fatal happened")
還有很多其他的基礎功能, 課參看lib/ansible/module_utils/basic.py
check模式
模塊支持check模式. 如果用戶在check模式下運行ansible, 模塊會去嘗試預判change是否發生. 如果想定義一個check模塊, 用戶必須在初始化模塊的時候設置supports_check_mode=True
module = AnsibleModule( argument_spec = dict(...), supports_check_mode=True ) if module.check_mode: # Check if any changes would be made but don't actually make those changes module.exit_json(changed=check_if_system_state_would_be_changed())
作為模塊的開發者, 你有責任去保證在check模式下沒有系統狀態被改變?
Remember that, as module developer, you are responsible for ensuring that no system state is altered when the user enables check mode.
如果你的模塊不支持check模式, 而用戶卻在check模式下運行ansible, 你的模塊會被自動跳過
在模塊中永遠不要使用"print "some status message"". 因為在ansible中輸出被假定為一個可用的json.
Modules must not output anything on standard error, because the system will merge standard out with standard error and prevent the JSON from parsing. Capturing standard error and returning it as a variable in the JSON on standard out is fine, and is, in fact, how the command module is implemented.
ANSIBLE_KEEP_REMOTE_FILES 這個參數會保留在遠程服務器上執行的python腳本. 可以用來debug.