第八章: 擴展ansible

擴展ansible

ansible採用廚房水槽的方式來實現功能。寫這本書的時候,ansible裏邊大概有300多個模塊可用。此外,還有大量的回調插件、查詢插件、過濾插件、以及動態庫存插件。即便具備這麼多功能,仍是有必要添加新功能的須要。python

本章會探索給ansible添加新功能的方法:web

  • 開發模塊
  • 開發插件
  • 開發動態庫存插件
廚房水槽: Kitchen sink, 來源於everything but the kitchen sink。這是二戰時期的一個俗語。美國空軍戰士常常用它來形容他們在敵佔區上空所遇到的防空炮火,指敵人炮火猛烈(除了洗碗槽外,各式各樣的炮彈齊發)。 如今這個俗語導出使用,能夠指"無所不包,包羅萬象"。

開發模塊

模塊是ansible的馬達。它們只提供一種抽象,可讓劇本簡單明瞭的啓動起來。ansible核心開發團隊維護的ansible核心模塊大概有150多個,涵蓋了雲、命令、數據庫、文件、網絡、包、源控制、系統、工具、web設施等等。另外,還有100多個其餘額外模塊,主要由社區貢獻者維護,它們擴展了這些類別的不少功能。真正神奇就發生在模塊代碼內部,它們接受傳入的參數,而後努力創建預期的結果。docker

ansible中的模塊就是傳輸給遠程主機並執行的那點代碼。它們可使用遠程主機能夠執行的任何語言實現。然而,ansible提供了一些很是有用的python語言模塊的快捷方式。shell

基本模塊結構

一個模塊的存在就是知足一個需求--須要在主機上完成一些工做。模塊,一般但並不老是,指望輸入,並返回一些類型的輸出。模塊同時力圖是冪等的,容許一次又一次的運行模塊,而不產生負面影響。在ansible中,輸入是以命令行參數的形式給到模塊,輸出是以JSON的形式給到標準輸出。輸入通常使用空格分隔的key=value語法提供,它是由模塊將這些結構分解成可用數據的。若是使用Python, 有一些方便的函數來管理這些,若是使用其餘語言,則徹底由模塊代碼來處理輸入。數據庫

輸出是JSON格式的。慣例規定,在成功的場景中,JSON輸出至少要有一個key, changed,這個值是布爾類型,表示模塊執行結果是否致使改變。附加數據也能夠返回,這些能夠定義具體改變了什麼,或者給劇本返回一些重要的信息便於後續使用。json

另外,主機事實能夠在JSON數據中返回,自動基於模塊執行結果建立主機變量。後面咱們會詳細看到更多這方面的內容。網絡

自定義模塊

ansible提供了一種簡單的機制來利用來自ansible外部的自定義模塊。咱們在第一章已經瞭解到,ansible會查找不少位置來查找請求的模塊。一個這樣的路徑,第一個路徑就是頂級劇本所在目錄下面的library/目錄。咱們能夠將咱們的自定義模塊放在這個目錄下面,這樣咱們就能夠在咱們的劇本中使用了。ssh

模塊還能夠嵌入到角色裏邊,爲角色添加一些可能會依賴的功能。這些模塊就只能被包含它們的角色或其餘在包含模塊的角色以後的其餘角色和任務執行。要用角色表達一個模塊,就能夠將模塊放到角色根目錄下面的library子目錄下面。async

簡單模塊

爲了演示python實現模塊的簡單,讓咱們建立一個簡單的模塊。這個模塊的目的就是從遠程克哦被一個源文件爲目標文件,咱們能夠從它構建的簡單任務。要開始咱們的模塊,咱們首先建立模塊文件。爲了方便訪問咱們的新模塊,咱們就在工做目錄下面建立一個library目錄。ide

創建remote_copy.py,其代碼以下:

#!/usr/bin/env python
# coding=utf-8

import shutil
from ansible.module_utils.basic import *

def main():
    module = AnsibleModule(
        argument_spec = dict(
            source = dict(required=True, type="str"),
            dest = dict(required=True, type="str")
        )
    )

    shutil.copy(module.params['source'],
                module.params['dest'])
    module.exit_json(changed=True)

if __name__ == '__main__':
    main()

而後創建一個測試劇本:

---
DOCUMENTATION = '''
---
module: remote_copy
version_added: future
short_description: Copy a file on the remote host
description:
  - The remote_copy module copies a file on the remote host from a given source to a provided destination.
options:
  source:
    description:
      - Path to a file on the source file on the remote host
    required: True
  dest:
    description:
      - Path to the destination on the remote host for the copy
    required: True
author:
  - Jesse Keating
'''

這個字符串的格式徹底是YAML格式的,具備一些包含哈希結構的頂級key, 例如options。

而後咱們可使用ansible-doc來查看模塊的文檔內容:

ansible-doc -M library/ remote_copy | cat -
注意文檔描述必定要用標準的YAML格式,不然查看文檔會報錯的。

提供事實數據

和模塊退出附帶的數據返回相似,模塊還能夠直接建立主機事實,經過返回名字爲ansible_facts的數據。直接從模塊提供事實就消除了使用後續的set_fact任務註冊任務返回值的操做。

facts = {'rc_source': module.params['source'],
                'rc_dest': module.params['dest']}
module.exit_json(changed=True, ansible_facts=facts)

那麼在劇情中咱們就能夠直接在debug中使用事實中的某個數據了。

- name: show a fact
  debug:
    var: rc_dest

而模塊若是不返回facts, 那麼咱們就須要註冊輸出,並使用set_fact來爲咱們建立事實,就像這樣:

- name: do a remote copy
  remote_copy:
    source: /tmp/foo
    dest: /tmp/bar
  register: mycopy

- name: set facts from mycopy
  set_fact:
    rc_dest: "{{ mycopy.dest }}"

檢查模式(check mode)

ansible 1.1以後,支持檢查模式,就是一種僞裝對系統作修改可是實際上並無改變系統的一種操做模式。檢查模式對於測試修改是否真正發生,或者系統狀態自從上次ansible運行是否漂移都很是有用。 檢查模式依賴於模塊是否支持檢查模式,並返回數據就像它實際上已經作了改變同樣。

支持檢查模式

爲了只是模塊支持檢查模式,咱們在建立模塊對象的時候,須要設置一個參數support_check_mode。
注意設置這個參數能夠在定義argument_spec以前,也能夠在它以後。這裏咱們在argument_spec定義以後:

module = AnsibleModule(
  argument_spec = dict(
    source=dict(required=True, type='str'),
    dest=dict(required=True, type='str')
  ),
  supports_check_mode=True
)
處理檢查模式

監測何時檢查模式是活動狀態很是容易。模塊對象就包含一個check_mode屬性,若是檢查模式是活動狀態,這個屬性就是True。咱們的模塊中,咱們但願在執行復制以前先看檢查模式是否激活。咱們能夠簡單的將複製行爲放入一個if語句裏邊,避免檢查模式是活躍的時候去拷貝了。返回能夠發生沒有任何改變:

if not module.check_mode:
  shutil.copy(module.params['source'],
              module.params['dest'])

那麼,如今咱們能夠在運行劇本的時候添加一個-C參數來執行。這個參數讓劇本執行進行檢查模式。 執行完後,看執行的輸出好像建立並複製了文件,可是真實卻不存在這些文件。

開發插件

插件是另一種擴展和修改ansible功能的方式。模塊是做爲任務來執行的,而插件是在其餘不少地方利用的。 插件會分解爲一些類型,具體依賴於它們在它們能插入ansible執行的什麼地方。ansible這些範圍的每一個都帶有一些插件,終端用戶能夠建立在這些特定地方的它們本身的功能擴展。

鏈接類型插件

ansible任什麼時候間對主機創建鏈接來執行任務,是使用了一個鏈接插件。ansible自帶了一些鏈接插件,包括ssh, docker, chroot, local和smart。經過建立鏈接插件,ansible能夠利用附加的鏈接機制來鏈接遠程主機,這對於鏈接一些新類型的系統會很是有用,就像網絡交換器,或者某天能夠鏈接你的冰箱。 建立鏈接插件有點超出本書的範圍;然而,最簡單的起步的方法就是讀現有的鏈接插件的實現。現有插件能夠在runner/connection_plugins/裏邊找到源代碼。

shell插件

和鏈接插件差很少,ansible用shell插件在shell環境執行一些東西。 每一個shell稍微有所不一樣,ansible關心按順序執行命令、重定向輸出、發現錯誤、以及其餘交互。ansible支持幾種shell, 包括sh, csh, fish以及powershell。咱們能夠經過實現一個新的shell插件添加更多shell。

lookup插件

lookup插件是ansible從主機系統如何訪問外部數據源,以及實現語言特性,例如循環構建(with_*)。

vars插件

事實蒐集插件

過濾器插件

回調插件

回調是放在ansible執行裏邊的,能夠插入一些東西來添加功能。有一些預期的回調點能夠註冊來在這些點觸發用戶自定義行爲。下面是一些可能觸發功能的點:
• runner_on_failed
• runner_on_ok
• runner_on_skipped
• runner_on_unreachable • runner_on_no_hosts
• runner_on_async_poll
• runner_on_async_ok
• runner_on_async_failed
• playbook_on_start
• playbook_on_notify
• playbook_on_no_hosts_matched
• playbook_on_no_hosts_remaining • playbook_on_task_start
• playbook_on_vars_prompt
• playbook_on_setup
• playbook_on_import_for_host
• playbook_on_not_import_for_host • playbook_on_play_start
• playbook_on_stats

ansible運行到達這些裝袋的每一個點,任何有代碼的插件均可以在這些點上被執行。這就提供了極大的能力去擴展ansible而無需修改基礎代碼。

回調能夠用不少方式利用:

  • 修改屏幕上的顯示。
  • 更新

行爲插件

分佈插件(distributing plugins)

開發動態庫存插件

列舉主機

列舉主機變量

簡單庫存插件

優化腳本性能

總結

ansible是一個強大的工具,然而,有時候它可能沒有提供某些須要的全部功能。並非每個功能都適合由主項目來支持,也不可能集成自定義的專有數據源。出於這些緣由,ansible裏邊存在能夠擴展功能的設施。因爲共享模塊的基本代碼,建立和使用自定義模塊變得很容易。不少不一樣類型的插件能夠建立並和ansible一塊兒使用,以各類方式影響操做。超出ansible支持的庫存源依然能相對容易和高效的使用。

在全部狀況下,都有一種機制來提供模塊、插件和庫存源,以及依賴於加強功能的劇本和角色,使其無縫分佈。

詞彙

  • everything but the kitchen sink: 無所不包、包羅萬象。

導航

相關文章
相關標籤/搜索