File: //opt/saltstack/salt/lib/python3.10/site-packages/salt/returners/splunk.py
"""
Send json response data to Splunk via the HTTP Event Collector
Requires the following config values to be specified in config or pillar:
.. code-block:: yaml
splunk_http_forwarder:
token: <splunk_http_forwarder_token>
indexer: <hostname/IP of Splunk indexer>
sourcetype: <Destination sourcetype for data>
index: <Destination index for data>
verify_ssl: true
Run a test by using ``salt-call test.ping --return splunk``
Written by Scott Pack (github.com/scottjpack)
"""
import logging
import socket
import time
import requests
import salt.utils.json
_max_content_bytes = 100000
http_event_collector_debug = False
log = logging.getLogger(__name__)
__virtualname__ = "splunk"
def __virtual__():
"""
Return virtual name of the module.
:return: The virtual name of the module.
"""
return __virtualname__
def returner(ret):
"""
Send a message to Splunk via the HTTP Event Collector.
Requires the Splunk HTTP Event Collector running on port 8088.
This is available on Splunk Enterprise version 6.3 or higher.
"""
# Get Splunk Options
opts = _get_options()
log.info(
"Options: %s",
salt.utils.json.dumps(opts),
)
http_collector = _create_http_event_collector(opts)
payload = _prepare_splunk_payload(ret, opts)
http_collector.sendEvent(payload)
return True
def event_return(events):
"""
Return events to Splunk via the HTTP Event Collector.
Requires the Splunk HTTP Event Collector running on port 8088.
This is available on Splunk Enterprise version 6.3 or higher.
"""
# Get Splunk Options
opts = _get_options()
log.info(
"Options: %s",
salt.utils.json.dumps(opts),
)
http_collector = _create_http_event_collector(opts)
for event in events:
payload = _prepare_splunk_payload(event, opts)
http_collector.sendEvent(payload)
return True
def _get_options():
try:
token = __salt__["config.get"]("splunk_http_forwarder:token")
indexer = __salt__["config.get"]("splunk_http_forwarder:indexer")
sourcetype = __salt__["config.get"]("splunk_http_forwarder:sourcetype")
index = __salt__["config.get"]("splunk_http_forwarder:index")
verify_ssl = __salt__["config.get"](
"splunk_http_forwarder:verify_ssl", default=True
)
except Exception: # pylint: disable=broad-except
log.error("Splunk HTTP Forwarder parameters not present in config.")
return None
splunk_opts = {
"token": token,
"indexer": indexer,
"sourcetype": sourcetype,
"index": index,
"verify_ssl": verify_ssl,
}
return splunk_opts
def _create_http_event_collector(opts):
"""
Prepare a connection to the Splunk HTTP event collector.
"""
http_event_collector_key = opts["token"]
http_event_collector_host = opts["indexer"]
http_event_collector_verify_ssl = opts["verify_ssl"]
# Return the collector
return http_event_collector(
http_event_collector_key,
http_event_collector_host,
verify_ssl=http_event_collector_verify_ssl,
)
def _prepare_splunk_payload(event, opts):
"""
Prepare a payload for submission to the Splunk HTTP event collector.
"""
# Get Splunk Options
opts = _get_options()
# init the payload
payload = {}
# Set up the event metadata
payload.update({"index": opts["index"]})
payload.update({"sourcetype": opts["sourcetype"]})
# Add the event
payload.update({"event": event})
log.info(
"Payload: %s",
salt.utils.json.dumps(payload),
)
return payload
# Thanks to George Starcher for the http_event_collector class (https://github.com/georgestarcher/)
class http_event_collector:
def __init__(
self,
token,
http_event_server,
host="",
http_event_port="8088",
http_event_server_ssl=True,
max_bytes=_max_content_bytes,
verify_ssl=True,
):
self.token = token
self.batchEvents = []
self.maxByteLength = max_bytes
self.currentByteLength = 0
self.verify_ssl = verify_ssl
# Set host to specified value or default to localhostname if no value provided
if host:
self.host = host
else:
self.host = socket.gethostname()
# Build and set server_uri for http event collector
# Defaults to SSL if flag not passed
# Defaults to port 8088 if port not passed
if http_event_server_ssl:
buildURI = ["https://"]
else:
buildURI = ["http://"]
for i in [http_event_server, ":", http_event_port, "/services/collector/event"]:
buildURI.append(i)
self.server_uri = "".join(buildURI)
if http_event_collector_debug:
log.debug(self.token)
log.debug(self.server_uri)
def sendEvent(self, payload, eventtime=""):
# Method to immediately send an event to the http event collector
headers = {"Authorization": "Splunk " + self.token}
# If eventtime in epoch not passed as optional argument use current system time in epoch
if not eventtime:
eventtime = str(int(time.time()))
# Fill in local hostname if not manually populated
if "host" not in payload:
payload.update({"host": self.host})
# Update time value on payload if need to use system time
data = {"time": eventtime}
data.update(payload)
# send event to http event collector
r = requests.post(
self.server_uri,
data=salt.utils.json.dumps(data),
headers=headers,
verify=self.verify_ssl,
timeout=120,
)
# Print debug info if flag set
if http_event_collector_debug:
log.debug(r.text)
log.debug(data)