运维工具ansible调用callbacks实现结果nosql回调

前言:

ansible的结果默认是输出到cli终端和日志里面的,用惯了saltsatck的returners数据回调后,也很是喜欢ansible也有,一开始不知道有这个功能,自己也简单实现了这样的功能。

我的实现方式是,在模块里面做一些输出的逻辑。当使用ansible runner api的时候,是在后面runner代码,最后加了一段往redis输出的逻辑。 这里实现数据的输出有些独特,但是只能是在模块和 api方面搞 。 如果是用playbook的话,按照我以前的思路的话,再继续改ansbile的源码。  这两天听沈灿说,ansible有个callback_plugins的功能,可以对于执行的状态做一些判断,比如,执行成功,执行失败,异步执行,异步执行失败,playbook开始,结束等等。

我也不说复杂了,就简单说一个例子,把执行的结果,都推到redis里面,也可以暂存到sqlite数据库里面,只是这段代码我给屏蔽了,有兴趣的朋友再搞搞。对于redis里面的数据可以写一个页面展现下,专门记录错误的问题,成功的就pass掉。

 代码如下 复制代码
#xiaorui.cc
 
import os
import time
import sqlite3
import redis
import json
 
dbname = '/tmp/setup.db'
TIME_FORMAT='%Y-%m-%d %H:%M:%S'
 
try:
    con = sqlite3.connect(dbname)
    cur = con.cursor()
except:
    pass
 
def log(host, data):
 
#    if type(data) == dict:
#        invocation = data.pop('invocation', None)
#        if invocation.get('module_name', None) != 'setup':
#            return
#
#    facts = data.get('ansible_facts', None)
#
#    now = time.strftime(TIME_FORMAT, time.localtime())
#
#    try:
#        # `host` is a unique index
#        cur.execute("REPLACE INTO inventory (now, host, arch, dist, distvers, sys,kernel) VALUES(?,?,?,?,?,?,?);",
#        (
#            now,
#            facts.get('ansible_hostname', None),
#            facts.get('ansible_architecture', None),
#            facts.get('ansible_distribution', None),
#            facts.get('ansible_distribution_version', None),
#            facts.get('ansible_system', None),
#            facts.get('ansible_kernel', None)
#        ))
#        con.commit()
#    except:
#        pass
#
class CallbackModule(object):
    def runner_on_ok(self, host, res):
        r = redis.Redis(host='127.0.0.1', port=6379, db=0)
        r.set(host,str(res))
 
        f = open('/tmp/11','a')
        f.write(str(host))
        f.write(str(res))
        f.close()
        log(host, res)
    def runner_on_failed(self, host, res, ignore_errors=False):
        f = open('/tmp/11','a')
        f.write('nbadn')
        f.close()
        log(host, res)

 

还是可以接收所有的facts数据的。

虽然我上面的例子用了redis,sqlite数据库,其实我个人推荐用mongodb这样的文档数据库的。因为ansible主runner函数,给callbacks传递了一个叫res的变量,他本身就是一个dict对象,如果放到redis的hash,sqlite的各种字段,够你烦的了,如果直接mongo,那就简单了,直接insert ! 欧了

这里在show一个邮件的callbacks代码,场景是,非常消耗时间的任务,当执行完成后,查看结果咋办?  但是你也可以在终端继续看,既然咱们讲了callbacks_plugins,就可以把结果push到你的邮箱里面,当然只给你发错误的,有问题的。 下面的callback代码需要自己替换成自己用的邮箱、密码、smtp服务器。

 代码如下 复制代码
#xiaorui.cc

 
import smtplib
 
def mail(subject='Ansible error mail', sender='<root>', to='root', cc=None, bcc=None, body=None):
    if not body:
        body = subject
 
    smtp = smtplib.SMTP('localhost')
 
    content = 'From: %sn' % sender
    content += 'To: %sn' % to
    if cc:
        content += 'Cc: %sn' % cc
    content += 'Subject: %snn' % subject
    content += body
 
    addresses = to.split(',')
    if cc:
        addresses += cc.split(',')
    if bcc:
        addresses += bcc.split(',')
 
    for address in addresses:
        smtp.sendmail(sender, address, content)
 
    smtp.quit()
 
 
class CallbackModule(object):
 
    """
    This Ansible callback plugin mails errors to interested parties.
    """
 
    def runner_on_failed(self, host, res, ignore_errors=False):
        if ignore_errors:
            return
        sender = '"Ansible: %s" <root>' % host
        subject = 'Failed: %(module_name)s %(module_args)s' % res['invocation']
        body = 'The following task failed for host ' + host + ':nn%(module_name)s %(module_args)snn' % res['invocation']
        if 'stdout' in res.keys() and res['stdout']:
            subject = res['stdout'].strip('rn').split('n')[-1]
            body += 'with the following output in standard output:nn' + res['stdout'] + 'nn'
        if 'stderr' in res.keys() and res['stderr']:
            subject = res['stderr'].strip('rn').split('n')[-1]
            body += 'with the following output in standard error:nn' + res['stderr'] + 'nn'
        if 'msg' in res.keys() and res['msg']:
            subject = res['msg'].strip('rn').split('n')[0]
            body += 'with the following message:nn' + res['msg'] + 'nn'
        body += 'A complete dump of the error:nn' + str(res)
        mail(sender=sender, subject=subject, body=body)
                  
    def runner_on_unreachable(self, host, res):
        sender = '"Ansible: %s" <root>' % host
        if isinstance(res, basestring):
            subject = 'Unreachable: %s' % res.strip('rn').split('n')[-1]
            body = 'An error occured for host ' + host + ' with the following message:nn' + res
        else:
            subject = 'Unreachable: %s' % res['msg'].strip('rn').split('n')[0]
            body = 'An error occured for host ' + host + ' with the following message:nn' +
                   res['msg'] + 'nnA complete dump of the error:nn' + str(res)
        mail(sender=sender, subject=subject, body=body)
 
    def runner_on_async_failed(self, host, res, jid):
        sender = '"Ansible: %s" <root>' % host
        if isinstance(res, basestring):
            subject = 'Async failure: %s' % res.strip('rn').split('n')[-1]
            body = 'An error occured for host ' + host + ' with the following message:nn' + res
        else:
            subject = 'Async failure: %s' % res['msg'].strip('rn').split('n')[0]
            body = 'An error occured for host ' + host + ' with the following message:nn' +
                   res['msg'] + 'nnA complete dump of the error:nn' + str(res)
        mail(sender=sender, subject=subject, body=body)

如果不想发邮件,又不想搞到数据库里面,怎么办? 那来点低端的。  直接写入到文件里面。

官方给出一个例子,大家照着模板写就行了。

 代码如下 复制代码
import os
import time
import json
 
TIME_FORMAT="%b %d %Y %H:%M:%S"
MSG_FORMAT="%(now)s - %(category)s - %(data)snn"
 
if not os.path.exists("/var/log/ansible/hosts"):
    os.makedirs("/var/log/ansible/hosts")
 
def log(host, category, data):
    if type(data) == dict:
        if 'verbose_override' in data:
            # avoid logging extraneous data from facts
            data = 'omitted'
        else:
            data = data.copy()
            invocation = data.pop('invocation', None)
            data = json.dumps(data)
            if invocation is not None:
                data = json.dumps(invocation) + " => %s " % data
 
    path = os.path.join("/var/log/ansible/hosts", host)
    now = time.strftime(TIME_FORMAT, time.localtime())
    fd = open(path, "a")
    fd.write(MSG_FORMAT % dict(now=now, category=category, data=data))
    fd.close()
 
class CallbackModule(object):
    """
    logs playbook results, per host, in /var/log/ansible/hosts
    """
 
    def on_any(self, *args, **kwargs):
        pass
 
    def runner_on_failed(self, host, res, ignore_errors=False):
        log(host, 'FAILED', res)
 
    def runner_on_ok(self, host, res):
        log(host, 'OK', res)
 
    def runner_on_skipped(self, host, item=None):
        log(host, 'SKIPPED', '...')
 
    def runner_on_unreachable(self, host, res):
        log(host, 'UNREACHABLE', res)
 
    def runner_on_no_hosts(self):
        pass
 
    def runner_on_async_poll(self, host, res, jid, clock):
        pass
 
    def runner_on_async_ok(self, host, res, jid):
        pass
 
    def runner_on_async_failed(self, host, res, jid):
        log(host, 'ASYNC_FAILED', res)
 
    def playbook_on_start(self):
        pass
 
    def playbook_on_notify(self, host, handler):
        pass
 
    def playbook_on_no_hosts_matched(self):
        pass
 
    def playbook_on_no_hosts_remaining(self):
        pass
 
    def playbook_on_task_start(self, name, is_conditional):
        pass
 
    def playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None):
        pass
 
    def playbook_on_setup(self):
        pass
 
    def playbook_on_import_for_host(self, host, imported_file):
        log(host, 'IMPORTED', imported_file)
 
    def playbook_on_not_import_for_host(self, host, missing_file):
        log(host, 'NOTIMPORTED', missing_file)
 
    def playbook_on_play_start(self, name):
        pass
 
    def playbook_on_stats(self, stats):
        pass

也可以把结果以webhooks钩子的方式,做些你想做的东西。

callbacks的各种状态还是很多的,每个函数的字眼还是很好理解的。

比如:

on_any  哪都有他 !任何的状态他触发。

runner_on_failed 失败

runner_on_ok  成功

runner_on_unreachable 网络不可达

runner_on_no_hosts 没有主机

runner_on_async_poll 任务的异步执行

playbook_on_start  playbook执行的时候

等等。。。。  自己尝试吧 !

 代码如下 复制代码
class CallbackModule(object):
 
 
    def on_any(self, *args, **kwargs):
        pass
 
    def runner_on_failed(self, host, res, ignore_errors=False):
        log(host, 'FAILED', res)
 
    def runner_on_ok(self, host, res):
        log(host, 'OK', res)
 
    def runner_on_skipped(self, host, item=None):
        log(host, 'SKIPPED', '...')
 
    def runner_on_unreachable(self, host, res):
        log(host, 'UNREACHABLE', res)
 
    def runner_on_no_hosts(self):
        pass
 
    def runner_on_async_poll(self, host, res, jid, clock):
        pass
 
    def runner_on_async_ok(self, host, res, jid):
        pass
 
    def runner_on_async_failed(self, host, res, jid):
        log(host, 'ASYNC_FAILED', res)
 
    def playbook_on_start(self):
        pass
 
    def playbook_on_notify(self, host, handler):
        pass
 
    def playbook_on_no_hosts_matched(self):
        pass
 
    def playbook_on_no_hosts_remaining(self):
        pass
 
    def playbook_on_task_start(self, name, is_conditional):
        pass
 
    def playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None):
        pass
 
    def playbook_on_setup(self):
        pass
 
    def playbook_on_import_for_host(self, host, imported_file):
        log(host, 'IMPORTED', imported_file)
 
    def playbook_on_not_import_for_host(self, host, missing_file):
        log(host, 'NOTIMPORTED', missing_file)
 
    def playbook_on_play_start(self, name):
        pass
 
    def playbook_on_stats(self, stats):
        pass

咱们可以简单看看ansible的callbacks源码。

规定了两个类,一个是供应ansible-playbook用的,还有一个是供应ansible,也就是cli。 根据各种的情况,调用不同的函数,首先会打到终端,再log日志,最后是自定义的callbacks的插件。

 

时间: 2024-11-08 23:31:22

运维工具ansible调用callbacks实现结果nosql回调的相关文章

自动化运维工具ansible的使用详细教程_服务器其它

一.ansible简介 1.ansible ansible是新出现的自动化运维工具,基于Python研发.糅合了众多老牌运维工具的优点实现了批量操作系统配置.批量程序的部署.批量运行命令等功能.仅需在管理工作站上安装ansible程序配置被管控主机的IP信息,被管控的主机无客户端.ansible应用程序存在于epel(第三方社区)源,依赖于很多python组件.主要包括: (1).连接插件connection plugins:负责和被监控端实现通信: (2).host inventory:指定操

自动化运维工具ansible安装配置步骤

一.简介 Ansible 是一个配置管理和应用部署工具,功能类似于目前业界的配置管理工具 Chef,Puppet,Saltstack.Ansible 是通过 Python 语言开发.Ansible 平台由 Michael DeHaan 创建,他同时也是知名软件 Cobbler 与 Func 的作者.Ansible 的第一个版本发布于 2012 年 2 月.Ansible 默认通过 SSH 协议管理机器,所以 Ansible 不需要安装客户端程序在服务器上.您只需要将 Ansible 安装在一台服

Linux自动化运维工具之ansible(一)

运维自动化是运维发展的必然方向,同时也是一个运维工程师实现效率最大化的必然选择. 运维自动化的知识可以说是浩瀚如海,本文将选择其中一个工具ansible为大家介绍一下. 一.哪些工作需要批量部署 1.操作系统的安装 常见的有collber,red hat satelite(redhat)系统专用. 2.操作系统的配置 常见的有cfengine,puppet,chef,func.其中puppet最受欢迎 3.批量程序的部署 4.批量命令的运行查看状态信息 二.ansible介绍 ansible的架

运维工具大宝典之开源平台篇

本文讲的是 :  运维工具大宝典之开源平台篇  , [IT168技术]在运维工具大宝典系列第一篇文章<运维工具大宝典之运维需求篇>中,云智慧对上云企业的运维需求进行的汇总,其中第6条"对开源的强烈需求"主要是来自运维人员,特别是技术大牛,他们喜欢一切尽在掌握的感脚,而这就需要开源运维工具. 目前流行的开源运维工具如Zabbix.Nagios等大部分来自国外,虽然这些开源产品功能非常强大,但对技术要求很高,而且缺少足够的中文文档和本土服务支持,一般运维人员要想用好难度很大.

基于YARN与Docker实现分布式Web服务的自动化部署运维工具

问题描述 部署运维工具主要有以下需求:-面向服务实例LTS类业务组件,不考虑数据库.缓存等基础组件-实现对这些分布式服务进行自动化部署.启停与伸缩-要能够支持自动部署与固定部署混合-自动部署,不指定主机,不指定端口-服务实例分配允许指定主机范围-固定部署,指定主机与端口,匹配传统需求-服务实例服务注册与查询-服务日志存储日志收集需求-数据存储共享存储需求挂共享存储-其他需求,配置界面与监控界面各位大神有没有实现思路与案例? 解决方案

Linux集群和自动化维3.6 轻量级自动化运维工具Fabric介绍

3.6 轻量级自动化运维工具Fabric介绍 笔者公司目前的数据中心采用的是分布式部署方案,在全球多地都有数据中心.数据中心采用的是AWS EC2机器,在核心的数据中心里,EC2机器的数量比较多,基本上每个数据中心都在运行着几百台AWS EC2机器,而且业务繁忙的时候,会通过AWS AMI(Amazon系统映像)直接上线几十台相同业务的EC2机器,它们的机器类型.系统应用和配置文件基本上都是一模一样的,很多时候需要修改相同的配置文件和执行相同的操作,这个时候为了避免重复性的劳动就需要用到自动化运

《Puppet权威指南》——1.3 自动化运维工具对比

1.3 自动化运维工具对比 在1.2节中我们介绍了现在比较常见的自动化配置工具Cfengine.Chef和Puppet,下面再来看一下这3款自动化运维工具的区别,如表1-1所示. 讲到这里,我们已经基本了解了Cfengine.Chef和Puppet这3款自动化运维工具.通过表1-1可知,Puppet的优势还是比较明显的.若是我们去Puppet的官方网站上看一看,会发现很多使用Puppet作为公司自动化运维工具的例子,目前超过18000家公司在使用Puppet软件,其中包括Twitter.Zyng

MySQL自动化运维工具 Inception

Inception 详细介绍 Inception -- 集审核.执行.备份及生成回滚语句于一身的MySQL自动化运维工具 MySQL语句的审核,在业界都已经基本被认同了,实际上也是对MySQL语句写法的统一化,标准化,而之前的人工审核,针对标准这个问题其实是很 吃力的,标准越多,DBA越累,开发也越累. 那么在这个都追求自动化运维的时代,审核也必须要跟上步伐,因此Inception诞生了.而Inception可以做的工作远不止是一个自动化审核工 具,同时还具备执行,生成对影响数据的回滚语句(类似

《Puppet权威指南》——第1章 运维工程师的利器——自动化运维工具

第1章 运维工程师的利器--自动化运维工具 随着网络云时代和大数据时代的到来,运维工程师负责管理的服务器数量也成倍地增长.如何管理好这些服务器为云时代和大数据时代保驾护航,是摆在运维工程师面前的一道难题.而解决这道难题就需要运维工程师对自动化运维工具的掌握达到一定的程度.笔者希望通过本章抛砖引玉,结合自己的经验介绍多年来使用自动化运维工具的心得和体会.本章首先介绍互联网运维工程师的职责.优秀运维工程师和普通运维工程师的区别:然后简要介绍常见的自动化运维工具:最后比较当前常见的自动化运维工具的优势