Ansible AdHoc & playbook API + 動態生成Inventory +結果關注

爲以後用的方便,記錄一下(主要是怕忘,又得折騰半天)

直接貼代碼,沒太多註釋,看不懂的看下源碼。Pycharm+b

Ansible 2.0 之後的 API 比 2.0 之前要複雜,但使用起來的自由度更好,可根據自己需求修改 Ansible API 的使用方法;功能也更強大。

我主要是使用這個 API 配合 Djcelery 實現監控系統的數據採集功能,好處是不再需要每中服務器再開發一個agent。這樣使用的問題可能主要是程序的負載性能及程序併發性能,我還沒測試。

-- coding:utf8 --

import os
import sys
import logging
logger = logging.getLogger('django')

from collections import namedtuple

from ansible.inventory import Inventory
from ansible.vars import VariableManager
from ansible.parsing.dataloader import DataLoader
from ansible.inventory.group import Group
from ansible.inventory.host import Host
from ansible.playbook.play import Play
from ansible.executor.playbook_executor import PlaybookExecutor
from ansible.executor.task_queue_manager import TaskQueueManager
from ansible.plugins.callback import CallbackBase

OPTIONS = namedtuple('OPTIONS',

['module_path', 'extra_vars', 'forks', 'become', 'become_method', 'become_user',

'become_ask_pass', 'connection', 'timeout', 'poll_interval', 'check', 'diff']

)

options = OPTIONS(module_path=None, extra_vars=None, forks=5, become=None, become_method=None, become_user=None,

become_ask_pass=None, connection='smart', timeout=10, poll_interval=15, check=False, diff=3)

class Options(object):

"""
Initialize options class to replace Ansible OptParser
"""

def __init__(self, module_path=None, extra_vars=None, forks=10, become=None, become_method=None, become_user=None,
             become_ask_pass=None, connection='smart', timeout=2, poll_interval=15, check=False, diff=3,
             listtasks=None, listhosts=None, listtags=None, syntax=None):
    self.module_path = module_path
    self.extra_vars = extra_vars
    self.forks = forks
    self.become = become
    self.become_method = become_method
    self.become_user = become_user
    self.become_ask_pass = become_ask_pass
    self.connection = connection
    self.timeout = timeout
    self.poll_interval = poll_interval
    self.check = check
    self.diff = diff
    self.listhosts = listhosts
    self.listtasks = listtasks
    self.listtags = listtags
    self.syntax = syntax

class ResultsCallback(CallbackBase):

'''
Callback the result of execute AdHoc and playbook
'''

def __init__(self, *args, **kwargs):
    super(ResultsCallback, self).__init__(*args, **kwargs)
    self.host_ok = {}
    self.host_unreachable = {}
    self.host_failed = {}

def v2_runner_on_unreachable(self, result):
    self.host_unreachable[result._host.get_name()] = result

def v2_runner_on_ok(self, result,  *args, **kwargs):
    self.host_ok[result._host.get_name()] = result

def v2_runner_on_failed(self, result,  *args, **kwargs):
    self.host_failed[result._host.get_name()] = result

def v2_runner_on_async_poll(self, result):
    self.host_ok.setdefault('async_poll', result)

def v2_runner_on_async_ok(self, result):
    self.host_ok.setdefault('async_ok', result)

def v2_runner_on_async_failed(self, result):
    self.host_failed.setdefault('async_failed', result)

class DynamicInventory(Inventory):

def __init__(self, resource, loader, variable_manager):

    '''
    @resource:
    { 
        "group1": { 
            "hosts": [{"hostname": "10.0.0.0", "port": "22", "username": "test", "password": "pass"}, ...], 
            "vars": {"var1": value1, "var2": value2, ...} 
        } 
    }
    '''

    self.resource = resource
    self.inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=[])
    self.gen_inventory()

def Dynamic_add_group(self, hosts, groupname, groupvars=None):
    NewGroup = Group(name=groupname)

    # if group variables exists, add them to group
    if groupvars:
        for key, value in groupvars.iteritems():
            NewGroup.set_variable(key, value)

    # add hosts to group
    for host in hosts:
        # set connection variables
        hostname = host.get("hostname")
        hostport = host.get("port")
        username = host.get("username")
        password = host.get("password")
        # ssh_key = host.get("ssh_key")
        GeneralHost = Host(name=hostname, port=hostport)
        GeneralHost.set_variable('ansible_ssh_host', hostname)
        GeneralHost.set_variable('ansible_ssh_port', hostport)
        GeneralHost.set_variable('ansible_ssh_user', username)
        GeneralHost.set_variable('ansible_ssh_pass', password)
        # GeneralHost.set_variable('ansible_ssh_private_key_file', ssh_key)

        # set other variables
        for key, value in host.iteritems():
            if key not in ["hostname", "port", "username", "password"]:
            # if key not in ["hostname", "port"]:
                GeneralHost.set_variable(key, value)
        # add to group
        NewGroup.add_host(GeneralHost)

    return self.inventory.add_group(NewGroup)

def gen_inventory(self):

    """
    Dynamic add host to inventory.
    """

    if isinstance(self.resource, list):
        self.Dynamic_add_group(self.resource, 'default_group')
    elif isinstance(self.resource, dict):
        for groupname, hosts_and_vars in self.resource.iteritems():
            self.Dynamic_add_group(hosts_and_vars.get("hosts"), groupname, hosts_and_vars.get("vars"))

class AnsibleAPI(object):

def __init__(self, resource):

    '''
    @resource type: dict
    { 
        "group1": { 
            "hosts": [{"hostname": "10.0.0.0", "port": "22", "username": "test", "password": "pass"}, ...], 
            "vars": {"var1": value1, "var2": value2, ...} 
        } 
    }
    @resource: list
    { 
        "hosts": [{"hostname": "10.0.0.0", "port": "22", "username": "test", "password": "pass"}
    }
    '''
    self.variable_manager = VariableManager()
    self.loader = DataLoader()
    self.options = Options()
    self.passwords = dict()
    self.results_raw = {'success': {}, 'failed': {}, 'unreachable': {}}
    self.resource = resource
    self.callback = ResultsCallback()
    self.inventory = DynamicInventory(self.resource, self.loader, self.variable_manager).inventory
    self.variable_manager.set_inventory(self.inventory)

    if isinstance(self.resource, list):
        self.host_list = map(str, self.inventory.get_hosts(pattern='default_group'))

    if isinstance(self.resource, dict):
        self.host_list = []
        for groupname in self.resource.keys():
            self.host_list.extend(self.inventory.get_group(groupname).get_hosts())
        self.host_list = map(str, self.host_list)

def PrivateAdHoc(self, module_name, module_args=''):

    """
    run module from andible ad-hoc.
    module_name: ansible module_name
    module_args: ansible module args
    """

    # create play with tasks
    play_source = dict(
            name="Ansible Play",
            hosts=self.host_list,
            gather_facts='no',
            tasks=[dict(action=dict(module=module_name, args=module_args))]
    )
    play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader)

    # Actually 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=self.callback
        )
        result = tqm.run(play)
    finally:
        if tqm is not None:
            tqm.cleanup()

    return result

def PrivatePlaybook(self, playbooks):

    """
    run ansible palybook and get ran result
    """

    try:
        if not os.path.exists(playbooks):
            logger.error('No such file: %s' % playbooks)
            sys.exit()
        self.executor = PlaybookExecutor(playbooks=[playbooks, ],
                                         inventory=self.inventory,
                                         variable_manager=self.variable_manager,
                                         loader=self.loader,
                                         options=self.options,
                                         passwords=self.passwords
                                         )

        print self.inventory.get_group_dict()

        self.executor._tqm._stdout_callback = self.callback
        result = self.executor.run()

    except Exception as e:
        print "Error: %s" % e
    finally:
        return result

def playbook_result(self):

    for host, result_object in self.executor._tqm._stdout_callback.host_ok.iteritems():
        self.results_raw['success'][host] = result_object._result

    for host, result_object in self.executor._tqm._stdout_callback.host_failed.iteritems():
        self.results_raw['failed'][host] = result_object._result

    for host, result_object in self.executor._tqm._stdout_callback.host_unreachable.iteritems():
        self.results_raw['failed'][host] = result_object._result

    return self.results_raw

def AdHoc_result(self):

    for host, result in self.callback.host_ok.items():
        self.results_raw['success'][host] = result._result

    for host, result in self.callback.host_failed.items():
        try:
            self.results_raw['failed'][host] = result._result['stderr']
        except KeyError:
            self.results_raw['failed'][host] = result._result['msg']

    for host, result in self.callback.host_unreachable.items():
        self.results_raw['unreachable'][host] = result._result['msg']

    return self.results_raw

if name == 'main':

print 'complete'
    #### 以下是測試成功示例,主要關注如何傳參
# example = AnsibleAPI([
    # dict(hostname='10.10.181.132', port=20003, username='root', password=123456),
# ])
# example.PrivateAdHoc('service', module_args='name=crond state=reloaded')
# example.PrivateAdHoc('setup')
# print example.AdHoc_result()
# example = AnsibleAPI(dict(memory=dict(hosts=[dict(hostname='10.10.181.132', port=20003, username='root', password=123456)], vars=dict())))
# print example.PrivatePlaybook('/Users/fanolee/PycharmProjects/AutoOPPlatform/monitor/ansible/playbooks/entry_files/memory/memory.yml')
# print example.playboot_result()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章