Ansible 2.0+版本api使用方法

Posted python运维技术

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ansible 2.0+版本api使用方法相关的知识,希望对你有一定的参考价值。

Ansible这个工具在现在运维中用的越来越多,它可以方便的批量执行命令,上传文件,配置playbook初始化一些新机器非常快速方便,当然除了我们命令行使用外,我们还可以通过ansible提供的api接口编写一些自动化脚本工作,用过ansible 的api的小伙伴可能知道在2.0版本之前,调用ansible的api是一件非常简单容易的事,几行代码就可以搞定,而且还非常直观,但到了2.0版本后会发现调用没那么容易了,如果没有python基础,是没法玩了,有基础的也会感觉很麻烦,因为在2.0版本一些数据处理是要自己来写的,不像2.0版本之前,基本都是ansible给实现了,不过别急,今天我们就把跟2.0版本的api调用逐一看一遍,先来一个简单的调用:


#!/usr/bin/env python


import os

import sys

from collections import namedtuple


from ansible.parsing.dataloader import DataLoader

from ansible.vars import VariableManager

from ansible.inventory import Inventory

from ansible.executor.playbook_executor import PlaybookExecutor


variable_manager = VariableManager()

loader = DataLoader()


inventory = Inventory(loader=loader, variable_manager=variable_manager,  host_list='/etc/ansible/hosts')

playbook_path = '/tmp/onedir/main.yml'


if not os.path.exists(playbook_path):

    print '[INFO] The playbook does not exist'

    sys.exit()


Options = namedtuple('Options', ['listtags', 'listtasks', 'listhosts', 'syntax', 'connection','module_path', 'forks', 'remote_user', 'p

rivate_key_file', 'ssh_common_args', 'ssh_extra_args', 'sftp_extra_args', 'scp_extra_args', 'become', 'become_method', 'become_user', '

verbosity', 'check'])


options = Options(listtags=False, listtasks=False, listhosts=False, syntax=False, connection='ssh', module_path=None, forks=100, remote

_user='slotlocker', private_key_file=None, ssh_common_args=None, ssh_extra_args=None, sftp_extra_args=None, scp_extra_args=None, become

=True, become_method=None, become_user='root', verbosity=None, check=False)


variable_manager.extra_vars = {'hosts': 'port'} 


passwords = {}


pbex = PlaybookExecutor(playbooks=[playbook_path], inventory=inventory, variable_manager=variable_manager, loader=loader, options=optio

ns, passwords=passwords)


results = pbex.run()

这是最简单的方法,也没定义自己回调函数,就是让大家看看调用api的时候都需要哪些初始化参数,它运行的结果跟用ansible-playbook 命令执行的结果显示是一样的。

当然这种方式我们用的时候还不太方便,我们有时候期望运行完的结果返回的是json格式数据,方便我们做进一步处理,我们来看下一个实现了自己回调函数的例子,例子参考了网络上的一个例子,自己做了微调,不过大部分例子实现方式都差不多,都时候自己定义回调类,自己然后定义一个任务类,然后开始执行,我们先看第一个回调类,回调类继承CallbackBase父类,如下:


import os

import json

from collections import namedtuple

from ansible.inventory import Inventory

from ansible.vars import VariableManager

from ansible.parsing.dataloader import DataLoader

from ansible.executor.playbook_executor import PlaybookExecutor

from ansible.plugins.callback import CallbackBase

from ansible.errors import AnsibleParserError


class mycallback(CallbackBase):

    def __init__(self,*args):

        super(mycallback,self).__init__(display=None)

        self.status_ok=json.dumps({})

        self.status_fail=json.dumps({})

        self.status_unreachable=json.dumps({})

        self.status_playbook=''

        self.status_no_hosts=False

        self.host_ok = {}

        self.host_failed={}

        self.host_unreachable={}

    def v2_runner_on_ok(self,result):

        host=result._host.get_name()

        self.runner_on_ok(host, result._result)

        self.host_ok[host] = result

    def v2_runner_on_failed(self, result, ignore_errors=False):

        host = result._host.get_name()

        self.runner_on_failed(host, result._result, ignore_errors)

        self.host_failed[host] = result

    def v2_runner_on_unreachable(self, result):

        host = result._host.get_name()

        self.runner_on_unreachable(host, result._result)

        self.host_unreachable[host] = result

    def v2_playbook_on_no_hosts_matched(self):

        self.playbook_on_no_hosts_matched()

        self.status_no_hosts=True

    def v2_playbook_on_play_start(self, play):

        self.playbook_on_play_start(play.name)

        self.playbook_path=play.name


任务类:


class my_ansible_play():

    def __init__(self, playbook, extra_vars={}, 

                        host_list='/etc/ansible/hosts', 

                        connection='ssh',

                        become=False,

                        become_user=None,

                        module_path=None,

                        fork=50,

                        passwords={},

                        check=False):

        self.playbook_path=playbook

        self.passwords=passwords

        self.extra_vars=extra_vars

        Options = namedtuple('Options',

                   ['listtags', 'listtasks', 'listhosts', 'syntax', 'connection','module_path',

                   'forks', 'private_key_file', 'ssh_common_args', 'ssh_extra_args', 'sftp_extra_args',

                      'scp_extra_args', 'become', 'become_method', 'become_user', 'verbosity', 'check'])

        self.options = Options(listtags=False, listtasks=False, 

                              listhosts=False, syntax=False, 

                              connection=connection, module_path=module_path, 

                              forks=fork, private_key_file=None, 

                              ssh_common_args=None, ssh_extra_args=None, 

                              sftp_extra_args=None, scp_extra_args=None, 

                              become=become, become_method=None, 

                              become_user=become_user, 

                              verbosity=None, check=check)

        if ansible_cfg != None:

            os.environ["ANSIBLE_CONFIG"] = ansible_cfg

        self.variable_manager=VariableManager()

        self.loader=DataLoader()

        self.inventory=Inventory(loader=self.loader,variable_manager=self.variable_manager,host_list=host_list)

    def run(self):

        complex_msg={}

        if not os.path.exists(self.playbook_path):

            code=1000

            results={'playbook':self.playbook_path,'msg':self.playbook_path+' playbook is not exist','flag':False}

        pbex= PlaybookExecutor(playbooks=[self.playbook_path],

                       inventory=self.inventory,

                       variable_manager=self.variable_manager,

                       loader=self.loader,

                       options=self.options,

                       passwords=self.passwords)

        self.results_callback=mycallback()

        print dir(pbex._tqm)

        pbex._tqm._stdout_callback=self.results_callback

        try:

            code=pbex.run()

        except AnsibleParserError:

            code=1001

            results={'playbook':self.playbook_path,'msg':self.playbook_path+' playbook have syntax error','flag':False}

            return code,results

        if self.results_callback.status_no_hosts:

            code=1002

            results={'playbook':self.playbook_path,'msg':self.results_callback.status_no_hosts,'flag':False,'executed':False}

            return code,results

    def get_result(self):

        self.result_all={'success':{},'fail':{},'unreachable':{}}

        for host, result in self.results_callback.host_ok.items():

            self.result_all['success'][host] = result._result


        for host, result in self.results_callback.host_failed.items():

            self.result_all['failed'][host] = result._result['msg']


        for host, result in self.results_callback.host_unreachable.items():

            self.result_all['unreachable'][host]= result._result['msg']

        

        for i in self.result_all['success'].keys():

            return self.result_all


主函数执行:


if __name__ =='__main__':

    play_book=my_ansible_play('/tmp/onedir/main.yml')

    play_book.run()

    data = play_book.get_result()

    print data



这里说一下PlaybookExecutor初始化的几个参数:


  • inventory –> 由ansible.inventory模块创建,用于导入inventory文件

  • variable_manager –> 由ansible.vars模块创建,用于存储各类变量信息

  • loader –> 由ansible.parsing.dataloader模块创建,用于数据解析

  • options –> 存放各类配置信息的数据字典

  • passwords –> 登录密码,可设置加密信息

  • stdout_callback –> 回调函数 


写在最后,因为ansible要求返回的数据是Json格式,所以如果你想自定义一些模块,我建议最好用python去实现比较方便,如果一定要用shell,需要在shell脚本里 加上#WANT_JSON, 然后返回构造的json格式数据,例如:


{


    "changed": true,


    "msg": "OK",   


}


以上是关于Ansible 2.0+版本api使用方法的主要内容,如果未能解决你的问题,请参考以下文章

Ansible API 2.0的测试

Ansible API 2.0解析

ansible-playbook api 2.0

Ansible 2.0发布

Ansible AdHoc & playbook API + 动态生成Inventory +结果关注

python学习之ansible api