Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for macros #516

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open

Add support for macros #516

wants to merge 3 commits into from

Conversation

Synse
Copy link

@Synse Synse commented Feb 13, 2023

This adds Service.macros for creating, retrieving, updating, and deleting macros.

Currently macros can be accessed via Configurations / ConfigurationFile but creating a proper Macros(Collection) and Macro(Entity) makes them much easier to work with.

Almost all of the code, including tests, is copied and modified from the existing code for saved searches (Service.saved_searches) so you can interact with macros in the same manner.

Tests

I added a few tests modeled after the existing ones for saved searches. The naming for macros with arguments means that test_create_with_args should probably move to another class (self.macro created by setUp is not used) but I didn't want to get carried away until I know there's a desire to merge this (or not).

I also had to remove the app parameter from the self.macro.acl_update call because it was failing with Argument "app" is not supported by this handler. It's not immediately clear to me why this is working for saved searches but not for macros.

$ pytest tests/test_macro.py --verbose
========================================================= test session starts =========================================================
platform linux -- Python 3.10.4, pytest-7.2.1, pluggy-1.0.0 -- /usr/local/python/3.10.4/bin/python
cachedir: .pytest_cache
rootdir: /workspaces/splunk-sdk-python, configfile: pytest.ini
plugins: anyio-3.6.2
collected 10 items                                                                                                                    

tests/test_macro.py::TestMacro::test_acl PASSED                                                                                 [ 10%]
tests/test_macro.py::TestMacro::test_acl_fails_without_owner PASSED                                                             [ 20%]
tests/test_macro.py::TestMacro::test_acl_fails_without_sharing PASSED                                                           [ 30%]
tests/test_macro.py::TestMacro::test_cannot_update_name PASSED                                                                  [ 40%]
tests/test_macro.py::TestMacro::test_create PASSED                                                                              [ 50%]
tests/test_macro.py::TestMacro::test_create_with_args PASSED                                                                    [ 60%]
tests/test_macro.py::TestMacro::test_delete PASSED                                                                              [ 70%]
tests/test_macro.py::TestMacro::test_name_collision PASSED                                                                      [ 80%]
tests/test_macro.py::TestMacro::test_no_equality PASSED                                                                         [ 90%]
tests/test_macro.py::TestMacro::test_update PASSED                                                                              [100%]

========================================================= 10 passed in 1.00s ==========================================================

Usage

As mentioned above, the usage is almost identical to Service.saved_searches for saved searches today.

List macros

>>> from splunklib.client import connect
>>> sc = connect(host='localhost', port=8089, username='admin', password='changed!')
>>> sc.macros
<splunklib.client.Macros object at 0x7f422daa5ba0>
>>> sc.macros.list()
[<splunklib.client.Macro object at 0x7f422d842050>, <splunklib.client.Macro object at 0x7f422d841f90>, <splunklib.client.Macro object at 0x7f422d841fc0>, <splunklib.client.Macro object at 0x7f422d841e40>, <splunklib.client.Macro object at 0x7f422d8424d0>, <splunklib.client.Macro object at 0x7f422d841f30>, <splunklib.client.Macro object at 0x7f422d8be4d0>, <splunklib.client.Macro object at 0x7f422d8be530>]
>>> [m.name for m in sc.macros.list()]
['audit_rexsearch', 'audit_searchlocal', 'audit_searchlocal(1)', 'comment(1)', 'histperc(3)', 'histperc(4)', 'set_local_host', 'truncate_search']
>>> 

Create a macro

>>> sc.macros.create(name='new_macro', definition='| eval foo="bar"')
<splunklib.client.Macro object at 0x7f422daa5ba0>
>>> sc.macros.list(search='new_macro')[0].content
{'definition': '| eval foo="bar"', 'disabled': '0', 'eai:appName': 'search', 'eai:userName': 'admin'}
>>> 

Enable/disable a macro

>>> macro = sc.macros.list(search='new_macro')[0]
>>> macro
<splunklib.client.Macro object at 0x7f422d841de0>
>>> macro.disabled
'0'
>>> macro.disable()
<splunklib.client.Macro object at 0x7f422d841de0>
>>> sc.macros.list(search='new_macro')[0].disabled
'1'
>>> macro.enable()
<splunklib.client.Macro object at 0x7f422d841de0>
>>> sc.macros.list(search='new_macro')[0].disabled
'0'

Update a macro

>>> macro = sc.macros.list(search='new_macro')[0]
>>> macro.content
{'definition': '| eval foo="bar"', 'disabled': '0', 'eai:appName': 'search', 'eai:userName': 'admin'}
>>> macro.update(definition='| eval updated="true"')
<splunklib.client.Macro object at 0x7f422daa5ba0>
>>> sc.macros.list(search='new_macro')[0].content
{'definition': '| eval updated="true"', 'disabled': '0', 'eai:appName': 'search', 'eai:userName': 'admin'}

Delete a macro

>>> macro = sc.macros.list(search='new_macro')[0]
>>> macro
<splunklib.client.Macro object at 0x7f422d841270>
>>> macro.delete()
{'status': 200, 'reason': 'OK', 'headers': [('Date', 'Mon, 13 Feb 2023 20:57:16 GMT'), ('Expires', 'Thu, 26 Oct 1978 00:00:00 GMT'), ('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0'), ('Content-Type', 'text/xml; charset=UTF-8'), ('X-Content-Type-Options', 'nosniff'), ('Content-Length', '1944'), ('Vary', 'Cookie, Authorization'), ('Connection', 'Close'), ('Set-Cookie', 'splunkd_8089=REDACTED; Path=/; Secure; HttpOnly; Max-Age=3600; Expires=Mon, 13 Feb 2023 21:57:16 GMT'), ('X-Frame-Options', 'SAMEORIGIN'), ('Server', 'Splunkd')], 'body': <splunklib.binding.ResponseReader object at 0x7f422d841cc0>}
>>> sc.macros.list(search='new_macro')
[]

@Synse
Copy link
Author

Synse commented Feb 13, 2023

It is also worth noting that the name/argument validation (e.g., Number of arguments provided (2) does not match with the number implied by the macro name (0)) appears to be occurring in the web UI so its possible to create macros that violate that naming convention.

I didn't add validation for that here as it should really be handled by the API and not in each SDK. That is, this is an issue with the API allowing creation of macros that don't conform to the expected naming conventions, not an SDK issue.

>>> sc = connect(host='localhost', port=8089, username='admin', password='changed!')
>>> sc.macros.create(name='no_args', definition='| eval foo="bar"', args='one, two')
<splunklib.client.Macro object at 0x7f8aac282860>
>>> sc.macros.list(search='no_args')[0].content
{'args': 'one, two', 'definition': '| eval foo="bar"', 'disabled': '0', 'eai:appName': 'search', 'eai:userName': 'admin'}

@Synse
Copy link
Author

Synse commented Mar 21, 2024

I've brought this PR up to date with develop and ensured tests still pass for the 2.0.0 release:

Screenshot 2024-03-21 at 11 44 41 AM

Tagging a few recent contributors to get some movement on this PR (it's been sitting over a year now).

@ashah-splunk, @PKing70, @maszyk99, @ichaer, or @akaila-splunk is there anything y'all can do to help move this along? 🙇

@jonod8698
Copy link

+1 We need this for our use case!

@pmeyerson
Copy link

+1 would be helpful!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants