Skip to content

Commit a535a04

Browse files
chris.willmoreolivielpeau
authored andcommitted
Add compatibility with Ansible 2
[[email protected]: Merged the changes into the existing callback]
1 parent d0e7672 commit a535a04

File tree

2 files changed

+57
-17
lines changed

2 files changed

+57
-17
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ A callback to send Ansible events and metrics to Datadog.
44

55
## Requirements
66

7-
Ansible >=1.1,<2.0
7+
Ansible >=1.1
88

99
The following python libraries are required on the Ansible server:
1010

datadog_callback.py

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,36 @@
1+
import getpass
12
import os.path
23
import time
34

45
import datadog
56
import yaml
67

8+
try:
9+
# Ansible v2
10+
from ansible.plugins.callback import CallbackBase
11+
from __main__ import cli
12+
except ImportError:
13+
# Ansible v1
14+
CallbackBase = object
15+
cli = None
716

8-
class CallbackModule(object):
17+
18+
class CallbackModule(CallbackBase):
919
def __init__(self):
1020
# Read config and set up API client
1121
api_key, url = self._load_conf(os.path.join(os.path.dirname(__file__), "datadog_callback.yml"))
1222
datadog.initialize(api_key=api_key, api_host=url)
1323

1424
self._playbook_name = None
1525
self._start_time = time.time()
26+
self._options = None
27+
if cli:
28+
self._options = cli.options
29+
30+
# self.playbook is either set by Ansible (v1), or by us in the `playbook_start` callback method (v2)
31+
self.playbook = None
32+
# self.play is either set by Ansible (v1), or by us in the `playbook_on_play_start` callback method (v2)
33+
self.play = None
1634

1735
# Load parameters from conf file
1836
def _load_conf(self, file_path):
@@ -47,7 +65,6 @@ def _send_event(self, title, alert_type=None, text=None, tags=None, host=None, e
4765

4866
# Send event, aggregated with other task-level events from the same host
4967
def send_task_event(self, title, alert_type='info', text='', tags=None, host=None):
50-
# self.play is set by ansible
5168
if getattr(self, 'play', None):
5269
if tags is None:
5370
tags = []
@@ -98,6 +115,23 @@ def start_timer(self):
98115
def get_elapsed_time(self):
99116
return time.time() - self._start_time
100117

118+
# Handle `playbook_on_start` callback, common to Ansible v1 & v2
119+
def _handle_playbook_on_start(self, playbook_file_name, inventory):
120+
self.start_timer()
121+
122+
# Set the playbook name from its filename
123+
self._playbook_name, _ = os.path.splitext(
124+
os.path.basename(playbook_file_name))
125+
inventory_name = os.path.basename(os.path.realpath(inventory))
126+
127+
self.send_playbook_event(
128+
'Ansible playbook "{0}" started by "{1}" against "{2}"'.format(
129+
self._playbook_name,
130+
getpass.getuser(),
131+
inventory_name),
132+
event_type='start',
133+
)
134+
101135
# Default tags sent with events and metrics
102136
@property
103137
def default_tags(self):
@@ -121,7 +155,7 @@ def format_result(res):
121155
elif not res.get('invocation'):
122156
event_text = msg
123157
else:
124-
event_text = "$$$\n{0}[{1}]\n$$$\n".format(res['invocation']['module_name'], res['invocation']['module_args'])
158+
event_text = "$$$\n{0}[{1}]\n$$$\n".format(res['invocation']['module_name'], res['invocation'].get('module_args', ''))
125159
event_text += msg
126160
module_name = 'module:{0}'.format(res['invocation']['module_name'])
127161

@@ -159,20 +193,26 @@ def runner_on_unreachable(self, host, res):
159193
host=host,
160194
)
161195

196+
# Implementation compatible with Ansible v1 only
162197
def playbook_on_start(self):
163-
# Retrieve the playbook name from its filename
164-
self._playbook_name, _ = os.path.splitext(
165-
os.path.basename(self.playbook.filename))
166-
self.start_timer()
167-
host_list = self.playbook.inventory.host_list
168-
inventory = os.path.basename(os.path.realpath(host_list))
169-
self.send_playbook_event(
170-
'Ansible playbook "{0}" started by "{1}" against "{2}"'.format(
171-
self._playbook_name,
172-
self.playbook.remote_user,
173-
inventory),
174-
event_type='start',
175-
)
198+
playbook_file_name = self.playbook.filename
199+
inventory = self.playbook.inventory.host_list
200+
201+
self._handle_playbook_on_start(playbook_file_name, inventory)
202+
203+
# Implementation compatible with Ansible v2 only
204+
def v2_playbook_on_start(self, playbook):
205+
# On Ansible v2, Ansible doesn't set `self.playbook` automatically
206+
self.playbook = playbook
207+
208+
playbook_file_name = self.playbook._file_name
209+
inventory = self._options.inventory
210+
211+
self._handle_playbook_on_start(playbook_file_name, inventory)
212+
213+
def v2_playbook_on_play_start(self, play):
214+
# On Ansible v2, Ansible doesn't set `self.play` automatically
215+
self.play = play
176216

177217
def playbook_on_stats(self, stats):
178218
total_tasks = 0

0 commit comments

Comments
 (0)