如何使用Ansible 2的API做python開(kāi)發(fā)

在ansible1.9的時(shí)候,API是一個(gè)非常簡(jiǎn)單的東西府树。官方說(shuō)“it's pretty simple”澜倦,真是又pretty又simple。

import ansible.runner

runner = ansible.runner.Runner(
   module_name='ping',
   module_args='',
   pattern='web*',
   forks=10
)
datastructure = runner.run()

到了ansible2.0以后篡殷,是“a bit more complicated”钝吮,Oh my,簡(jiǎn)直讓人難受贴唇。

簡(jiǎn)潔和靈活是魚(yú)和熊掌搀绣。

ansible2.0 API怎么用?

ansible2.0更貼近于ansible cli的常用命令執(zhí)行方式戳气,不同于上一版本只能發(fā)送單個(gè)命令或playbook链患;而更推薦用戶在調(diào)用ansibleAPI的時(shí)候,將playbook的每個(gè)task拆分出來(lái)瓶您,獲取每個(gè)task的結(jié)果麻捻。能夠跟靈活處理在執(zhí)行批量作業(yè)過(guò)程中的各種反饋。

  • 將執(zhí)行操作的隊(duì)列模型呀袱,包含各類環(huán)境參數(shù)設(shè)置贸毕,歸結(jié)到“ansible.executor.task_queue_manager”類中
  • 將執(zhí)行過(guò)程中的各個(gè)task的設(shè)置,或者說(shuō)playbook中的編排內(nèi)容夜赵,歸結(jié)到“ansible.playbook.play”中

上述兩個(gè)東西明棍,幾乎囊括了可以在執(zhí)行過(guò)程中設(shè)置的所有參數(shù),足夠靈活寇僧,也讓人抓狂摊腋,相當(dāng)于需要自己寫一個(gè)1.9版本中的runner。
他們的確也都是原生類嘁傀,并非專用于外部調(diào)用兴蒸。

ansible.executor.task_queue_manager

這是ansible的一個(gè)內(nèi)部模塊(ansible/executor/task_queue_manager.py)。初始化的源碼如下:

class TaskQueueManager:

    '''
    This class handles the multiprocessing requirements of Ansible by
    creating a pool of worker forks, a result handler fork, and a
    manager object with shared datastructures/queues for coordinating
    work between all processes.

    The queue manager is responsible for loading the play strategy plugin,
    which dispatches the Play's tasks to hosts.
    '''

    def __init__(self, inventory, variable_manager, loader, options, passwords, stdout_callback=None, run_additional_callbacks=True, run_tree=False):

        self._inventory        = inventory
        self._variable_manager = variable_manager
        self._loader           = loader
        self._options          = options
        self._stats            = AggregateStats()
        self.passwords         = passwords
        self._stdout_callback  = stdout_callback
        self._run_additional_callbacks = run_additional_callbacks
        self._run_tree         = run_tree

        self._callbacks_loaded = False
        self._callback_plugins = []
        self._start_at_done    = False
        self._result_prc       = None

        ……

創(chuàng)建時(shí)细办,需要的主要參數(shù)包括:

  • inventory --> 由ansible.inventory模塊創(chuàng)建橙凳,用于導(dǎo)入inventory文件
  • variable_manager --> 由ansible.vars模塊創(chuàng)建,用于存儲(chǔ)各類變量信息
  • loader --> 由ansible.parsing.dataloader模塊創(chuàng)建,用于數(shù)據(jù)解析
  • options --> 存放各類配置信息的數(shù)據(jù)字典
  • passwords --> 登錄密碼岛啸,可設(shè)置加密信息
  • stdout_callback --> 回調(diào)函數(shù)

ansible.playbook.play

ansible.playbook是一個(gè)原生模塊钓觉,既用于CLI也用于API。從源碼可以看出來(lái):

try:
    from __main__ import display
except ImportError:
    from ansible.utils.display import Display
    display = Display()

ansible.playbook.play(ansible/playbook/play.py)值戳。初始化源碼的介紹如下:

__all__ = ['Play']


class Play(Base, Taggable, Become):

    """
    A play is a language feature that represents a list of roles and/or
    task/handler blocks to execute on a given set of hosts.

    Usage:

       Play.load(datastructure) -> Play
       Play.something(...)
    """
  • 最后议谷,用task_queue_manager(play)來(lái)執(zhí)行,老規(guī)矩堕虹,源碼的官方解釋。
def run(self, play):
        '''
        Iterates over the roles/tasks in a play, using the given (or default)
        strategy for queueing tasks. The default is the linear strategy, which
        operates like classic Ansible by keeping all hosts in lock-step with
        a given task (meaning no hosts move on to the next task until all hosts
        are done with the current task).
        '''

一個(gè)完整的例子

# -*- coding:utf-8 -*-
# !/usr/bin/env python
#
# Author: Shawn.T
# Email: shawntai.ds@gmail.com
#
# this is the Interface package of Ansible2 API
#

from collections import namedtuple
from ansible.parsing.dataloader import DataLoader
from ansible.vars import VariableManager
from ansible.inventory import Inventory
from ansible.playbook.play import Play
from ansible.executor.task_queue_manager import TaskQueueManager
from tempfile import NamedTemporaryFile
import os

class AnsibleTask(object):
    def __init__(self, targetHost):
        Options = namedtuple(
                          'Options', [
                              'listtags', 'listtasks', 'listhosts', 'syntax', 'connection','module_path',
                              'forks', 'remote_user', 'private_key_file', 'ssh_common_args', 'ssh_extra_args',
                              'sftp_extra_args', 'scp_extra_args', 'become', 'become_method', 'become_user',
                              'verbosity', 'check'
                          ]
                       )

        # initialize needed objects
        self.variable_manager = VariableManager()

        self.options = Options(
                          listtags=False, listtasks=False, listhosts=False, syntax=False, connection='smart',
                          module_path='/usr/lib/python2.7/site-packages/ansible/modules', forks=100,
                          remote_user='root', private_key_file=None, ssh_common_args=None, ssh_extra_args=None,
                          sftp_extra_args=None, scp_extra_args=None, become=False, become_method=None, become_user='root',
                          verbosity=None, check=False
                      )
        self.passwords = dict(vault_pass='secret')
        self.loader = DataLoader()

        # create inventory and pass to var manager
        self.hostsFile = NamedTemporaryFile(delete=False)
        self.hostsFile.write(targetHost)
        self.hostsFile.close()
        self.inventory = Inventory(loader=self.loader, variable_manager=self.variable_manager, host_list=self.hostsFile.name)
        self.variable_manager.set_inventory(self.inventory)

    def ansiblePlay(self, action):
        # create play with tasks
        args = "ls /"
        play_source =  dict(
                name = "Ansible Play",
                hosts = 'all',
                gather_facts = 'no',
                tasks = [
                    dict(action=dict(module='shell', args=args), register='shell_out'),
                    dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}')))
                ]
            )
        play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader)

        # run it
        tqm = None
        try:
            tqm = TaskQueueManager(
                      inventory=self.inventory,
                      variable_manager=self.variable_manager,
                      loader=self.loader,
                      options=self.options,
                      passwords=self.passwords,
                      stdout_callback='default',
                  )
            result = tqm.run(play)
        finally:
        # print result
            if tqm is not None:
                tqm.cleanup()
                os.remove(self.hostsFile.name)
                self.inventory.clear_pattern_cache()
            return result

寫一個(gè)ansibleTask類芬首,創(chuàng)建了上述的各類必要的配置信息對(duì)象赴捞,最后使用ansibleTask.ansiblePlay()函數(shù)執(zhí)行。

  • inventory文件的動(dòng)態(tài)生成

寫上面的代碼的過(guò)程中郁稍,碰到一個(gè)問(wèn)題:inventory對(duì)象創(chuàng)建時(shí)需要一個(gè)實(shí)體的hosts文件赦政,而文件需要?jiǎng)討B(tài)生成。
生成的方法參考了這篇牛逼閃閃的文章耀怜。使用tempfile.NamedTemporaryFile這個(gè)方法來(lái)創(chuàng)建一個(gè)有名稱的臨時(shí)文件恢着,可以選擇關(guān)閉后刪除或保留。上面的處理辦法是:不刪除财破,在執(zhí)行完畢之后掰派,通過(guò)os.remove(self.hostsFile.name)進(jìn)行刪除。

ps.經(jīng)YiChenWang指出左痢,inventory的創(chuàng)建參數(shù)host_list可以使列表靡羡。使用以下方式創(chuàng)建inventory也是可以的:

self.inventory = Inventory(loader=self.loader, variable_manager=self.variable_manager, host_list=['xx.xx.xx.xx', 'xx.xx.xx.xx'])

不過(guò),源碼中指出俊性,采用list格式參數(shù)是無(wú)法加載inventory data的略步。如果需要加載,還是得使用臨時(shí)文件的辦法定页。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末趟薄,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子典徊,更是在濱河造成了極大的恐慌杭煎,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宫峦,死亡現(xiàn)場(chǎng)離奇詭異岔帽,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)导绷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門犀勒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事贾费∏展海” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵褂萧,是天一觀的道長(zhǎng)押桃。 經(jīng)常有香客問(wèn)我,道長(zhǎng)导犹,這世上最難降的妖魔是什么唱凯? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮谎痢,結(jié)果婚禮上磕昼,老公的妹妹穿的比我還像新娘。我一直安慰自己节猿,他們只是感情好票从,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著滨嘱,像睡著了一般峰鄙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上太雨,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天吟榴,我揣著相機(jī)與錄音,去河邊找鬼躺彬。 笑死煤墙,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的宪拥。 我是一名探鬼主播仿野,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼她君!你這毒婦竟也來(lái)了脚作?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤缔刹,失蹤者是張志新(化名)和其女友劉穎球涛,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體校镐,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡亿扁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鸟廓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片从祝。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡襟己,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出牍陌,到底是詐尸還是另有隱情擎浴,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布毒涧,位于F島的核電站贮预,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏契讲。R本人自食惡果不足惜仿吞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望捡偏。 院中可真熱鬧茫藏,春花似錦、人聲如沸霹琼。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)枣申。三九已至,卻和暖如春看杭,著一層夾襖步出監(jiān)牢的瞬間忠藤,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工楼雹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留模孩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓贮缅,卻偏偏與公主長(zhǎng)得像榨咐,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子谴供,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容