splunk / splunk-sdk-python

Splunk Software Development Kit for Python
http://dev.splunk.com
Apache License 2.0
698 stars 370 forks source link

JSONResultsReader not iterable when the result of the query is empty #501

Closed lc4nt closed 1 year ago

lc4nt commented 1 year ago

Describe the bug When using oneshot, the JSONResultsReader object is not iterable, if the result of the query is empty. Other type of jobs haven't been tested.

To Reproduce Adjust the script below for your own environment and construct a query which doesn't return results

from splunklib.results import JSONResultsReader
from splunklib import client as splunkclient

from getpass import getpass

HOST = "yourhost"
PORT = 8089
USER = "youruser"

if __name__ == "__main__":
    splunkservice = splunkclient.connect(
                host=HOST,
                port=PORT,
                username=USER,
                password=getpass(),
                scheme="https",
                autologin=True)

    kwargs = {
                "latest_time": "now",
                "earliest_time": "-1h",
                "output_mode":"json",
                "f":["*"]
            }

    query = 'search index=yourindex blablabla'

    r = splunkservice.jobs.oneshot(query=query, kwargs=kwargs, output_mode='json')
    print("done with query")
    res = JSONResultsReader(r)
    print("created JSONResultsReader object")
    l = list(res)
    print("converted to list")

Expected behavior The program ends and the variable l is empty

Logs or Screenshots The program doesn't terminate trying to iterate over res indefinitely

(venv) [user@system]$ python oneshot.py 
Password: 
done with query
created JSONResultsReader object

Splunk (please complete the following information):

SDK (please complete the following information):

lc4nt commented 1 year ago

More updates and a possible workaround.
If one tries to read the content of ResponseReader returned by oneshot by using readall(), the program hangs. This doesn't happen though by trying to read one byte at the time gradually expanding the buffer size:

    r = splunkservice.jobs.oneshot(query=query, kwargs=kwargs, output_mode='json')
    print(f"Is empty:{r.empty}")
    for i in range (1,100):
        print(f"bytes read:{i}, content {r.read(i)}")

The program painfully and slowly tries to read the number of bytes requested:

[user@system]$ python oneshot.py 
Password: 
Is empty:False
bytes read:1, content b' '
bytes read:2, content b'  '
bytes read:3, content b'   '
bytes read:4, content b'    '
bytes read:5, content b'     '
bytes read:6, content b'      '
bytes read:7, content b'       '
bytes read:8, content b'        '
bytes read:9, content b'         '
bytes read:10, content b'          '
bytes read:11, content b'           '
bytes read:12, content b'            '
bytes read:13, content b'             '
bytes read:14, content b'              '
bytes read:15, content b'               '
bytes read:16, content b'                '
bytes read:17, content b'                 '
bytes read:18, content b'                  '
bytes read:19, content b'                   '
bytes read:20, content b'                    '
bytes read:21, content b'                     '

What is actually the content of that buffer?

    r = splunkservice.jobs.oneshot(query=query, kwargs=kwargs, output_mode='json')
    print(binascii.hexlify(r.read(5)))

---------------------------------------------------------------------------
[user@system]$ python oneshot.py 
Password: 
b'2020202020'

Possible workaround Read the first n-bytes of ResponseReader, if they all equal to \x20, the response is empty

    r = splunkservice.jobs.oneshot(query=query, kwargs=kwargs, output_mode='json')
    if r.read(5) == b'\x20\x20\x20\x20\x20':
        print('empty response')
        sys.exit(0)
ashah-splunk commented 1 year ago

@lc4nt thank you for the details of the issue as well as for the workaround. We will look into this and provide an update soon.

ashah-splunk commented 1 year ago

Hi @lc4nt Sorry for the delay in response. We were not able to reproduce the issue. The given script executed successfully in our testing without any changes in the SDK. Please let us know if anything is missed from the script that needs to be tested.

ashah-splunk commented 1 year ago

Closing the Issue as we haven't received any response. @lc4nt please reopen the Issue if you are still facing the issue.

lc4nt commented 1 year ago

Hi @ashah-splunk ,

apologies for the late response. I can confirm the problem still exists in our infrastructure. However, it is difficult to tell what is the potential root cause precisely.

The behavior I described shows up sometime. If you would like repeat the test, you would probably need to wrap it around an infinite loop.

However, there is also a chance that something is odd with our networking environment. In addition to the problem I described above, it seems the JSON Response we get back from the Splunk API is sometimes truncated (but in the beginning), at the point I had to ditch the usage of JSONResultsReader and introduce a fix like this in one of our tools:

        fixed_resp = ""
        resp_text = response.read().decode("utf-8", errors='replace')

        #"preview":false
        if resp_text[0] == '"':
            fixed_resp = "{" + resp_text
        # preview":false
        elif resp_text[0] == 'p':
            fixed_resp = '{"' + resp_text
        else:
            fixed_resp = resp_text

Anyway thanks for looking into it!