在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í)文件的辦法定页。