Coverage for lib/ansible/plugins/callback/logentries.py : 26%

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
# (c) 2015, Logentries.com, Jimmy Tang <jimmy.tang@logentries.com> # (c) 2017 Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
callback: logentries type: notification short_description: Sends events to Logentries description: - This callback plugin will generate JSON objects and send them to Logentries via TCP for auditing/debugging purposes. - Before 2.4, if you wanted to use an ini configuration, the file must be placed in the same directory as this plugin and named logentries.ini - In 2.4 and above you can just put it in the main Ansible configuration file. version_added: "2.0" requirements: - whitelisting in configuration - certifi (python library) - flatdict (pytnon library), if you want to use the 'flatten' option options: api: description: URI to the Logentries API env: - name: LOGENTRIES_API default: data.logentries.com ini: - section: callback_logentries key: api port: description: Http port to use when connecting to the API env: - name: LOGENTRIES_PORT default: 80 ini: - section: callback_logentries key: port tls_port: description: Port to use when connecting to the API when TLS is enabled env: - name: LOGENTRIES_TLS_PORT default: 443 ini: - section: callback_logentries key: tls_port token: description: The logentries "TCP token" env: - name: LOGENTRIES_ANSIBLE_TOKEN required: True ini: - section: callback_logentries key: token use_tls: description: - Toggle to decidewhether to use TLS to encrypt the communications with the API server env: - name: LOGENTRIES_USE_TLS default: False type: boolean ini: - section: callback_logentries key: use_tls flatten: description: flatten complex data structures into a single dictionary with complex keys type: boolean default: False env: - name: LOGENTRIES_FLATTEN ini: - section: callback_logentries key: flatten '''
examples: > To enable, add this to your ansible.cfg file in the defaults block
[defaults] callback_whitelist = logentries
Either set the environment variables export LOGENTRIES_API=data.logentries.com export LOGENTRIES_PORT=10000 export LOGENTRIES_ANSIBLE_TOKEN=dd21fc88-f00a-43ff-b977-e3a4233c53af
Or in the main Ansible config file [callback_logentries] api = data.logentries.com port = 10000 tls_port = 20000 use_tls = no token = dd21fc88-f00a-43ff-b977-e3a4233c53af flatten = False '''
HAS_CERTIFI = True
HAS_FLATDICT = True
# Todo: # * Better formatting of output before sending out to logentries data/api nodes.
self.LE_API = LE_API self.LE_PORT = LE_PORT self.LE_TLS_PORT = LE_TLS_PORT self.MIN_DELAY = 0.1 self.MAX_DELAY = 10 # Error message displayed when an incorrect Token has been detected self.INVALID_TOKEN = ("\n\nIt appears the LOGENTRIES_TOKEN parameter you entered is incorrect!\n\n") # Unicode Line separator character \u2028 self.LINE_SEP = u'\u2028'
self._display = display self._conn = None
self._conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._conn.connect((self.LE_API, self.LE_PORT))
self.close_connection()
root_delay = self.MIN_DELAY while True: try: self.open_connection() return except Exception as e: self._display.vvvv("Unable to connect to Logentries: %s" % str(e))
root_delay *= 2 if (root_delay > self.MAX_DELAY): root_delay = self.MAX_DELAY
wait_for = root_delay + random.uniform(0, root_delay)
try: self._display.vvvv("sleeping %s before retry" % wait_for) time.sleep(wait_for) except KeyboardInterrupt: raise
if self._conn is not None: self._conn.close()
# Replace newlines with Unicode line separator # for multi-line events data = to_text(data, errors='surrogate_or_strict') multiline = data.replace(u'\n', self.LINE_SEP) multiline += u"\n" # Send data, reconnect if needed while True: try: self._conn.send(to_bytes(multiline, errors='surrogate_or_strict')) except socket.error: self.reopen_connection() continue break
self.close_connection()
except ImportError: # for systems without TLS support. SocketAppender = PlainTextSocketAppender HAS_SSL = False else:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock = ssl.wrap_socket( sock=sock, keyfile=None, certfile=None, server_side=False, cert_reqs=ssl.CERT_REQUIRED, ssl_version=getattr( ssl, 'PROTOCOL_TLSv1_2', ssl.PROTOCOL_TLSv1), ca_certs=certifi.where(), do_handshake_on_connect=True, suppress_ragged_eofs=True, ) sock.connect((self.LE_API, self.LE_TLS_PORT)) self._conn = sock
# TODO: allow for alternate posting methods (REST/UDP/agent/etc) super(CallbackModule, self).__init__()
# verify dependencies if not HAS_SSL: self._display.warning("Unable to import ssl module. Will send over port 80.")
if not HAS_CERTIFI: self.disabled = True self._display.warning('The `certifi` python module is not installed.\nDisabling the Logentries callback plugin.')
self.le_jobid = str(uuid.uuid4())
# FIXME: make configurable, move to options self.timeout = 10
super(CallbackModule, self).set_options(task_keys=task_keys, var_options=var_options, direct=direct)
# get options try: self.api_url = self.get_option('api') self.api_port = self.get_option('port') self.api_tls_port = self.get_option('tls_port') self.use_tls = self.get_option('use_tls') self.flatten = self.get_option('flatten') except KeyError as e: self._display.warning("Missing option for Logentries callback plugin: %s" % to_native(e)) self.disabled = True
try: self.token = self.get_option('token') except KeyError as e: self._display.warning('Logentries token was not provided, this is required for this callback to operate, disabling') self.disabled = True
if self.flatten and not HAS_FLATDICT: self.disabled = True self._display.warning('You have chosen to flatten and the `flatdict` python module is not installed.\nDisabling the Logentries callback plugin.')
self._initialize_connections()
if not self.disabled: if self.use_tls: self._display.vvvv("Connecting to %s:%s with TLS" % (self.api_url, self.api_tls_port)) self._appender = TLSSocketAppender(display=self._display, LE_API=self.api_url, LE_TLS_PORT=self.api_tls_port) else: self._display.vvvv("Connecting to %s:%s" % (self.api_url, self.api_port)) self._appender = PlainTextSocketAppender(display=self._display, LE_API=self.api_url, LE_PORT=self.api_port) self._appender.reopen_connection()
if self.flatten: results = flatdict.FlatDict(record) self.emit(self._dump_results(results)) else: self.emit(self._dump_results(record))
msg = record.rstrip('\n') msg = "{0} {1}".format(self.token, msg) self._appender.put(msg) self._display.vvvv("Sent event to logentries")
return {'le_jobid': self.le_jobid, 'hostname': host, 'results': res}
results = self._set_info(host, res) results['status'] = 'OK' self.emit_formatted(results)
results = self._set_info(host, res) results['status'] = 'FAILED' self.emit_formatted(results)
results = self._set_info(host, item) del results['results'] results['status'] = 'SKIPPED' self.emit_formatted(results)
results = self._set_info(host, res) results['status'] = 'UNREACHABLE' self.emit_formatted(results)
results = self._set_info(host, res) results['jid'] = jid results['status'] = 'ASYNC_FAILED' self.emit_formatted(results)
results = {} results['le_jobid'] = self.le_jobid results['started_by'] = os.getlogin() if play.name: results['play'] = play.name results['hosts'] = play.hosts self.emit_formatted(results)
""" close connection """ self._appender.close_connection() |