Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

# (C) 2016, Ievgen Khmelenko <ujenmr@gmail.com> 

# (C) 2017 Ansible Project 

# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 

 

from __future__ import (absolute_import, division, print_function) 

__metaclass__ = type 

 

DOCUMENTATION = ''' 

callback: logstash 

type: notification 

short_description: Sends events to Logstash 

description: 

- This callback will report facts and task events to Logstash https://www.elastic.co/products/logstash 

version_added: "2.3" 

requirements: 

- whitelisting in configuration 

- logstash (python library) 

options: 

server: 

description: Address of the Logstash server 

env: 

- name: LOGSTASH_SERVER 

default: localhost 

port: 

description: Port on which logstash is listening 

env: 

- name: LOGSTASH_PORT 

default: 5000 

type: 

description: Message type 

env: 

- name: LOGSTASH_TYPE 

default: ansible 

''' 

 

import os 

import json 

import socket 

import uuid 

from datetime import datetime 

 

import logging 

 

try: 

import logstash 

HAS_LOGSTASH = True 

except ImportError: 

HAS_LOGSTASH = False 

 

from ansible.plugins.callback import CallbackBase 

 

 

class CallbackModule(CallbackBase): 

""" 

ansible logstash callback plugin 

ansible.cfg: 

callback_plugins = <path_to_callback_plugins_folder> 

callback_whitelist = logstash 

and put the plugin in <path_to_callback_plugins_folder> 

 

logstash config: 

input { 

tcp { 

port => 5000 

codec => json 

} 

} 

 

Requires: 

python-logstash 

 

This plugin makes use of the following environment variables: 

LOGSTASH_SERVER (optional): defaults to localhost 

LOGSTASH_PORT (optional): defaults to 5000 

LOGSTASH_TYPE (optional): defaults to ansible 

""" 

 

CALLBACK_VERSION = 2.0 

CALLBACK_TYPE = 'aggregate' 

CALLBACK_NAME = 'logstash' 

CALLBACK_NEEDS_WHITELIST = True 

 

def __init__(self): 

super(CallbackModule, self).__init__() 

 

if not HAS_LOGSTASH: 

self.disabled = True 

self._display.warning("The required python-logstash is not installed. " 

"pip install python-logstash") 

else: 

self.logger = logging.getLogger('python-logstash-logger') 

self.logger.setLevel(logging.DEBUG) 

 

self.handler = logstash.TCPLogstashHandler( 

os.getenv('LOGSTASH_SERVER', 'localhost'), 

int(os.getenv('LOGSTASH_PORT', 5000)), 

version=1, 

message_type=os.getenv('LOGSTASH_TYPE', 'ansible') 

) 

 

self.logger.addHandler(self.handler) 

self.hostname = socket.gethostname() 

self.session = str(uuid.uuid1()) 

self.errors = 0 

self.start_time = datetime.utcnow() 

 

def v2_playbook_on_start(self, playbook): 

self.playbook = playbook._file_name 

data = { 

'status': "OK", 

'host': self.hostname, 

'session': self.session, 

'ansible_type': "start", 

'ansible_playbook': self.playbook, 

} 

self.logger.info("ansible start", extra=data) 

 

def v2_playbook_on_stats(self, stats): 

end_time = datetime.utcnow() 

runtime = end_time - self.start_time 

summarize_stat = {} 

for host in stats.processed.keys(): 

summarize_stat[host] = stats.summarize(host) 

 

if self.errors == 0: 

status = "OK" 

else: 

status = "FAILED" 

 

data = { 

'status': status, 

'host': self.hostname, 

'session': self.session, 

'ansible_type': "finish", 

'ansible_playbook': self.playbook, 

'ansible_playbook_duration': runtime.total_seconds(), 

'ansible_result': json.dumps(summarize_stat), 

} 

self.logger.info("ansible stats", extra=data) 

 

def v2_runner_on_ok(self, result, **kwargs): 

data = { 

'status': "OK", 

'host': self.hostname, 

'session': self.session, 

'ansible_type': "task", 

'ansible_playbook': self.playbook, 

'ansible_host': result._host.name, 

'ansible_task': result._task, 

'ansible_result': self._dump_results(result._result) 

} 

self.logger.info("ansible ok", extra=data) 

 

def v2_runner_on_skipped(self, result, **kwargs): 

data = { 

'status': "SKIPPED", 

'host': self.hostname, 

'session': self.session, 

'ansible_type': "task", 

'ansible_playbook': self.playbook, 

'ansible_task': result._task, 

'ansible_host': result._host.name 

} 

self.logger.info("ansible skipped", extra=data) 

 

def v2_playbook_on_import_for_host(self, result, imported_file): 

data = { 

'status': "IMPORTED", 

'host': self.hostname, 

'session': self.session, 

'ansible_type': "import", 

'ansible_playbook': self.playbook, 

'ansible_host': result._host.name, 

'imported_file': imported_file 

} 

self.logger.info("ansible import", extra=data) 

 

def v2_playbook_on_not_import_for_host(self, result, missing_file): 

data = { 

'status': "NOT IMPORTED", 

'host': self.hostname, 

'session': self.session, 

'ansible_type': "import", 

'ansible_playbook': self.playbook, 

'ansible_host': result._host.name, 

'missing_file': missing_file 

} 

self.logger.info("ansible import", extra=data) 

 

def v2_runner_on_failed(self, result, **kwargs): 

data = { 

'status': "FAILED", 

'host': self.hostname, 

'session': self.session, 

'ansible_type': "task", 

'ansible_playbook': self.playbook, 

'ansible_host': result._host.name, 

'ansible_task': result._task, 

'ansible_result': self._dump_results(result._result) 

} 

self.errors += 1 

self.logger.error("ansible failed", extra=data) 

 

def v2_runner_on_unreachable(self, result, **kwargs): 

data = { 

'status': "UNREACHABLE", 

'host': self.hostname, 

'session': self.session, 

'ansible_type': "task", 

'ansible_playbook': self.playbook, 

'ansible_host': result._host.name, 

'ansible_task': result._task, 

'ansible_result': self._dump_results(result._result) 

} 

self.logger.error("ansible unreachable", extra=data) 

 

def v2_runner_on_async_failed(self, result, **kwargs): 

data = { 

'status': "FAILED", 

'host': self.hostname, 

'session': self.session, 

'ansible_type': "task", 

'ansible_playbook': self.playbook, 

'ansible_host': result._host.name, 

'ansible_task': result._task, 

'ansible_result': self._dump_results(result._result) 

} 

self.errors += 1 

self.logger.error("ansible async", extra=data)