Skip to content

Commit

Permalink
fix: standalone HEC Event writer (#380)
Browse files Browse the repository at this point in the history
When create_from_token() is invoked, it triggers the HECEventWriter
constructor with scheme, host, and port set to None. This leads to a
get_splunkd_access_info() call, which throws an exception if the HEC URI
doesn’t reference the local machine. As this call is unnecessary in such
cases, its invocation has been relocated within the if-statement
  • Loading branch information
zugf authored Jul 22, 2024
1 parent bdc78c8 commit 4e961b2
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 67 deletions.
5 changes: 2 additions & 3 deletions solnlib/modular_input/event_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,12 +229,11 @@ def __init__(
else:
self.logger = logging

if not all([scheme, host, port]):
scheme, host, port = get_splunkd_access_info()

if hec_uri and hec_token:
scheme, host, hec_port = utils.extract_http_scheme_host_port(hec_uri)
else:
if not all([scheme, host, port]):
scheme, host, port = get_splunkd_access_info()
hec_port, hec_token = self._get_hec_config(
hec_input_name, session_key, scheme, host, port, **context
)
Expand Down
176 changes: 112 additions & 64 deletions tests/unit/test_modular_input_event_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import sys

import common
import pytest
from splunklib import binding

from solnlib.modular_input import ClassicEventWriter, HECEventWriter
Expand Down Expand Up @@ -85,7 +86,54 @@ def flush(self):
assert mock_stdout.write_count == 1


def test_hec_event_writer(monkeypatch):
def create_hec_event_writer__create_from_input(hec=False):
return HECEventWriter.create_from_input(
"HECTestInput",
"https://localhost:8089",
common.SESSION_KEY,
global_settings_schema=hec,
)


def create_hec_event_writer__create_from_token_with_session_key(hec=False):
return HECEventWriter.create_from_token_with_session_key(
"https://localhost:8089",
common.SESSION_KEY,
"https://localhost:8090",
"test_token",
global_settings_schema=hec,
)


def create_hec_event_writer__create_from_token(hec=False):
return HECEventWriter.create_from_token(
"https://localhost:8090", "test_token", global_settings_schema=hec
)


def create_hec_event_writer__create_from_token__external_host(hec=False):
return HECEventWriter.create_from_token(
"https://external:8090", "test_token", global_settings_schema=hec
)


def create_hec_event_writer__constructor(hec=False):
return HECEventWriter(
"HECTestInput", common.SESSION_KEY, global_settings_schema=hec
)


@pytest.mark.parametrize(
"create_hec_event_writer, has_splunk_home",
[
(create_hec_event_writer__constructor, True),
(create_hec_event_writer__create_from_input, True),
(create_hec_event_writer__create_from_token_with_session_key, True),
(create_hec_event_writer__create_from_token, True),
(create_hec_event_writer__create_from_token__external_host, False),
],
)
def test_hec_event_writer(monkeypatch, create_hec_event_writer, has_splunk_home):
def mock_get(self, path_segment, owner=None, app=None, sharing=None, **query):
if path_segment.endswith("/http"):
return common.make_response_record(
Expand Down Expand Up @@ -120,42 +168,46 @@ def mock_get_hec_config(
):
return "8088", "87de04d1-0823-11e6-9c94-a45e60e"

common.mock_splunkhome(monkeypatch)
if has_splunk_home:
common.mock_splunkhome(monkeypatch)
else:
# simulate an environment that has no splunk installation
monkeypatch.delenv("SPLUNK_HOME", raising=False)
monkeypatch.delenv("SPLUNK_ETC", raising=False)
monkeypatch.setattr(binding.Context, "get", mock_get)
monkeypatch.setattr(binding.Context, "post", mock_post)
monkeypatch.setattr(HECEventWriter, "_get_hec_config", mock_get_hec_config)

for i in range(4):
ew = create_hec_event_writer(i)

events = []
events.append(
ew.create_event(
data="This is a test data1.",
time=1372274622.493,
index="main",
host="localhost",
source="Splunk",
sourcetype="misc",
stanza="test_scheme://test",
unbroken=True,
done=False,
)
ew = create_hec_event_writer(hec=False)

events = []
events.append(
ew.create_event(
data="This is a test data1.",
time=1372274622.493,
index="main",
host="localhost",
source="Splunk",
sourcetype="misc",
stanza="test_scheme://test",
unbroken=True,
done=False,
)
events.append(
ew.create_event(
data="This is a test data2.",
time=1372274622.493,
index="main",
host="localhost",
source="Splunk",
sourcetype="misc",
stanza="test_scheme://test",
unbroken=True,
done=True,
)
)
events.append(
ew.create_event(
data="This is a test data2.",
time=1372274622.493,
index="main",
host="localhost",
source="Splunk",
sourcetype="misc",
stanza="test_scheme://test",
unbroken=True,
done=True,
)
ew.write_events(events)
)
ew.write_events(events)

# length of this list will indicate how many times post was called
times_post_called = []
Expand All @@ -170,7 +222,7 @@ def mock_post_2(
# test that there are 2 event batches created for write_event and post is called 2 times
# max batch size is 1,000,000. If the max size is exceeded then a new batch is created.
assert len(times_post_called) == 0
ew = create_hec_event_writer(1)

events = []

# each event length will be ~500 characters, 3000 events length will equal ~1,500,000 characters
Expand Down Expand Up @@ -207,35 +259,31 @@ def mock_post_2(
# test that post is called 2 times
assert len(times_post_called) == 2

for i in range(4):
ev = create_hec_event_writer(i)
assert ev._rest_client.scheme == "https"
for i in range(4):
ev = create_hec_event_writer(i, hec=True)
assert ev._rest_client.scheme == "http"


def create_hec_event_writer(i, hec=False):
if i == 1:
return HECEventWriter.create_from_input(
"HECTestInput",
"https://localhost:8089",
common.SESSION_KEY,
global_settings_schema=hec,
)
elif i == 2:
return HECEventWriter.create_from_token_with_session_key(
"https://localhost:8089",
common.SESSION_KEY,
"https://localhost:8090",
"test_token",
global_settings_schema=hec,
)
elif i == 3:
return HECEventWriter.create_from_token(
"https://localhost:8090", "test_token", global_settings_schema=hec
)
else:
return HECEventWriter(
"HECTestInput", common.SESSION_KEY, global_settings_schema=hec
)

@pytest.mark.parametrize(
"create_hec_event_writer, hec, expected_scheme",
[
(create_hec_event_writer__constructor, True, "http"),
(create_hec_event_writer__constructor, False, "https"),
(create_hec_event_writer__create_from_input, True, "http"),
(create_hec_event_writer__create_from_input, False, "https"),
(create_hec_event_writer__create_from_token_with_session_key, True, "http"),
(create_hec_event_writer__create_from_token_with_session_key, False, "https"),
(create_hec_event_writer__create_from_token, True, "http"),
(create_hec_event_writer__create_from_token, False, "https"),
],
)
def test_hec_event_writer_gets_scheme_from_global_settings_if_requested(
monkeypatch, create_hec_event_writer, hec, expected_scheme
):
common.mock_splunkhome(monkeypatch)

def mock_get_hec_config(
self, hec_input_name, session_key, scheme, host, port, **context
):
return "8088", "87de04d1-0823-11e6-9c94-a45e60e"

monkeypatch.setattr(HECEventWriter, "_get_hec_config", mock_get_hec_config)

ev = create_hec_event_writer(hec)
assert ev._rest_client.scheme == expected_scheme

0 comments on commit 4e961b2

Please sign in to comment.