Skip to content

Commit d0ef02c

Browse files
committed
RSPEED-2326: feat(config): add SplunkConfiguration model and fields
Add SplunkConfiguration Pydantic model for Splunk HEC settings: - enabled: toggle for Splunk integration - url: HEC endpoint URL - token_path: path to HEC auth token file - index: target Splunk index - source: event source identifier (default: lightspeed-stack) - timeout: HTTP timeout in seconds (default: 5) - verify_ssl: SSL verification toggle (default: True) Add splunk and deployment_environment fields to Configuration class. Signed-off-by: Major Hayden <major@redhat.com>
1 parent e9f0c09 commit d0ef02c

2 files changed

Lines changed: 201 additions & 0 deletions

File tree

src/models/config.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,87 @@ def check_llama_stack_model(self) -> Self:
612612
return self
613613

614614

615+
class SplunkConfiguration(ConfigurationBase):
616+
"""Splunk HEC (HTTP Event Collector) configuration.
617+
618+
Splunk HEC allows sending events directly to Splunk over HTTP/HTTPS.
619+
This configuration is used to send telemetry events for inference
620+
requests to the corporate Splunk deployment.
621+
622+
Useful resources:
623+
624+
- [Splunk HEC Docs](https://docs.splunk.com/Documentation/SplunkCloud)
625+
- [About HEC](https://docs.splunk.com/Documentation/Splunk/latest/Data)
626+
"""
627+
628+
enabled: bool = Field(
629+
False,
630+
title="Enabled",
631+
description="Enable or disable Splunk HEC integration.",
632+
)
633+
634+
url: Optional[str] = Field(
635+
None,
636+
title="HEC URL",
637+
description="Splunk HEC endpoint URL.",
638+
)
639+
640+
token_path: Optional[FilePath] = Field(
641+
None,
642+
title="Token path",
643+
description="Path to file containing the Splunk HEC authentication token.",
644+
)
645+
646+
index: Optional[str] = Field(
647+
None,
648+
title="Index",
649+
description="Target Splunk index for events.",
650+
)
651+
652+
source: str = Field(
653+
"lightspeed-stack",
654+
title="Source",
655+
description="Event source identifier.",
656+
)
657+
658+
timeout: PositiveInt = Field(
659+
5,
660+
title="Timeout",
661+
description="HTTP timeout in seconds for HEC requests.",
662+
)
663+
664+
verify_ssl: bool = Field(
665+
True,
666+
title="Verify SSL",
667+
description="Whether to verify SSL certificates for HEC endpoint.",
668+
)
669+
670+
@model_validator(mode="after")
671+
def check_splunk_configuration(self) -> Self:
672+
"""Validate that required fields are set when Splunk is enabled.
673+
674+
Returns:
675+
Self: The validated configuration instance.
676+
677+
Raises:
678+
ValueError: If enabled is True but required fields are missing.
679+
"""
680+
if self.enabled:
681+
missing_fields = []
682+
if not self.url:
683+
missing_fields.append("url")
684+
if not self.token_path:
685+
missing_fields.append("token_path")
686+
if not self.index:
687+
missing_fields.append("index")
688+
if missing_fields:
689+
raise ValueError(
690+
f"Splunk is enabled but required fields are missing: "
691+
f"{', '.join(missing_fields)}"
692+
)
693+
return self
694+
695+
615696
class UserDataCollection(ConfigurationBase):
616697
"""User data collection configuration."""
617698

@@ -1659,6 +1740,19 @@ class Configuration(ConfigurationBase):
16591740
)
16601741
azure_entra_id: Optional[AzureEntraIdConfiguration] = None
16611742

1743+
splunk: Optional[SplunkConfiguration] = Field(
1744+
default=None,
1745+
title="Splunk configuration",
1746+
description="Splunk HEC configuration for sending telemetry events.",
1747+
)
1748+
1749+
deployment_environment: str = Field(
1750+
"development",
1751+
title="Deployment environment",
1752+
description="Deployment environment name (e.g., 'development', 'staging', 'production'). "
1753+
"Used in telemetry events.",
1754+
)
1755+
16621756
@model_validator(mode="after")
16631757
def validate_mcp_auth_headers(self) -> Self:
16641758
"""
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
"""Unit tests for SplunkConfiguration model."""
2+
3+
from pathlib import Path
4+
5+
import pytest
6+
7+
from models.config import SplunkConfiguration
8+
9+
10+
@pytest.fixture(name="token_file")
11+
def token_file_fixture(tmp_path: Path) -> Path:
12+
"""Create a temporary token file for testing."""
13+
token_file = tmp_path / "token"
14+
token_file.write_text("test-token")
15+
return token_file
16+
17+
18+
def test_default_values() -> None:
19+
"""Test default SplunkConfiguration has expected values."""
20+
cfg = SplunkConfiguration()
21+
assert cfg.enabled is False
22+
assert cfg.url is None
23+
assert cfg.token_path is None
24+
assert cfg.index is None
25+
assert cfg.source == "lightspeed-stack"
26+
assert cfg.timeout == 5
27+
assert cfg.verify_ssl is True
28+
29+
30+
def test_disabled_skips_validation() -> None:
31+
"""Test that disabled Splunk config doesn't require other fields."""
32+
cfg = SplunkConfiguration(enabled=False)
33+
assert cfg.enabled is False
34+
assert cfg.url is None
35+
36+
37+
@pytest.mark.parametrize(
38+
("url", "has_token", "index", "expected_missing"),
39+
[
40+
(None, False, None, r"url.*token_path.*index"),
41+
("https://splunk:8088", False, None, r"token_path.*index"),
42+
("https://splunk:8088", False, "idx", r"token_path"),
43+
("https://splunk:8088", True, None, r"index"),
44+
(None, True, "idx", r"url"),
45+
],
46+
ids=[
47+
"all_missing",
48+
"url_present_only",
49+
"url_and_index_present",
50+
"url_and_token_present",
51+
"token_and_index_present",
52+
],
53+
)
54+
def test_enabled_missing_required_fields(
55+
token_file: Path,
56+
url: str | None,
57+
has_token: bool,
58+
index: str | None,
59+
expected_missing: str,
60+
) -> None:
61+
"""Test that enabled Splunk config validates required fields."""
62+
with pytest.raises(ValueError, match=expected_missing):
63+
SplunkConfiguration(
64+
enabled=True,
65+
url=url,
66+
token_path=token_file if has_token else None,
67+
index=index,
68+
)
69+
70+
71+
def test_valid_enabled_configuration(token_file: Path) -> None:
72+
"""Test valid enabled Splunk configuration passes validation."""
73+
cfg = SplunkConfiguration(
74+
enabled=True,
75+
url="https://splunk.example.com:8088",
76+
token_path=token_file,
77+
index="rhel_lightspeed",
78+
source="my-service",
79+
timeout=10,
80+
verify_ssl=False,
81+
)
82+
83+
assert cfg.enabled is True
84+
assert cfg.url == "https://splunk.example.com:8088"
85+
assert cfg.token_path == token_file
86+
assert cfg.index == "rhel_lightspeed"
87+
assert cfg.source == "my-service"
88+
assert cfg.timeout == 10
89+
assert cfg.verify_ssl is False
90+
91+
92+
def test_custom_source() -> None:
93+
"""Test custom source value is preserved."""
94+
cfg = SplunkConfiguration(enabled=False, source="custom-source")
95+
assert cfg.source == "custom-source"
96+
97+
98+
def test_custom_timeout() -> None:
99+
"""Test custom timeout value is preserved."""
100+
cfg = SplunkConfiguration(enabled=False, timeout=30)
101+
assert cfg.timeout == 30
102+
103+
104+
def test_verify_ssl_disabled() -> None:
105+
"""Test verify_ssl can be disabled."""
106+
cfg = SplunkConfiguration(enabled=False, verify_ssl=False)
107+
assert cfg.verify_ssl is False

0 commit comments

Comments
 (0)