Skip to content

Commit e441358

Browse files
authored
Merge pull request #511 from splunk/release/1.7.3
Release/1.7.3
2 parents e323dd8 + ba791fb commit e441358

15 files changed

+279
-69
lines changed

.env

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ scheme=https
1111
# Your version of Splunk (default: 6.2)
1212
version=9.0
1313
# Bearer token for authentication
14-
#bearerToken="<Bearer-token>"
14+
#splunkToken="<Bearer-token>"
1515
# Session key for authentication
16-
#sessionKey="<Session-Key>"
16+
#token="<Session-Key>"

.github/dependabot.yaml

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "github-actions"
4+
directory: "/"
5+
target-branch: "master"
6+
schedule:
7+
interval: "weekly"

.github/workflows/release.yml

+2-3
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,11 @@ jobs:
2929
run: |
3030
rm -rf ./docs/_build
3131
tox -e docs
32-
cd ./docs/_build/html && zip -r ../docs_html.zip . -x ".*" -x "__MACOSX"
3332
- name : Docs Upload
3433
uses: actions/upload-artifact@v3
3534
with:
36-
name: apidocs
37-
path: docs/_build/docs_html.zip
35+
name: python_sdk_docs
36+
path: docs/_build/html
3837
# Test upload
3938
# - name: Publish package to TestPyPI
4039
# uses: pypa/gh-action-pypi-publish@master

.github/workflows/test.yml

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ jobs:
1313
- ubuntu-latest
1414
python: [ 2.7, 3.7 ]
1515
splunk-version:
16+
- "8.1"
1617
- "8.2"
1718
- "latest"
1819
fail-fast: false

CHANGELOG.md

+15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# Splunk Enterprise SDK for Python Changelog
22

3+
## Version 1.7.3
4+
5+
### Bug fixes
6+
* [#493](https://github.com/splunk/splunk-sdk-python/pull/493) Fixed file permission for event_writer.py file [[issue#487](https://github.com/splunk/splunk-sdk-python/issues/487)]
7+
* [#500](https://github.com/splunk/splunk-sdk-python/pull/500) Replaced index_field with accelerated_field for kvstore [[issue#497](https://github.com/splunk/splunk-sdk-python/issues/497)]
8+
* [#502](https://github.com/splunk/splunk-sdk-python/pull/502) Updated check for IPv6 addresses
9+
10+
### Minor changes
11+
* [#490](https://github.com/splunk/splunk-sdk-python/pull/490) Added ACL properties update feature
12+
* [#495](https://github.com/splunk/splunk-sdk-python/pull/495) Added Splunk 8.1 in GitHub Actions Matrix
13+
* [#485](https://github.com/splunk/splunk-sdk-python/pull/485) Added test case for cookie persistence
14+
* [#503](https://github.com/splunk/splunk-sdk-python/pull/503) README updates on accessing "service" instance in CSC and ModularInput apps
15+
* [#504](https://github.com/splunk/splunk-sdk-python/pull/504) Updated authentication token names in docs to reduce confusion
16+
* [#494](https://github.com/splunk/splunk-sdk-python/pull/494) Reuse splunklib.__version__ in handler.request
17+
318
## Version 1.7.2
419

520
### Minor changes

README.md

+37-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
# The Splunk Enterprise Software Development Kit for Python
55

6-
#### Version 1.7.2
6+
#### Version 1.7.3
77

88
The Splunk Enterprise Software Development Kit (SDK) for Python contains library code designed to enable developers to build applications using the Splunk platform.
99

@@ -30,7 +30,7 @@ Here's what you need to get going with the Splunk Enterprise SDK for Python.
3030

3131
* Splunk Enterprise 9.0 or 8.2
3232

33-
The Splunk Enterprise SDK for Python has been tested with Splunk Enterprise 9.0 and 8.2
33+
The Splunk Enterprise SDK for Python has been tested with Splunk Enterprise 9.0, 8.2 and 8.1
3434

3535
If you haven't already installed Splunk Enterprise, download it [here](http://www.splunk.com/download).
3636
For more information, see the Splunk Enterprise [_Installation Manual_](https://docs.splunk.com/Documentation/Splunk/latest/Installation).
@@ -111,9 +111,9 @@ here is an example of .env file:
111111
# Your version of Splunk Enterprise
112112
version=9.0
113113
# Bearer token for authentication
114-
#bearerToken=<Bearer-token>
114+
#splunkToken=<Bearer-token>
115115
# Session key for authentication
116-
#sessionKey=<Session-Key>
116+
#token=<Session-Key>
117117

118118
#### SDK examples
119119

@@ -209,7 +209,39 @@ class GeneratorTest(GeneratingCommand):
209209
checkpoint_dir = inputs.metadata["checkpoint_dir"]
210210
```
211211

212-
#### Optional:Set up logging for splunklib
212+
### Access service object in Custom Search Command & Modular Input apps
213+
214+
#### Custom Search Commands
215+
* The service object is created from the Splunkd URI and session key passed to the command invocation the search results info file.
216+
* Service object can be accessed using `self.service` in `generate`/`transform`/`stream`/`reduce` methods depending on the Custom Search Command.
217+
* For Generating Custom Search Command
218+
```python
219+
def generate(self):
220+
# other code
221+
222+
# access service object that can be used to connect Splunk Service
223+
service = self.service
224+
# to get Splunk Service Info
225+
info = service.info
226+
```
227+
228+
229+
230+
#### Modular Inputs app:
231+
* The service object is created from the Splunkd URI and session key passed to the command invocation on the modular input stream respectively.
232+
* It is available as soon as the `Script.stream_events` method is called.
233+
```python
234+
def stream_events(self, inputs, ew):
235+
# other code
236+
237+
# access service object that can be used to connect Splunk Service
238+
service = self.service
239+
# to get Splunk Service Info
240+
info = service.info
241+
```
242+
243+
244+
### Optional:Set up logging for splunklib
213245
+ The default level is WARNING, which means that only events of this level and above will be visible
214246
+ To change a logging level we can call setup_logging() method and pass the logging level as an argument.
215247
+ Optional: we can also pass log format and date format string as a method argument to modify default format

scripts/templates/env.template

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ scheme=$scheme
1111
# Your version of Splunk (default: 6.2)
1212
version=$version
1313
# Bearer token for authentication
14-
#bearerToken=<Bearer-token>
14+
#splunkToken=<Bearer-token>
1515
# Session key for authentication
16-
#sessionKey=<Session-Key>
16+
#token=<Session-Key>

splunklib/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,5 @@ def setup_logging(level, log_format=DEFAULT_LOG_FORMAT, date_format=DEFAULT_DATE
3131
format=log_format,
3232
datefmt=date_format)
3333

34-
__version_info__ = (1, 7, 2)
34+
__version_info__ = (1, 7, 3)
3535
__version__ = ".".join(map(str, __version_info__))

splunklib/binding.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
from io import BytesIO
4040
from xml.etree.ElementTree import XML
4141

42+
from splunklib import __version__
4243
from splunklib import six
4344
from splunklib.six.moves import urllib
4445

@@ -346,7 +347,8 @@ def _authority(scheme=DEFAULT_SCHEME, host=DEFAULT_HOST, port=DEFAULT_PORT):
346347
"http://splunk.utopia.net:471"
347348
348349
"""
349-
if ':' in host:
350+
# check if host is an IPv6 address and not enclosed in [ ]
351+
if ':' in host and not (host.startswith('[') and host.endswith(']')):
350352
# IPv6 addresses must be enclosed in [ ] in order to be well
351353
# formed.
352354
host = '[' + host + ']'
@@ -1434,7 +1436,7 @@ def request(url, message, **kwargs):
14341436
head = {
14351437
"Content-Length": str(len(body)),
14361438
"Host": host,
1437-
"User-Agent": "splunk-sdk-python/1.7.2",
1439+
"User-Agent": "splunk-sdk-python/%s" % __version__,
14381440
"Accept": "*/*",
14391441
"Connection": "Close",
14401442
} # defaults

splunklib/client.py

+50-11
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,36 @@ def reload(self):
12161216
self.post("_reload")
12171217
return self
12181218

1219+
def acl_update(self, **kwargs):
1220+
"""To update Access Control List (ACL) properties for an endpoint.
1221+
1222+
:param kwargs: Additional entity-specific arguments (required).
1223+
1224+
- "owner" (``string``): The Splunk username, such as "admin". A value of "nobody" means no specific user (required).
1225+
1226+
- "sharing" (``string``): A mode that indicates how the resource is shared. The sharing mode can be "user", "app", "global", or "system" (required).
1227+
1228+
:type kwargs: ``dict``
1229+
1230+
**Example**::
1231+
1232+
import splunklib.client as client
1233+
service = client.connect(...)
1234+
saved_search = service.saved_searches["name"]
1235+
saved_search.acl_update(sharing="app", owner="nobody", app="search", **{"perms.read": "admin, nobody"})
1236+
"""
1237+
if "body" not in kwargs:
1238+
kwargs = {"body": kwargs}
1239+
1240+
if "sharing" not in kwargs["body"]:
1241+
raise ValueError("Required argument 'sharing' is missing.")
1242+
if "owner" not in kwargs["body"]:
1243+
raise ValueError("Required argument 'owner' is missing.")
1244+
1245+
self.post("acl", **kwargs)
1246+
self.refresh()
1247+
return self
1248+
12191249
@property
12201250
def state(self):
12211251
"""Returns the entity's state record.
@@ -3679,24 +3709,31 @@ class KVStoreCollections(Collection):
36793709
def __init__(self, service):
36803710
Collection.__init__(self, service, 'storage/collections/config', item=KVStoreCollection)
36813711

3682-
def create(self, name, indexes = {}, fields = {}, **kwargs):
3712+
def __getitem__(self, item):
3713+
res = Collection.__getitem__(self, item)
3714+
for k, v in res.content.items():
3715+
if "accelerated_fields" in k:
3716+
res.content[k] = json.loads(v)
3717+
return res
3718+
3719+
def create(self, name, accelerated_fields={}, fields={}, **kwargs):
36833720
"""Creates a KV Store Collection.
36843721
36853722
:param name: name of collection to create
36863723
:type name: ``string``
3687-
:param indexes: dictionary of index definitions
3688-
:type indexes: ``dict``
3724+
:param accelerated_fields: dictionary of accelerated_fields definitions
3725+
:type accelerated_fields: ``dict``
36893726
:param fields: dictionary of field definitions
36903727
:type fields: ``dict``
36913728
:param kwargs: a dictionary of additional parameters specifying indexes and field definitions
36923729
:type kwargs: ``dict``
36933730
36943731
:return: Result of POST request
36953732
"""
3696-
for k, v in six.iteritems(indexes):
3733+
for k, v in six.iteritems(accelerated_fields):
36973734
if isinstance(v, dict):
36983735
v = json.dumps(v)
3699-
kwargs['index.' + k] = v
3736+
kwargs['accelerated_fields.' + k] = v
37003737
for k, v in six.iteritems(fields):
37013738
kwargs['field.' + k] = v
37023739
return self.post(name=name, **kwargs)
@@ -3710,18 +3747,20 @@ def data(self):
37103747
"""
37113748
return KVStoreCollectionData(self)
37123749

3713-
def update_index(self, name, value):
3714-
"""Changes the definition of a KV Store index.
3750+
def update_accelerated_field(self, name, value):
3751+
"""Changes the definition of a KV Store accelerated_field.
37153752
3716-
:param name: name of index to change
3753+
:param name: name of accelerated_fields to change
37173754
:type name: ``string``
3718-
:param value: new index definition
3719-
:type value: ``dict`` or ``string``
3755+
:param value: new accelerated_fields definition
3756+
:type value: ``dict``
37203757
37213758
:return: Result of POST request
37223759
"""
37233760
kwargs = {}
3724-
kwargs['index.' + name] = value if isinstance(value, six.string_types) else json.dumps(value)
3761+
if isinstance(value, dict):
3762+
value = json.dumps(value)
3763+
kwargs['accelerated_fields.' + name] = value
37253764
return self.post(**kwargs)
37263765

37273766
def update_field(self, name, value):

splunklib/modularinput/event_writer.py

100755100644
File mode changed.

tests/test_binding.py

+56
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,12 @@ def test_ipv6_host(self):
190190
host="2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
191191
"https://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8089")
192192

193+
def test_ipv6_host_enclosed(self):
194+
self.assertEqual(
195+
binding._authority(
196+
host="[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"),
197+
"https://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8089")
198+
193199
def test_all_fields(self):
194200
self.assertEqual(
195201
binding._authority(
@@ -491,6 +497,56 @@ def test_handlers(self):
491497
body = context.get(path).body.read()
492498
self.assertTrue(isatom(body))
493499

500+
def urllib2_insert_cookie_handler(url, message, **kwargs):
501+
method = message['method'].lower()
502+
data = message.get('body', b"") if method == 'post' else None
503+
headers = dict(message.get('headers', []))
504+
req = Request(url, data, headers)
505+
try:
506+
# If running Python 2.7.9+, disable SSL certificate validation
507+
if sys.version_info >= (2, 7, 9):
508+
response = urlopen(req, context=ssl._create_unverified_context())
509+
else:
510+
response = urlopen(req)
511+
except HTTPError as response:
512+
pass # Propagate HTTP errors via the returned response message
513+
514+
# Mimic the insertion of 3rd party cookies into the response.
515+
# An example is "sticky session"/"insert cookie" persistence
516+
# of a load balancer for a SHC.
517+
header_list = [(k, v) for k, v in response.info().items()]
518+
header_list.append(("Set-Cookie", "BIGipServer_splunk-shc-8089=1234567890.12345.0000; path=/; Httponly; Secure"))
519+
header_list.append(("Set-Cookie", "home_made=yummy"))
520+
521+
return {
522+
'status': response.code,
523+
'reason': response.msg,
524+
'headers': header_list,
525+
'body': BytesIO(response.read())
526+
}
527+
528+
class TestCookiePersistence(testlib.SDKTestCase):
529+
# Verify persistence of 3rd party inserted cookies.
530+
def test_3rdPartyInsertedCookiePersistence(self):
531+
paths = ["/services", "authentication/users",
532+
"search/jobs"]
533+
logging.debug("Connecting with urllib2_insert_cookie_handler %s", urllib2_insert_cookie_handler)
534+
context = binding.connect(
535+
handler=urllib2_insert_cookie_handler,
536+
**self.opts.kwargs)
537+
538+
persisted_cookies = context.get_cookies()
539+
540+
splunk_token_found = False
541+
for k, v in persisted_cookies.items():
542+
if k[:8] == "splunkd_":
543+
splunk_token_found = True
544+
break
545+
546+
self.assertEqual(splunk_token_found, True)
547+
self.assertEqual(persisted_cookies['BIGipServer_splunk-shc-8089'], "1234567890.12345.0000")
548+
self.assertEqual(persisted_cookies['home_made'], "yummy")
549+
494550
@pytest.mark.smoke
495551
class TestLogout(BindingTestCase):
496552
def test_logout(self):

0 commit comments

Comments
 (0)