Merge "Add external http logging callback"
This commit is contained in:
commit
14d175d00f
34
README.rst
34
README.rst
@ -1,4 +1,36 @@
|
||||
==================
|
||||
Validations-common
|
||||
==================
|
||||
|
||||
A collection of common Ansible libraries and plugins for the Validation Framework
|
||||
A collection of common Ansible libraries and plugins for the Validation
|
||||
Framework
|
||||
|
||||
|
||||
Validations Callbacks
|
||||
=====================
|
||||
|
||||
******************
|
||||
http_json callback
|
||||
******************
|
||||
|
||||
The callback `http_json` sends Validations logs and information to an HTTP
|
||||
server as a JSON format in order to get caught and analysed with external
|
||||
tools for log parsing (as Fluentd or others).
|
||||
|
||||
This callback inherits from `validation_json` the format of the logging
|
||||
remains the same as the other logger that the Validation Framework is using
|
||||
by default.
|
||||
|
||||
To enable this callback, you need to add it to the callback whitelist.
|
||||
Then you need to export your http server url and port::
|
||||
|
||||
export HTTP_JSON_SERVER=http://localhost
|
||||
export HTTP_JSON_PORT=8989
|
||||
|
||||
The callback will post JSON log to the URL provided.
|
||||
This repository has a simple HTTP server for testing purpose under::
|
||||
|
||||
tools/http_server.py
|
||||
|
||||
The default host and port are localhost and 8989, feel free to adjust those
|
||||
values to your needs.
|
||||
|
54
tools/http_server.py
Normal file
54
tools/http_server.py
Normal file
@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
import logging
|
||||
|
||||
|
||||
class SimpleHandler(BaseHTTPRequestHandler):
|
||||
def _set_headers(self):
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type', 'text/html')
|
||||
self.end_headers()
|
||||
|
||||
def do_GET(self):
|
||||
logging.info("Received GET request:\n"
|
||||
"Headers: {}\n".format(str(self.headers)))
|
||||
self._set_headers()
|
||||
self.wfile.write("GET request: {}".format(self.path).encode('utf-8'))
|
||||
|
||||
def do_POST(self):
|
||||
content_length = int(self.headers['Content-Length'])
|
||||
data = self.rfile.read(content_length)
|
||||
logging.info("Received POST request:\n"
|
||||
"Headers: {}\n"
|
||||
"Body: \n{}\n".format(self.headers, data.decode('utf-8')))
|
||||
self._set_headers()
|
||||
self.wfile.write("POST request: {}".format(self.path).encode('utf-8'))
|
||||
|
||||
|
||||
def run(host='localhost', port=8989):
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
http_server = HTTPServer((host, port), SimpleHandler)
|
||||
logging.info("Starting http server...\n")
|
||||
try:
|
||||
http_server.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
http_server.server_close()
|
||||
logging.info('Stopping http server...\n')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
94
validations_common/callback_plugins/http_json.py
Normal file
94
validations_common/callback_plugins/http_json.py
Normal file
@ -0,0 +1,94 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
requirements:
|
||||
- whitelist in configuration
|
||||
short_description: sends JSON events to a HTTP server
|
||||
description:
|
||||
- This plugin logs ansible-playbook and ansible runs to an HTTP server in JSON format
|
||||
options:
|
||||
server:
|
||||
description: remote server that will receive the event
|
||||
env:
|
||||
- name: HTTP_JSON_SERVER
|
||||
default: http://localhost
|
||||
ini:
|
||||
- section: callback_http_json
|
||||
key: http_json_server
|
||||
port:
|
||||
description: port on which the remote server is listening
|
||||
env:
|
||||
- name: HTTP_JSON_PORT
|
||||
default: 8989
|
||||
ini:
|
||||
- section: callback_http_json
|
||||
key: http_json_port
|
||||
'''
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
|
||||
from urllib import request
|
||||
|
||||
from validations_common.callback_plugins import validation_json
|
||||
|
||||
url = '{}:{}'.format(os.getenv('HTTP_JSON_SERVER', 'http://localhost'),
|
||||
os.getenv('HTTP_JSON_PORT', '8989'))
|
||||
|
||||
|
||||
def http_post(data):
|
||||
req = request.Request(url)
|
||||
req.add_header('Content-Type', 'application/json; charset=utf-8')
|
||||
json_data = json.dumps(data)
|
||||
json_bytes = json_data.encode('utf-8')
|
||||
req.add_header('Content-Length', len(json_bytes))
|
||||
response = request.urlopen(req, json_bytes)
|
||||
|
||||
|
||||
def current_time():
|
||||
return '%sZ' % datetime.datetime.utcnow().isoformat()
|
||||
|
||||
|
||||
class CallbackModule(validation_json.CallbackModule):
|
||||
|
||||
CALLBACK_VERSION = 2.0
|
||||
CALLBACK_TYPE = 'aggregate'
|
||||
CALLBACK_NAME = 'http_json'
|
||||
CALLBACK_NEEDS_WHITELIST = True
|
||||
|
||||
def __init__(self):
|
||||
super(validation_json.CallbackModule, self).__init__()
|
||||
self.results = []
|
||||
self.simple_results = []
|
||||
self.env = {}
|
||||
self.t0 = None
|
||||
self.current_time = current_time()
|
||||
|
||||
def v2_playbook_on_stats(self, stats):
|
||||
"""Display info about playbook statistics"""
|
||||
|
||||
hosts = sorted(stats.processed.keys())
|
||||
|
||||
summary = {}
|
||||
for h in hosts:
|
||||
s = stats.summarize(h)
|
||||
summary[h] = s
|
||||
|
||||
http_post({
|
||||
'plays': self.results,
|
||||
'stats': summary,
|
||||
'validation_output': self.simple_results
|
||||
})
|
Loading…
Reference in New Issue
Block a user