Skip to content

Instantly share code, notes, and snippets.

@Deepakkothandan
Created February 15, 2017 10:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save Deepakkothandan/4808bcb4e9881e2d4fe8a643a9bab4eb to your computer and use it in GitHub Desktop.
Save Deepakkothandan/4808bcb4e9881e2d4fe8a643a9bab4eb to your computer and use it in GitHub Desktop.
Rocketchat callback plugin for Ansible
# (C) 2016, Deepak Kothandan
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import json
import os
import uuid
import urllib
try:
from __main__ import cli
except ImportError:
cli = None
from ansible.constants import mk_boolean
from ansible.module_utils.urls import open_url
from ansible.plugins.callback import CallbackBase
try:
import prettytable
HAS_PRETTYTABLE = True
except ImportError:
HAS_PRETTYTABLE = False
class CallbackModule(CallbackBase):
"""This is an ansible callback plugin that sends status
updates to a RocketChat channel during playbook execution.
This plugin makes use of the following environment variables:
ROCKETCHAT_WEBHOOK_URL (required): RocketChat Webhook URL
ROCKETCHAT_CHANNEL (optional): RocketChat room to post in. Default: #ansible
ROCKETCHAT_USERNAME (optional): Username to post as. Default: ansible
ROCKETCHAT_INVOCATION (optional): Show command line invocation
details. Default: False
Requires:
prettytable
"""
CALLBACK_VERSION = 2.0
CALLBACK_TYPE = 'notification'
CALLBACK_NAME = 'rocket'
CALLBACK_NEEDS_WHITELIST = True
os.environ['ROCKETCHAT_WEBHOOK_URL'] = 'ur rocketchat webhook url here'
def __init__(self, display=None):
self.disabled = False
if cli:
self._options = cli.options
else:
self._options = None
super(CallbackModule, self).__init__(display=display)
if not HAS_PRETTYTABLE:
self.disabled = True
self._display.warning('The `prettytable` python module is not '
'installed. Disabling the RocketChat callback '
'plugin.')
self.webhook_url = os.getenv('ROCKETCHAT_WEBHOOK_URL')
self.channel = os.getenv('ROCKETCHAT_CHANNEL', '#ansible')
self.username = os.getenv('ROCKETCHAT_USERNAME', 'ansible')
self.show_invocation = mk_boolean(
os.getenv('ROCKETCHAT_INVOCATION', self._display.verbosity > 1)
)
self.playbook_name = None
# This is a 6 character identifier provided with each message
# This makes it easier to correlate messages when there are more
# than 1 simultaneous playbooks running
self.guid = uuid.uuid4().hex[:6]
def send_msg(self, attachments):
payload = {}
payload['username'] = 'username'
payload['icon_url'] = 'https://img.stackshare.io/service/663/ElOjna20.png'
payload['attachments'] = attachments
payload['parse'] = 'none'
headers = {'content-type': 'application/json'}
data = json.dumps(payload)
try:
response = open_url(self.webhook_url, data=data, headers=headers)
return response.read()
except Exception as e:
self._display.warning('Could not submit message to RocketChat: %s' %
str(e))
def v2_playbook_on_start(self, playbook):
self.playbook_name = os.path.basename(playbook._file_name)
title = [
'*Playbook initiated* (_%s_)' % self.guid
]
invocation_items = []
if self._options and self.show_invocation:
tags = self._options.tags
skip_tags = self._options.skip_tags
extra_vars = self._options.extra_vars
subset = self._options.subset
inventory = os.path.basename(
os.path.realpath(self._options.inventory)
)
invocation_items.append('Inventory: %s' % inventory)
if tags and tags != 'all':
invocation_items.append('Tags: %s' % tags)
if skip_tags:
invocation_items.append('Skip Tags: %s' % skip_tags)
if subset:
invocation_items.append('Limit: %s' % subset)
if extra_vars:
invocation_items.append('Extra Vars: %s' %
' '.join(extra_vars))
title.append('by *%s*' % self._options.remote_user)
title.append('\n\n*%s*' % self.playbook_name)
msg_items = [' '.join(title)]
if invocation_items:
msg_items.append('```\n%s\n```' % '\n'.join(invocation_items))
msg = '\n'.join(msg_items)
attachments = [{
'fallback': msg,
'fields': [
{
'value': msg
}
],
'color': 'warning',
'mrkdwn_in': ['text', 'fallback', 'fields'],
}]
self.send_msg(attachments=attachments)
def v2_playbook_on_play_start(self, play):
"""Display Play start messages"""
name = play.name or 'Play name not specified (%s)' % play._uuid
msg = '*Starting play* (_%s_)\n\n*%s*' % (self.guid, name)
attachments = [
{
'fallback': msg,
'text': msg,
'color': 'warning',
'mrkdwn_in': ['text', 'fallback', 'fields'],
}
]
self.send_msg(attachments=attachments)
def v2_playbook_on_stats(self, stats):
"""Display info about playbook statistics"""
hosts = sorted(stats.processed.keys())
t = prettytable.PrettyTable(['Host', 'Ok', 'Changed', 'Unreachable',
'Failures'])
failures = False
unreachable = False
for h in hosts:
s = stats.summarize(h)
if s['failures'] > 0:
failures = True
if s['unreachable'] > 0:
unreachable = True
t.add_row([h] + [s[k] for k in ['ok', 'changed', 'unreachable',
'failures']])
attachments = []
msg_items = [
'*Playbook Complete* (_%s_)' % self.guid
]
if failures or unreachable:
color = 'danger'
msg_items.append('\n*Failed!*')
else:
color = 'good'
msg_items.append('\n*Success!*')
msg_items.append('```\n%s\n```' % t)
msg = '\n'.join(msg_items)
attachments.append({
'fallback': msg,
'fields': [
{
'value': msg
}
],
'color': color,
'mrkdwn_in': ['text', 'fallback', 'fields']
})
self.send_msg(attachments=attachments)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment