Skip to content

Commit e956b6e

Browse files
chore: merge develop into main (#424)
2 parents d46cd21 + 936572f commit e956b6e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1736
-174
lines changed

.github/workflows/build-test-release.yml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,20 @@ jobs:
108108
export SPLUNK_VERSION=${{ matrix.splunk.version }}
109109
export SPLUNK_BUILD=${{ matrix.splunk.build }}
110110
export SPLUNK_SLUG=$SPLUNK_VERSION-$SPLUNK_BUILD
111-
export SPLUNK_ARCH=x86_64
112-
export SPLUNK_LINUX_FILENAME=splunk-${SPLUNK_VERSION}-${SPLUNK_BUILD}-Linux-${SPLUNK_ARCH}.tgz
111+
export SPLUNK_ARCH=amd64
112+
export SPLUNK_LINUX_FILENAME=splunk-${SPLUNK_VERSION}-${SPLUNK_BUILD}-linux-${SPLUNK_ARCH}.tgz
113+
114+
# Before 9.4, the filename was splunk-<version>-<build>-Linux-x86_64.tgz
115+
if [[ $(echo $SPLUNK_VERSION | cut -d. -f1) -le 8 ]] || \
116+
[[ $SPLUNK_VERSION == 9.0.* ]] || \
117+
[[ $SPLUNK_VERSION == 9.1.* ]] || \
118+
[[ $SPLUNK_VERSION == 9.2.* ]] || \
119+
[[ $SPLUNK_VERSION == 9.3.* ]]
120+
then
121+
export SPLUNK_ARCH=x86_64
122+
export SPLUNK_LINUX_FILENAME=splunk-${SPLUNK_VERSION}-${SPLUNK_BUILD}-Linux-${SPLUNK_ARCH}.tgz
123+
fi
124+
113125
export SPLUNK_BUILD_URL=https://download.splunk.com/products/${SPLUNK_PRODUCT}/releases/${SPLUNK_VERSION}/linux/${SPLUNK_LINUX_FILENAME}
114126
echo "$SPLUNK_BUILD_URL"
115127
export SPLUNK_HOME=/opt/splunk

poetry.lock

Lines changed: 116 additions & 129 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright 2024 Splunk Inc.
2+
# Copyright 2025 Splunk Inc.
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
55
# you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
1616

1717
[tool.poetry]
1818
name = "solnlib"
19-
version = "6.0.1"
19+
version = "6.1.0-beta.1"
2020
description = "The Splunk Software Development Kit for Splunk Solutions"
2121
authors = ["Splunk <addonfactory@splunk.com>"]
2222
license = "Apache-2.0"

solnlib/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright 2024 Splunk Inc.
2+
# Copyright 2025 Splunk Inc.
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
55
# you may not use this file except in compliance with the License.
@@ -56,4 +56,4 @@
5656
"utils",
5757
]
5858

59-
__version__ = "6.0.1"
59+
__version__ = "6.1.0-beta.1"

solnlib/_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright 2024 Splunk Inc.
2+
# Copyright 2025 Splunk Inc.
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
55
# you may not use this file except in compliance with the License.

solnlib/acl.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright 2024 Splunk Inc.
2+
# Copyright 2025 Splunk Inc.
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
55
# you may not use this file except in compliance with the License.

solnlib/alerts_rest_client.py

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
#
2+
# Copyright 2025 Splunk Inc.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
import json
17+
from enum import Enum
18+
from typing import Tuple, Union, Optional
19+
20+
from solnlib import splunk_rest_client as rest_client
21+
22+
23+
class AlertType(Enum):
24+
CUSTOM = "custom"
25+
NUMBER_OF_EVENTS = "number of events"
26+
NUMBER_OF_HOSTS = "number of hosts"
27+
NUMBER_OF_SOURCES = "number of sources"
28+
29+
30+
class AlertSeverity(Enum):
31+
DEBUG = 1
32+
INFO = 2
33+
WARN = 3
34+
ERROR = 4
35+
SEVERE = 5
36+
FATAL = 6
37+
38+
39+
class AlertComparator(Enum):
40+
GREATER_THAN = "greater than"
41+
LESS_THAN = "less than"
42+
EQUAL_TO = "equal to"
43+
RISES_BY = "rises by"
44+
DROPS_BY = "drops by"
45+
RISES_BY_PERC = "rises by perc"
46+
DROPS_BY_PERC = "drops by perc"
47+
48+
49+
class AlertsRestClient:
50+
"""REST client for handling alerts."""
51+
52+
ENDPOINT = "/servicesNS/{owner}/{app}/saved/searches"
53+
headers = [("Content-Type", "application/json")]
54+
55+
def __init__(
56+
self,
57+
session_key: str,
58+
app: str,
59+
owner: str = "nobody",
60+
**context: dict,
61+
):
62+
"""Initializes AlertsRestClient.
63+
64+
Arguments:
65+
session_key: Splunk access token.
66+
app: App name of namespace.
67+
context: Other configurations for Splunk rest client.
68+
"""
69+
self.session_key = session_key
70+
self.app = app
71+
72+
self._rest_client = rest_client.SplunkRestClient(
73+
self.session_key,
74+
app=self.app,
75+
owner=owner,
76+
**context,
77+
)
78+
79+
self.endpoint = self.ENDPOINT.format(owner=owner, app=app)
80+
81+
def create_search_alert(
82+
self,
83+
name: str,
84+
search: str,
85+
*,
86+
disabled: bool = True,
87+
description: str = "",
88+
alert_type: AlertType = AlertType.NUMBER_OF_EVENTS,
89+
alert_condition: str = "",
90+
alert_comparator: AlertComparator = AlertComparator.GREATER_THAN,
91+
alert_threshold: Union[int, float, str] = 0,
92+
time_window: Tuple[str, str] = ("-15m", "now"),
93+
alert_severity: AlertSeverity = AlertSeverity.WARN,
94+
cron_schedule: str = "* * * * *",
95+
expires: Union[int, str] = "24h",
96+
**kwargs,
97+
):
98+
"""Creates a search alert in Splunk.
99+
100+
Arguments:
101+
name: Name of the alert.
102+
search: Search query for the alert.
103+
disabled: Whether the alert is disabled. Default is True.
104+
description: Description of the alert.
105+
alert_type: Type of the alert (see AlertType). If it equals to CUSTOM, Splunk executes a check in
106+
alert_condition. Otherwise, alert_comparator and alert_threshold are used.
107+
alert_condition: Condition for the alert.
108+
alert_comparator: Comparator for the alert. Default is GREATER_THAN.
109+
alert_threshold: Threshold for the alert. Default is 0.
110+
time_window: Time window for the alert. Tuple of earliest and latest time. Default is ("-15m", "now").
111+
alert_severity: Severity level of the alert. Default is WARN.
112+
cron_schedule: Cron schedule for the alert. Default is "* * * * *".
113+
expires: Expiration time for the alert (i.e. how long you can access the result of triggered alert).
114+
Default is "24h".
115+
kwargs: Additional parameters for the alert. See Splunk documentation for more details.
116+
"""
117+
params = {
118+
"output_mode": "json",
119+
"name": name,
120+
"search": search,
121+
"description": description,
122+
"alert_type": alert_type.value,
123+
"alert_condition": alert_condition,
124+
"alert_comparator": alert_comparator.value,
125+
"alert_threshold": alert_threshold,
126+
"alert.severity": str(alert_severity.value),
127+
"is_scheduled": "1",
128+
"cron_schedule": cron_schedule,
129+
"dispatch.earliest_time": time_window[0],
130+
"dispatch.latest_time": time_window[1],
131+
"alert.digest_mode": "1",
132+
"alert.expires": str(expires),
133+
"disabled": "1" if disabled else "0",
134+
"realtime_schedule": "1",
135+
}
136+
137+
params.update(kwargs)
138+
139+
self._rest_client.post(self.endpoint, body=params, headers=self.headers)
140+
141+
def delete_search_alert(self, name: str):
142+
"""Deletes a search alert in Splunk.
143+
144+
Arguments:
145+
name: Name of the alert to delete.
146+
"""
147+
self._rest_client.delete(f"{self.endpoint}/{name}")
148+
149+
def get_search_alert(self, name: str):
150+
"""Retrieves a specific search alert from Splunk.
151+
152+
Arguments:
153+
name: Name of the alert to retrieve.
154+
155+
Returns:
156+
A dictionary containing the alert details.
157+
"""
158+
response = (
159+
self._rest_client.get(f"{self.endpoint}/{name}", output_mode="json")
160+
.body.read()
161+
.decode("utf-8")
162+
)
163+
164+
return json.loads(response)
165+
166+
def get_all_search_alerts(self):
167+
"""Retrieves all search alerts from Splunk.
168+
169+
Returns:
170+
A dictionary containing all search alerts.
171+
"""
172+
response = (
173+
self._rest_client.get(self.endpoint, output_mode="json")
174+
.body.read()
175+
.decode("utf-8")
176+
)
177+
178+
return json.loads(response)
179+
180+
def update_search_alert(
181+
self,
182+
name: str,
183+
*,
184+
search: Optional[str] = None,
185+
disabled: Optional[bool] = None,
186+
description: Optional[str] = None,
187+
alert_type: Optional[AlertType] = None,
188+
alert_condition: Optional[str] = None,
189+
alert_comparator: Optional[AlertComparator] = None,
190+
alert_threshold: Optional[Union[int, float, str]] = None,
191+
time_window: Optional[Tuple[str, str]] = None,
192+
alert_severity: Optional[AlertSeverity] = None,
193+
cron_schedule: Optional[str] = None,
194+
expires: Optional[Union[int, str]] = None,
195+
**kwargs,
196+
):
197+
"""Updates a search alert in Splunk.
198+
199+
Arguments:
200+
name: Name of the alert to update.
201+
search: Search query for the alert.
202+
disabled: Whether the alert is disabled.
203+
description: Description of the alert.
204+
alert_type: Type of the alert (see AlertType). If it equals to CUSTOM, Splunk executes a check in
205+
alert_condition. Otherwise, alert_comparator and alert_threshold are used.
206+
alert_condition: Condition for the alert.
207+
alert_comparator: Comparator for the alert.
208+
alert_threshold: Threshold for the alert.
209+
time_window: Time window for the alert. Tuple of earliest and latest time.
210+
alert_severity: Severity level of the alert.
211+
cron_schedule: Cron schedule for the alert.
212+
expires: Expiration time for the alert.
213+
kwargs: Additional parameters for the alert. See Splunk documentation for more details.
214+
"""
215+
params = {
216+
"output_mode": "json",
217+
}
218+
219+
if search:
220+
params["search"] = search
221+
222+
if disabled is not None:
223+
params["disabled"] = "1" if disabled else "0"
224+
225+
if description:
226+
params["description"] = description
227+
228+
if alert_type:
229+
params["alert_type"] = alert_type.value
230+
231+
if alert_condition:
232+
params["alert_condition"] = alert_condition
233+
234+
if alert_comparator:
235+
params["alert_comparator"] = alert_comparator.value
236+
237+
if alert_threshold:
238+
params["alert_threshold"] = str(alert_threshold)
239+
240+
if time_window:
241+
params["dispatch.earliest_time"] = time_window[0]
242+
params["dispatch.latest_time"] = time_window[1]
243+
244+
if alert_severity:
245+
params["alert.severity"] = str(alert_severity.value)
246+
247+
if cron_schedule:
248+
params["is_scheduled"] = "1"
249+
params["cron_schedule"] = cron_schedule
250+
251+
if expires:
252+
params["alert.expires"] = str(expires)
253+
254+
params.update(kwargs)
255+
256+
self._rest_client.post(
257+
f"{self.endpoint}/{name}", body=params, headers=self.headers
258+
)

solnlib/bulletin_rest_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright 2024 Splunk Inc.
2+
# Copyright 2025 Splunk Inc.
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
55
# you may not use this file except in compliance with the License.

0 commit comments

Comments
 (0)