Skip to content

Commit 2bafede

Browse files
Merge pull request #253 from splunk/feature/Add-support-for-uf-file-monitor
feat: Adds support to ingest data via file monitor
2 parents 7829a1a + ea4046a commit 2bafede

20 files changed

+493
-14
lines changed

Dockerfile.uf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
ARG SPLUNK_VERSION=latest
2+
FROM splunk/universalforwarder:$SPLUNK_VERSION
3+
ARG SPLUNK_VERSION=latest
4+
ARG SPLUNK_APP_ID=TA_UNKNOWN
5+
ARG SPLUNK_APP_PACKAGE=package
6+
RUN echo ${SPLUNK_VERSION} $SPLUNK_APP_PACKAGE
7+
COPY ${SPLUNK_APP_PACKAGE} /opt/splunkforwarder/etc/apps/${SPLUNK_APP_ID}

docker-compose.yml

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,27 @@ services:
6363
- SPLUNK_PASSWORD=${SPLUNK_PASSWORD}
6464
- SPLUNK_START_ARGS=--accept-license
6565
- SPLUNK_HEC_TOKEN=${SPLUNK_HEC_TOKEN}
66-
66+
67+
uf:
68+
build:
69+
context: .
70+
dockerfile: Dockerfile.uf
71+
args:
72+
SPLUNK_APP_ID: ${SPLUNK_APP_ID}
73+
SPLUNK_APP_PACKAGE: ${SPLUNK_APP_PACKAGE}
74+
SPLUNK_VERSION: ${SPLUNK_VERSION}
75+
hostname: uf
76+
ports:
77+
- "9997"
78+
- "8089"
79+
links:
80+
- splunk
81+
environment:
82+
- SPLUNK_PASSWORD=Chang3d!
83+
- SPLUNK_START_ARGS=--accept-license
84+
volumes:
85+
- ${CURRENT_DIR}/uf_files:${CURRENT_DIR}/uf_files
86+
6787
volumes:
6888
splunk-sc4s-var:
6989
external: false

docs/api_reference/event_ingestion.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,11 @@ HEC Raw Ingestor
1616
SC4S Event Ingestor
1717
~~~~~~~~~~~~~~~~~~~~
1818
.. automodule:: standard_lib.event_ingestors.sc4s_event_ingestor
19+
:members:
20+
:show-inheritance:
21+
22+
File Monitor Ingestor
23+
~~~~~~~~~~~~~~~~~~~~~
24+
.. automodule:: standard_lib.event_ingestors.file_monitor_ingestor
1925
:members:
2026
:show-inheritance:

docs/release_history.rst

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,18 @@ Release History
88

99
The best way to track the development of pytest-splunk-addon is through `the GitHub Repo <https://github.com/splunk/pytest-splunk-addon/>`_.
1010

11-
1.4.0
11+
1.5.0
12+
"""""""""""""""""""""""""
13+
**Changes:**
14+
15+
* Added support for file monitoring which uses universal forwarder to monitor files and ingest data.
16+
17+
**Known Issues:**
18+
19+
* Event ingestion through SC4S via UDP port
20+
* Fields for modular regular expressions are not extracted in the plugin.
21+
22+
1.4.0 (2021-01-05)
1223
""""""""""""""""""""""""""
1324
**Changes:**
1425

@@ -20,7 +31,7 @@ The best way to track the development of pytest-splunk-addon is through `the Git
2031
* Fields for modular regular expressions are not extracted in the plugin.
2132

2233

23-
1.3.15
34+
1.3.15 (2020-12-16)
2435
""""""""""""""""""""""""""
2536
**Changes:**
2637

docs/sample_generator.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,14 @@ host_type = plugin | event
5252
* If the value is plugin, the plugin will generate host with format of "stanza_{count}" to uniquely identify the events.
5353
* If the value is event, the host field should be provided for a token using "token.<n>.field = host".
5454

55-
input_type = modinput | scripted_input | syslog_tcp | file_monitor | windows_input | default
55+
input_type = modinput | scripted_input | syslog_tcp | file_monitor | windows_input | uf_file_monitor | default
5656
* The input_type used in addon to ingest data of a sourcetype used in stanza.
5757
* The way with which the sample data is ingested in Splunk depends on Splunk. The most similar ingesting approach is used for each input_type to get accurate index-time testing.
58+
* In input_type=uf_file_monitor, universal forwarder will use file monitor to read event and then it will send data to indexer.
5859
* For example, in an Add-on, a sourcetype "alert" is ingested through syslog in live environment, provide input_type=syslog_tcp.
60+
61+
.. warning::
62+
uf_file_monitor input_type will only work with splunk-type=docker.
5963

6064
index = <index>
6165
* The index used to ingest the data.

pytest_splunk_addon/splunk.py

Lines changed: 131 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import logging
1010
import os
11+
import shutil
1112
from time import sleep
1213
import json
1314
import pytest
@@ -244,6 +245,34 @@ def pytest_addoption(parser):
244245
dest="ignore_addon_errors",
245246
help=("Path to file where list of addon related errors are suppressed."),
246247
)
248+
group.addoption(
249+
"--splunk-uf-host",
250+
action="store",
251+
dest="splunk_uf_host",
252+
default="uf",
253+
help="Address of Universal Forwarder Server.",
254+
)
255+
group.addoption(
256+
"--splunk-uf-port",
257+
action="store",
258+
dest="splunk_uf_port",
259+
default="8089",
260+
help="Universal Forwarder Management port. default is 8089.",
261+
)
262+
group.addoption(
263+
"--splunk-uf-user",
264+
action="store",
265+
dest="splunk_uf_user",
266+
default="admin",
267+
help="Universal Forwarder login user.",
268+
)
269+
group.addoption(
270+
"--splunk-uf-password",
271+
action="store",
272+
dest="splunk_uf_password",
273+
default="Chang3d!",
274+
help="Password of the Universal Forwarder user",
275+
)
247276

248277

249278
@pytest.fixture(scope="session")
@@ -321,7 +350,7 @@ def ignore_internal_errors(request):
321350

322351

323352
@pytest.fixture(scope="session")
324-
def splunk(request):
353+
def splunk(request, file_system_prerequisite):
325354
"""
326355
This fixture based on the passed option will provide a real fixture
327356
for external or docker Splunk
@@ -380,6 +409,61 @@ def sc4s(request):
380409

381410
yield sc4s
382411

412+
@pytest.fixture(scope="session")
413+
def uf(request):
414+
"""
415+
This fixture based on the passed option will provide a real fixture
416+
for external or docker uf configuration
417+
418+
Returns:
419+
dict: Details of uf which includes host, port, username and password
420+
"""
421+
if request.config.getoption("splunk_type") == "external":
422+
request.fixturenames.append("uf_external")
423+
uf = request.getfixturevalue("uf_external")
424+
elif request.config.getoption("splunk_type") == "docker":
425+
request.fixturenames.append("uf_docker")
426+
uf = request.getfixturevalue("uf_docker")
427+
else:
428+
raise Exception
429+
uf["uf_username"] = request.config.getoption("splunk_uf_user")
430+
uf["uf_password"] = request.config.getoption("splunk_uf_password")
431+
for _ in range(RESPONSIVE_SPLUNK_TIMEOUT):
432+
if is_responsive_uf(uf):
433+
break
434+
sleep(1)
435+
yield uf
436+
437+
@pytest.fixture(scope="session")
438+
def uf_docker(docker_services, tmp_path_factory, worker_id):
439+
"""
440+
Provides IP of the uf server and management port based on pytest-args(splunk_type)
441+
"""
442+
LOGGER.info("Starting docker_service=uf")
443+
os.environ["CURRENT_DIR"] = os.getcwd()
444+
if worker_id:
445+
# get the temp directory shared by all workers
446+
root_tmp_dir = tmp_path_factory.getbasetemp().parent
447+
fn = root_tmp_dir / "pytest_docker"
448+
with FileLock(str(fn) + ".lock"):
449+
docker_services.start("uf")
450+
uf_info = {
451+
"uf_host": docker_services.docker_ip,
452+
"uf_port": docker_services.port_for("uf", 8089),
453+
}
454+
return uf_info
455+
456+
@pytest.fixture(scope="session")
457+
def uf_external(request):
458+
"""
459+
Provides IP of the uf server and management port based on pytest-args(splunk_type)
460+
"""
461+
uf_info = {
462+
"uf_host": request.config.getoption("splunk_uf_host"),
463+
"uf_port": request.config.getoption("splunk_uf_port"),
464+
}
465+
return uf_info
466+
383467

384468
@pytest.fixture(scope="session")
385469
def splunk_docker(
@@ -544,7 +628,7 @@ def splunk_web_uri(request, splunk):
544628

545629

546630
@pytest.fixture(scope="session")
547-
def splunk_ingest_data(request, splunk_hec_uri, sc4s, splunk_events_cleanup):
631+
def splunk_ingest_data(request, splunk_hec_uri, sc4s, uf, splunk_events_cleanup):
548632
"""
549633
Generates events for the add-on and ingests into Splunk.
550634
The ingestion can be done using the following methods:
@@ -570,6 +654,10 @@ def splunk_ingest_data(request, splunk_hec_uri, sc4s, splunk_events_cleanup):
570654
config_path = request.config.getoption("splunk_data_generator")
571655

572656
ingest_meta_data = {
657+
"uf_host": uf.get("uf_host"),
658+
"uf_port": uf.get("uf_port"),
659+
"uf_username": uf.get("uf_username"),
660+
"uf_password": uf.get("uf_password"),
573661
"session_headers": splunk_hec_uri[0].headers,
574662
"splunk_hec_uri": splunk_hec_uri[1],
575663
"sc4s_host": sc4s[0], # for sc4s
@@ -608,6 +696,47 @@ def splunk_events_cleanup(request, splunk_search_util):
608696
else:
609697
LOGGER.info("Events cleanup was disabled.")
610698

699+
@pytest.fixture(scope="session")
700+
def file_system_prerequisite():
701+
"""
702+
File system prerequisite before running tests.
703+
Creating uf_files directory to write tokenized events for uf_file_monitor input.
704+
"""
705+
UF_FILE_MONTOR_DIR = "uf_files"
706+
monitor_dir = os.path.join(os.getcwd(), UF_FILE_MONTOR_DIR)
707+
if os.path.exists(monitor_dir):
708+
shutil.rmtree(UF_FILE_MONTOR_DIR, ignore_errors=True)
709+
os.mkdir(monitor_dir)
710+
711+
def is_responsive_uf(uf):
712+
"""
713+
Verify if the management port of Universal Forwarder is responsive or not
714+
715+
Args:
716+
uf (dict): details of the Universal Forwarder instance
717+
718+
Returns:
719+
bool: True if Universal Forwarder is responsive. False otherwise
720+
"""
721+
try:
722+
LOGGER.info(
723+
"Trying to connect Universal Forwarder instance... splunk=%s", json.dumps(uf),
724+
)
725+
client.connect(
726+
username=uf["uf_username"],
727+
password=uf["uf_password"],
728+
host=uf["uf_host"],
729+
port=uf["uf_port"],
730+
)
731+
LOGGER.info("Connected to Universal Forwarder instance.")
732+
733+
return True
734+
except Exception as e:
735+
LOGGER.warning(
736+
"Could not connect to Universal Forwarder Instance. Will try again. exception=%s", str(e),
737+
)
738+
return False
739+
611740
def is_responsive_splunk(splunk):
612741
"""
613742
Verify if the management port of Splunk is responsive or not

pytest_splunk_addon/standard_lib/event_ingestors/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
from .hec_metric_ingestor import HECMetricEventIngestor
33
from .hec_raw_ingestor import HECRawEventIngestor
44
from .sc4s_event_ingestor import SC4SEventIngestor
5+
from .file_monitor_ingestor import FileMonitorEventIngestor
56
from .ingestor_helper import IngestorHelper

0 commit comments

Comments
 (0)