Skip to content

Commit 06f8789

Browse files
committed
Change macros endpoint from configs/conf-macros to data/macros
1 parent f83af55 commit 06f8789

File tree

3 files changed

+125
-3
lines changed

3 files changed

+125
-3
lines changed

splunklib/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@
108108
PATH_JOBS = "search/jobs/"
109109
PATH_JOBS_V2 = "search/v2/jobs/"
110110
PATH_LOGGER = "/services/server/logger/"
111-
PATH_MACROS = "configs/conf-macros/"
111+
PATH_MACROS = "data/macros/"
112112
PATH_MESSAGES = "messages/"
113113
PATH_MODULAR_INPUTS = "data/modular-inputs"
114114
PATH_ROLES = "authorization/roles/"

test-reports/junit-py39.xml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?xml version="1.0" encoding="utf-8"?><testsuites name="pytest tests"><testsuite name="pytest" errors="0" failures="1" skipped="0" tests="1" time="0.377" timestamp="2025-09-03T12:33:38.683850+02:00" hostname="MPOLIWCZ-M-3NJ6"><testcase classname="tests.integration.test_macro.TestPrivilegesWithNamespace" name="test_create_macro_no_admin" time="0.176"><failure message="splunklib.binding.HTTPError: HTTP 409 Conflict -- An object with name=SDKTestMacro already exists">self = &lt;test_macro.TestPrivilegesWithNamespace testMethod=test_create_macro_no_admin&gt;
2+
3+
def test_create_macro_no_admin(self):
4+
&gt; self.service.macros.create(
5+
self.macro_name, 'eval test="123"', namespace=self.namespace
6+
)
7+
8+
tests/integration/test_macro.py:363:
9+
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
10+
splunklib/client.py:3644: in create
11+
return Collection.create(self, name, definition=definition, **kwargs)
12+
splunklib/client.py:1755: in create
13+
response = self.post(name=name, **params)
14+
splunklib/client.py:981: in post
15+
return self.service.post(path, owner=owner, app=app, sharing=sharing, **query)
16+
splunklib/binding.py:335: in wrapper
17+
return request_fun(self, *args, **kwargs)
18+
splunklib/binding.py:90: in new_f
19+
val = f(*args, **kwargs)
20+
splunklib/binding.py:856: in post
21+
response = self.http.post(path, all_headers, **query)
22+
splunklib/binding.py:1382: in post
23+
return self.request(url, message)
24+
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
25+
26+
self = &lt;splunklib.binding.HttpLib object at 0x101d280a0&gt;, url = UrlEncoded('https://localhost:8089/servicesNS/nobody/launcher/data/macros/')
27+
message = {'body': b'name=SDKTestMacro&amp;definition=eval+test%3D%22123%22', 'headers': [('Cookie', 'splunkd_8089=KgRkAxruIHVKU^LL_...K1LOsT3WAmmgC8xULxlGmQ0NBZhpLbR9G7Qo1H19WtacHgoD6HyKm7ENwQ227bVuFbfr5C5HlnbItLtzHtJJC9YSLhFGYi8bC')], 'method': 'POST'}
28+
kwargs = {}
29+
response = {'status': 409, 'reason': 'Conflict', 'headers': [('Date', 'Wed, 03 Sep 2025 10:33:38 GMT'), ('Expires', 'Thu, 26 Oct ...rame-Options', 'SAMEORIGIN'), ('Server', 'Splunkd')], 'body': &lt;splunklib.binding.ResponseReader object at 0x101ee16d0&gt;}
30+
31+
def request(self, url, message, **kwargs):
32+
"""Issues an HTTP request to a URL.
33+
34+
:param url: The URL.
35+
:type url: ``string``
36+
:param message: A dictionary with the format as described in
37+
:class:`HttpLib`.
38+
:type message: ``dict``
39+
:param kwargs: Additional keyword arguments (optional). These arguments
40+
are passed unchanged to the handler.
41+
:type kwargs: ``dict``
42+
:returns: A dictionary describing the response (see :class:`HttpLib` for
43+
its structure).
44+
:rtype: ``dict``
45+
"""
46+
while True:
47+
try:
48+
response = self.handler(url, message, **kwargs)
49+
break
50+
except Exception:
51+
if self.retries &lt;= 0:
52+
raise
53+
else:
54+
time.sleep(self.retryDelay)
55+
self.retries -= 1
56+
response = record(response)
57+
if 400 &lt;= response.status:
58+
&gt; raise HTTPError(response)
59+
E splunklib.binding.HTTPError: HTTP 409 Conflict -- An object with name=SDKTestMacro already exists
60+
61+
splunklib/binding.py:1411: HTTPError</failure></testcase></testsuite></testsuites>

tests/integration/test_macro.py

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# under the License.
1616

1717
from __future__ import absolute_import
18-
from splunklib.binding import HTTPError
18+
from splunklib.binding import HTTPError, namespace
1919
from tests import testlib
2020
import logging
2121

@@ -264,7 +264,7 @@ def query():
264264
self.assertRaisesRegex(HTTPError, "value must be smaller that value2", query)
265265

266266

267-
# This test makes sure that the endpoint we use for macros (configs/conf-macros)
267+
# This test makes sure that the endpoint we use for macros (data/macros/)
268268
# does not require admin privileges and can be used by normal users.
269269
class TestPrivileges(testlib.SDKTestCase):
270270
macro_name = "SDKTestMacro"
@@ -318,6 +318,67 @@ def test_create_macro_no_admin(self):
318318
self.assertEqual(out[0]["test"], "123")
319319

320320

321+
# This test makes sure that the endpoint we use for macros (data/macros/)
322+
# does not require admin privileges and can be used by normal users.
323+
class TestPrivilegesWithNamespace(testlib.SDKTestCase):
324+
macro_name = "SDKTestMacro"
325+
username = "SDKTestMacroUser".lower()
326+
password = "SDKTestMacroUserPassword!"
327+
328+
# TODO: Would be nice to create app on-demand here and control the
329+
# permissions, so that we are not dependent on default settings.
330+
namespace = namespace(owner="nobody", app="launcher")
331+
332+
def setUp(self):
333+
testlib.SDKTestCase.setUp(self)
334+
self.cleanUsers()
335+
336+
self.service.users.create(
337+
username=self.username, password=self.password, roles=["power"]
338+
)
339+
340+
self.service.logout()
341+
kwargs = self.opts.kwargs.copy()
342+
kwargs["username"] = self.username
343+
kwargs["password"] = self.password
344+
self.service = client.connect(**kwargs)
345+
346+
self.cleanMacros()
347+
348+
def tearDown(self):
349+
testlib.SDKTestCase.tearDown(self)
350+
self.cleanMacros()
351+
self.service = client.connect(**self.opts.kwargs)
352+
self.cleanUsers()
353+
354+
def cleanUsers(self):
355+
for user in self.service.users:
356+
if user.name == self.username:
357+
self.service.users.delete(self.username)
358+
359+
def cleanMacros(self):
360+
for macro in self.service.macros:
361+
if macro.name == self.macro_name:
362+
self.service.macros.delete(self.macro_name, namespace=self.namespace)
363+
364+
def test_create_macro_no_admin(self):
365+
self.service.macros.create(
366+
self.macro_name, 'eval test="123"', namespace=self.namespace
367+
)
368+
369+
stream = self.service.jobs.oneshot(
370+
f"| makeresults count=1 | `{self.macro_name}`",
371+
output_mode="json",
372+
namespace=self.namespace,
373+
)
374+
375+
result = results.JSONResultsReader(stream)
376+
out = list(result)
377+
378+
self.assertTrue(len(out) == 1)
379+
self.assertEqual(out[0]["test"], "123")
380+
381+
321382
if __name__ == "__main__":
322383
try:
323384
import unittest2 as unittest

0 commit comments

Comments
 (0)