參考官網:http://www.ansible.com.cn/docs/developing_modules.html#tutorial
閱讀 ansible 附帶的模組(上面連結)是學習如何編寫模組的好方法。但是請記住,ansible 原始碼樹中的某些模組是內在的,因此請檢視service或yum,不要太靠近async_wrapper 之類的東西,否則您會變成石頭。沒有人直接執行 async_wrapper。
好的,讓我們開始舉例。我們將使用 Python。首先,將其儲存為名為timetest.py的檔案:
#!/usr/bin/python import datetime import json date = str(datetime.datetime.now()) print(json.dumps({ "time" : date }))
自定義模組
建立模組目錄
[root@mcw1 ~]$ mkdir /usr/share/my_modules #這個目錄並不存在,ansible配置中存在這個註釋掉的路徑
編寫模組返回內容
[root@mcw1 ~]$ vim uptime
#!/usr/bin/python import json import os up = os.popen('uptime').read() dic = {"result":up} print json.dumps(dic)
執行結果:
啟動模組目錄
[root@mcw1 ~]$ grep library /etc/ansible/ansible.cfg #將配置中的這行內容註釋,取消掉,不需要重啟任何服務
library = /usr/share/my_modules/
測試模組使用情況
這裡顯示它使用的直譯器路徑了,這個直譯器是python2的直譯器,如果我寫的是python3的指令碼,並且不支援python2執行,我可能需要修改ansible預設使用的python直譯器。有點問題,我指令碼里寫的是python2的直譯器,我寫成python3應該就是python3了吧
按照上面想法試了下,果然是的,我另一個主機是沒有安裝python3的,所以報錯了。使用python3,貌似不會顯示python的路徑,跟之前python2有點區別
編寫指令碼:
程式如下:
[root@mcw1 ~]$ cat /usr/share/my_modules/mem #!/usr/bin/python3 import subprocess,json cmd="free -m |awk 'NR==2{print $2}'" p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) cmdres, err = p.communicate() mcw=str(cmdres).lstrip("b'").rstrip("\\n'") print(mcw) dic = { "result":{ "mem_total": mcw } , "err": str(err) } print(json.dumps(dic)) #print(dic)
上面程式中,python2和python3去掉\n換行符存在區別。python2:rstrip("\n"),python3:rstrip("\\n")
無論是否dumps,列印結果都是一行。當將字典dumps後,結果好看很多
當不使用dumps時,都是報錯,但是有標準輸出的還是會一行列印出來
當我程式裡將字典換成一行時,ansible輸出內容還是有層次的顯示出來。並且它把我們輸出的字典所有鍵值對,相當於批量追加進ansible自己的輸出字典中。同時它還會有自己的相關鍵值對,
總結:我們可以寫python(shell應該也可以)指令碼,將需要的資訊構建字典,列印出來。然後將指令碼放到自定義模組目錄下,無需新增執行許可權,就可以使用ansible呼叫自定義模組,將輸出結果顯示在ansible的列印結果字典中
思考:上面總結列印的結果我怎麼用?python中如何使用這個結果,ansible劇本中是否能使用這個模組,如何使用,這麼用到它的列印結果?
使用shell存在的問題
使用shell的方法還存在問題,有時間再看有辦法解決這個問題
set_fact模組作用
設定變數,其它地方使用變數
- hosts: testB remote_user: root tasks: - set_fact: testvar: "testtest" - debug: msg: "{{testvar}}"
設定變數,其它地方使用變數
我們通過set_fact模組定義了一個名為testvar的變數,變數值為testtest,然後使用debug模組輸出了這個變數:
設定變數接收其它變數的值,變數之間值的傳遞
如下:
- hosts: localhost remote_user: root vars: testvar1: test1_string tasks: - shell: "echo test2_string" register: shellreturn - set_fact: testsf1: "{{testvar1}}" testsf2: "{{shellreturn.stdout}}" - debug: msg: "{{testsf1}} {{testsf2}}" #var: shellreturn
在劇本中定義變數testvar1,在劇本中可以引用這個變數。執行shell命令,將命令返回值註冊為一個變數。set_fact模組設定兩個變數,變數1讓它等於前面設定的變數testvar1,變數2給它賦值shell命令的返回結果變數的標準輸出。後面對這兩個變數列印檢視
劇本中想要檢視資訊,需要使用debug 模組(debug msg 列印)
set_fact:可以自定義變數,可以進行變數值的傳遞。可以用這個模組重新定義一個變數去接收其它變數的值,包括接收其它註冊的變數值
上例中,我們先定義了一個變數testvar1,又使用register將shell模組的返回值註冊到了變數shellreturn中,
之後,使用set_fact模組將testvar1變數的值賦予了變數testsf1,將shellreturn變數中的stdout資訊賦值給了testsf2變數,(可以將註釋去掉檢視變數shellreturn的值)
最後,使用debug模組輸出了testsf1與testsf2的值:
vars關鍵字變數,set_fact設定變數和註冊變數。vars的只在當前play生效,另外兩個可以跨play
如上述示例所示,set_fact模組可以讓我們在tasks中建立變數,也可以將一個變數的值賦值給另一個變數。
其實,通過set_fact模組建立的變數還有一個特殊性,通過set_fact建立的變數就像主機上的facts資訊一樣,可以在之後的play中被引用。
預設情況下,每個play執行之前都會執行一個名為”[Gathering Facts]”的預設任務,這個任務會收集對應主機的相關資訊,我們可以稱這些資訊為facts資訊,我們已經總結過怎樣通過變數引用這些facts資訊,此處不再贅述,而通過set_fact模組建立的變數可以在之後play中被引用,就好像主機的facts資訊可以在play中引用一樣,這樣說可能還是不是特別容易理解,不如來看一個小例子,如下
- hosts: localhost remote_user: root vars: testvar1: tv1 tasks: - set_fact: testvar2: tv2 - debug: msg: "{{testvar1}} ----- {{testvar2}}" - hosts: localhost remote_user: root tasks: - name: other play get testvar2 debug: msg: "{{testvar2}}" - name: other play get testvar1 debug: msg: "{{testvar1}}"
變數1是vars關鍵字設定變數,在當前play生效,不能跨越play使用變數,但是變數2卻可以跨越play使用變數,變數2是set_facts模組設定變數
可以發現,這兩個變數在第一個play中都可以正常的輸出。但是在第二個play中,testvar2可以被正常輸出了,testvar1卻不能被正常輸出,會出現未定義testvar1的錯誤,因為在第一個play中針對testB主機進行操作時,testvar1是通過vars關鍵字建立的,而testvar2是通過set_fact建立的,所以testvar2就好像testB的facts資訊一樣,可以在第二個play中引用到,而建立testvar1變數的方式則不能達到這種效果,雖然testvar2就像facts資訊一樣能被之後的play引用,但是在facts資訊中並不能找到testvar2,只是”效果上”與facts資訊相同罷了。
通過註冊變數實現跨play呼叫變數
- hosts: localhost remote_user: root vars: testvar3: tv3 tasks: - shell: "echo tv4" register: testvar4 - debug: msg: "{{testvar3}} -- {{testvar4.stdout}}" - hosts: localhost remote_user: root tasks: - name: other play get testvar4 debug: msg: "{{testvar4.stdout}}" - name: other play get testvar3 debug: msg: "{{testvar3}}"
3是vars定義變數,4是註冊變數,4是可以跨play的,3卻不行 。是需要4還是3看情況
在第二個play中獲取”testvar3″時會報錯,而在第二個play中獲取註冊變數”testvar4″時則正常,但是,註冊變數中的資訊是模組的返回值,這並不是我們自定義的資訊,所以,如果想要在tasks中給變數自定義資訊,並且在之後的play操作同一個主機時能夠使用到之前在tasks中定義的變數時,則可以使用set_facts定義對應的變數。
上述示例中,即使是跨play獲取變數,也都是針對同一臺主機。
自定義過濾外掛
找到過濾外掛所在的目錄,當前沒有任何過濾外掛,新增一個外掛deal_list_num.py
[root@mcw1 ~]$ ls /usr/share/ansible/plugins/filter
deal_list_num.py
外掛的好處在於編寫YML檔案時可以減少我們的工作量,而且結果易於展示,只要學習一些比較重要的比如Filter、Callbacks等即可。
在普通情況下,我們主要是以{{somevars|filter}對somevars使用filter方法過濾,Ansible已經為我們提供了很多的過濾方法,比如找到列表中最大、最小數的max、min,把資料轉換成JSON格式的fromjson等,但這還遠遠不夠,我們還需要自定義一些過濾的方法來滿足一些特殊的需求,比如查詢列表中大於某個常數的所有數字等。以這個例子,展示如何編寫。
首先,到ansible.cfg中去掉#,開啟filter_plugins的存放目錄,filter_plugins=/usr/share/ansible/plugins/filter。
編寫deal_list_num.py檔案,他主要提供過濾列表中的正數、負數和查詢列表大於某一個給定數值這3個方法。/usr/share/ansible/filter/deal_list_num.py。
# !/usr/bin/env python # encoding=utf-8 class FilterModule(object): def filters(self): # 把使用的方法寫在這個return中 filter_map = { 'positive': self.positive, 'negative': self.negative, 'no_less_than': self.no_less_than } return filter_map def positive(self, data): r_data = [] for item in data: if item >= 0: r_data.append(item) return r_data def negative(self, data): r_data = [] for item in data: if item <= 0: r_data.append(item) return r_data def no_less_than(self, data, num): # 第1個變數為傳入的數值,第2個為條件1 r_data = [] for item in data: if item >= num: r_data.append(item) return r_data
[root@mcw1 ~]$ cat deal_list_num.yml - hosts: localhost gather_facts: False tasks: - name: set fact set_fact: num_list: [-1,-2,5,3,1] - name: echo positive shell: echo {{num_list | positive}} register: print_positive - debug: msg="{{print_positive.stdout_lines[0]}}" - name: echo negative shell: echo {{num_list | negative}} register: print_negative - debug: msg="{{print_negative.stdout_lines[0]}}" - name: echo negative shell: echo {{num_list | no_less_than(4)}} register: print_negative - debug: msg="{{print_negative.stdout_lines[0]}}"
第一個是取列表中的正數,第二個是取列表中的負數。第三個是取列表中不小於4的數
變數引用和檢視獲取shell命令結果作為註冊變數,該如何取到命令結果
過濾方法這裡做個修改
總結:
1、過濾外掛定義類,類中定義方法,方法返回內容
2、將過濾外掛放到ansible過濾外掛目錄下
3、劇本中{{變數}}的方式呼叫變數。然後變數後面|加過濾方法。這樣就可以將變數傳遞進外掛對應方法中,除了self之外的第一個位置引數就是這個劇本中的變數。
4、在過濾外掛方法中對這個變數做過濾,然後返回結果(這裡是定義空列表,然後將劇本變數列表遍歷一次,篩選出指定條件的元素追加到新的列表中,方法返回新的列表這樣劇本中就是使用過濾後的資料)
參考地址:
劇本編寫和定義模組: https://blog.csdn.net/weixin_46108954/article/details/104990063
設定和註冊變數:https://blog.csdn.net/weixin_45029822/article/details/105280206
自定義外掛:過濾外掛:https://blog.csdn.net/JackLiu16/article/details/82121044