ansible调用callbacks插件实现结果nosql输出回调

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介:

前言:

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


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

沈灿这货先写了关于ansible callbacks的文章,我看到了后,才知道有而一个东西。大家可以看看 。

http://www.shencan.net/index.php/2014/07/17/ansible-%E6%8F%92%E4%BB%B6%E4%B9%8Bcallback_plugins-%EF%BC%88%E5%AE%9E%E6%88%98%EF%BC%89/ 



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


原文:http://rfyiamcool.blog.51cto.com/1030776/1440624 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#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):
         =  redis.Redis(host = '127.0.0.1' , port = 6379 , db = 0
         r. set (host, str (res))
 
         =  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 ):
         =  open ( '/tmp/11' , 'a' )
         f.write( '\nbad\n' )
         f.close()
         log(host, res)



wKiom1PLxF7RgYIpAANcxv3ltOA830.jpg

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

原文:http://rfyiamcool.blog.51cto.com/1030776/1440624 


wKiom1PLz6jT6hSxAAvukgGOdaA867.jpg

原文:http://rfyiamcool.blog.51cto.com/1030776/1440624 


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


wKiom1PL2CqjPJdLAAi3W-Hd6Xs379.jpg


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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#xiaorui.cc
原文:http: / / rfyiamcool.blog. 51cto .com / 1030776 / 1440624 
  
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: %s\n'  %  sender
     content  + =  'To: %s\n'  %  to
     if  cc:
         content  + =  'Cc: %s\n'  %  cc
     content  + =  'Subject: %s\n\n'  %  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  +  ':\n\n%(module_name)s %(module_args)s\n\n'  %  res[ 'invocation' ]
         if  'stdout'  in  res.keys()  and  res[ 'stdout' ]:
             subject  =  res[ 'stdout' ].strip( '\r\n' ).split( '\n' )[ - 1 ]
             body  + =  'with the following output in standard output:\n\n'  +  res[ 'stdout' +  '\n\n'
         if  'stderr'  in  res.keys()  and  res[ 'stderr' ]:
             subject  =  res[ 'stderr' ].strip( '\r\n' ).split( '\n' )[ - 1 ]
             body  + =  'with the following output in standard error:\n\n'  +  res[ 'stderr' +  '\n\n'
         if  'msg'  in  res.keys()  and  res[ 'msg' ]:
             subject  =  res[ 'msg' ].strip( '\r\n' ).split( '\n' )[ 0 ]
             body  + =  'with the following message:\n\n'  +  res[ 'msg' +  '\n\n'
         body  + =  'A complete dump of the error:\n\n'  +  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( '\r\n' ).split( '\n' )[ - 1 ]
             body  =  'An error occured for host '  +  host  +  ' with the following message:\n\n'  +  res
         else :
             subject  =  'Unreachable: %s'  %  res[ 'msg' ].strip( '\r\n' ).split( '\n' )[ 0 ]
             body  =  'An error occured for host '  +  host  +  ' with the following message:\n\n'  +  \
                    res[ 'msg' +  '\n\nA complete dump of the error:\n\n'  +  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( '\r\n' ).split( '\n' )[ - 1 ]
             body  =  'An error occured for host '  +  host  +  ' with the following message:\n\n'  +  res
         else :
             subject  =  'Async failure: %s'  %  res[ 'msg' ].strip( '\r\n' ).split( '\n' )[ 0 ]
             body  =  'An error occured for host '  +  host  +  ' with the following message:\n\n'  +  \
                    res[ 'msg' +  '\n\nA complete dump of the error:\n\n'  +  str (res)
         mail(sender = sender, subject = subject, body = body)

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

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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import  os
import  time
import  json
 
TIME_FORMAT = "%b %d %Y %H:%M:%S"
MSG_FORMAT = "%(now)s - %(category)s - %(data)s\n\n"
 
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

原文: http://rfyiamcool.blog.51cto.com/1030776/1440624 

wKioL1PLzZbDY29sAAWL-68tvIQ014.jpg


也可以把结果以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执行的时候

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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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

原文: http://rfyiamcool.blog.51cto.com/1030776/1440624 


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

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




好了,就这样了 !!!! 




 本文转自 rfyiamcool 51CTO博客,原文链接:http://blog.51cto.com/rfyiamcool/1440624,如需转载请自行联系原作者


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
运维 应用服务中间件 网络安全
自动化运维的新篇章:使用Ansible进行服务器配置管理
【10月更文挑战第34天】在现代IT基础设施的快速迭代中,自动化运维成为提升效率、确保一致性的关键手段。本文将通过介绍Ansible工具的使用,展示如何实现高效的服务器配置管理。从基础安装到高级应用,我们将一步步揭开自动化运维的神秘面纱,让你轻松掌握这一技术,为你的运维工作带来革命性的变化。
|
25天前
|
运维 应用服务中间件 Linux
自动化运维的利器:Ansible在配置管理中的应用
【10月更文挑战第39天】本文旨在通过深入浅出的方式,向读者展示如何利用Ansible这一强大的自动化工具来优化日常的运维工作。我们将从基础概念讲起,逐步深入到实战操作,不仅涵盖Ansible的核心功能,还会分享一些高级技巧和最佳实践。无论你是初学者还是有经验的运维人员,这篇文章都会为你提供有价值的信息,帮助你提升工作效率。
|
9天前
|
运维 Ubuntu 应用服务中间件
自动化运维之路:使用Ansible进行服务器管理
在现代IT基础设施中,自动化运维已成为提高效率和可靠性的关键。本文将引导您通过使用Ansible这一强大的自动化工具来简化日常的服务器管理任务。我们将一起探索如何配置Ansible、编写Playbook以及执行自动化任务,旨在为读者提供一条清晰的路径,从而步入自动化运维的世界。
|
7天前
|
运维 网络安全 Python
自动化运维:使用Ansible实现批量服务器配置
在快速迭代的IT环境中,高效、可靠的服务器管理变得至关重要。本文将介绍如何使用Ansible这一强大的自动化工具,来简化和加速批量服务器配置过程。我们将从基础开始,逐步深入到更复杂的应用场景,确保即使是新手也能跟上节奏。文章将不包含代码示例,而是通过清晰的步骤和逻辑结构,引导读者理解自动化运维的核心概念及其在实际操作中的应用。
|
8天前
|
运维 Ubuntu 网络协议
自动化运维:使用Ansible进行服务器配置管理
在现代IT架构中,自动化运维已成为提升效率、减少人为错误的关键。本文将介绍如何使用Ansible这一强大的自动化工具来简化和标准化服务器的配置管理过程。通过具体的代码示例和操作步骤,我们将展示如何快速部署应用、管理配置以及自动化日常任务,从而确保环境的一致性和可靠性。
|
20天前
|
运维 监控 安全
自动化运维的利剑:Ansible在现代IT架构中的应用
在数字化浪潮中,企业对IT系统的敏捷性和可靠性要求日益提高。Ansible,一种简单但强大的自动化运维工具,正成为现代IT架构中不可或缺的一部分。它通过声明式编程语言YAM,简化了系统配置、应用部署和任务自动化的过程,显著提升了运维效率和准确性。本文将深入探讨Ansible的核心特性、应用场景以及如何有效整合进现有IT环境,为读者揭示其在自动化运维中的实用价值和未来发展潜力。
|
19天前
|
运维 安全 Ubuntu
自动化运维:使用Ansible进行服务器配置管理
在现代IT基础设施中,自动化运维是确保高效、稳定和安全服务的关键。本文将深入介绍如何使用Ansible这一开源工具来简化服务器配置管理工作,从基础安装到高级应用,我们将一步步展示如何通过Ansible Playbooks实现自动化部署和维护,旨在帮助读者构建更加灵活和可扩展的运维体系。
35 7