Git Product home page Git Product logo

pysnc's Introduction

ServiceNow Python API

What: PySnc is a python interface for the ServiceNow and the Table API. It is designed to mimic the familiar GlideRecord interface you know with pythonic support where applicable.

Why: Spawned from the desire to interact with ServiceNow data in a familiar and consistent manner

Install

pip install pysnc

Quick Start

from pysnc import ServiceNowClient

client = ServiceNowClient('https://dev0000.service-now.com', ('integration.user', password))

gr = client.GlideRecord('sys_user')
gr.add_query('user_name', 'admin')
gr.query()
for r in gr:
	print(r.sys_id)

Documentation

Full documentation currently available at https://servicenow.github.io/PySNC/

Or build them yourself:

cd docs && make html

Development Notes

The following functions are not (yet?) supported:

  • choose_window(first_row, last_row, force_count=True) TODO
  • get_class_display_value()
  • get_record_class_name()
  • is_valid() TODO
  • is_valid_record()
  • new_record()
  • _next()
  • _query()

The following will not be implemented:

  • get_attribute(field_name) Not Applicable
  • get_ED() Not Applicable
  • get_label() Not Applicable
  • get_last_error_message() Not Applicable
  • set_workflow(enable) Not Possible
  • operation() Not Applicable
  • set_abort_action() Not Applicable
  • is_valid_field() Not Possible
  • is_action_aborted() Not Applicable

Feature Wants and TODO

  • GlideAggregate support (/api/now/stats/{tableName})

And we want to:

  • Improve documentation

pysnc's People

Contributors

arthurzenika avatar dependabot[bot] avatar vetsin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

pysnc's Issues

Implement a insert_multiple()

We have update_multiple and delete_multiple which take advantage of the batch api -- no reason to not do the same with insert.

I imagine something like:

gr = client.GlideRecord('some_table')

gr.initialize()
gr.name = 'first'

gr.initialize()
gr.name = 'second'

gr.insert_multiple() # or maybe even just gr.insert()

We may want to 'iterate' the record to make it more obvious?

get function does not give ACL errors

doing a gr.get(sys_id) does not show any errors when we have a RoleException

doing it via gr.query() however does -- need this to be more consistent

e.g.

        test = self.client.GlideRecord('sys_atf_test')
        test.add_query('sys_id', sys_id)
        test.query()

vs

        test = self.client.GlideRecord('sys_atf_test')
        test.get(sys_id)

Default OAuth provider missing

Uses the legacy mobile oauth provider which isnt out of box on newest instances. Deprecate this feature and update unit tests.

ERROR: test_oauth (test_snc_auth.TestAuth)
ERROR: test_oauth_builtin (test_snc_auth.TestAuth)

ip access control error

when ipaccess control is enabled, a 403 is returned with HTML. however client.py:116 attempts to parse it as json.

Need to handle this error path so it's more debuggable

Dor walking reference fields

Hello, first of all, amazing work on this API! I've just started using it today and it already helped me A LOT.

For my question: does it support dot walking the reference fields, like gr.caller_id.user_name? It seems that caller_id is simply a string and not an object pointing to the sys_user, or am I wrong?

Mock GlideRecords in automation testing

Hello team,
I am trying to assembly some tests for my automation. This automation is a bunch of Python scripts using PySNC. Unfortunately, I do not have any test SNOW instances to connect to, so I cannot perform the tests as you do in your pipeline. Any idea how should I mock the GlideRecord with some entries inside, so I can iterate over them in the tests?
Many thanks for any ideas!
Best,
Szymon

Bulk extract fails with `Maximum Execution time exceeded`

I am trying to Bulk extract a table with a lot of data (last 7 months based on sys_created_on). The extraction fails with Maximum Execution time exceeded from here.

I used to use this other wrapper on top of ServiceNow API which used to provide means to use the limit param which could help with fetching larger volumes data. Is there any similar means to do the same using PySNC without having to make multiple calls to Gliderecord for shorter amounts of data?

Async Support

The topic of asynchronous requests was brought up. This seems mostly useful for the get() method.

Perhaps something like:

gr.get('sysidhere', lambda x: for e in x: print(e))

or we can deal with Futures

future = gr.get('sysidhere')
future.result()

...

await gr.get('sysidhere')

Or

client.await([gr.get('asdf'), gr.get('1234')])

CloudQuery Source Plugin?

Hi Team, hopefully this is right place to ask, if not, I'd appreciate if you can direct me.

I'm the founder of cloudquery.io, a high performance open source ELT framework.

Our users are interested in a ServiceNow plugin, but as we cannot maintain all the plugins ourselves, I was curious if this would be an interesting collaboration, where we would help implement an initial source plugin, and you will help maintain it.

This will give your users the ability to sync ServiceNow APIs to any of their datalakes/data-warehouses/databases easily using any of the growing list of CQ destination plugins.

Best,
Yevgeny

Type declaration for insert and update in GlideRecord is incorrect

Hi there, using 1.1.6 version of your lib to do some ServiceNow automation.

The methods insert and update on the GlideRecord are declared as

Optional(str)

This is incorrect they should have been declared as

Optional(GlideElement)

or made to return the sys_is as a str.

implementing set_new_guid_value

I see in the dev notes this hasn’t been implemented yet. But it’s not marked as “not possible”, so it seems to be possible. I’m having trouble finding resources online for doing this. Does anyone know the API request to do a set_new_guid_value on a record in service now? If someone can point me in the right direction, I can help implement. thanks

Provide join_queries that look through cmdb_rel_ci

I'm trying to extract data from two tables that are linked using cmdb_rel_ci. I was expecting to be able to add a join_query as described by https://servicenow.github.io/PySNC/user/advanced.html#join-queries but it seems that this is a functionality to query linked or dotwalked attributes (not sure how they are called in servicenow - reference field?) with join_table_field.

This is pseudo code I would like to be able to write :

gr = client.GlideRecord('cmdb_ci_server')
join_query = gr.add_join_query('cmdb_ci_ip_address', join_relationship_field='Owned by::Owns')
gr.query()

Inspired by schema https://docs.servicenow.com/en-US/bundle/tokyo-servicenow-platform/page/product/configuration-management/concept/class-server.html

That would return records of servers with their related ip_address.

Is this already possible with the existing code ?

Duplicate sys_id in response

image

This should not happen, i believe it is reproduced as follows

gr = bt1.GlideRecord('some_table')
gr.limit = 50
gr.query()
print(len(gr))

You'll see something like 53192 as the len is reporting the actual, returned by the headers. We're literally just limiting on the client side how much we pull in. If you then did something like this...

df = pd.DataFrame(gr.to_pandas())`
print(df.shape)

your df.shape would give you 53192 rows! How? it would just loop the 50 records you do have. Suggested solution? ensure everywhere that you actually only make results with 50? Or maybe we should report 50 as the len in the first place too.

Add easy method to query/execute UI Actions

We can use the API to query, then execute UI Actions. The following is the current method to execute:

params = dict(sysparm_table='x_snc_some_table', sysparm_sys_id=sys_id)
r = self.client.session.post(f"{self.client.instance}/api/now/ui/ui_action/{ui_action_sys_id}", params=params, json={})

But we could easily make this part of the client. Something like self.client.execute_ui_action(...) or perhaps even a self.client.UiAction(table, ...) deal like attachment?

Similarly the record object has a gr.add_attachment so maybe we could have also gr.exeute_ui_action?

Add key and hmac auth support

e.g.

secret = b'it would go here'

request = requests.Request(
    'POST', 
    'https://theinstance.service-now.com/api/now/table/incident',
    json={'short_description':'test'}
)
prepped = request.prepare()
signature = hmac.new(secret, prepped.body, digestmod=hashlib.sha256)
encoded_sig = base64.standard_b64encode(signature.digest()).decode()
prepped.headers['x-sn-hmac-signature-256'] = f"keyId=test_secret,signature={encoded_sig}"
print(prepped.headers)

with requests.Session() as session:
    response = session.send(prepped)
    print(response.status_code)
    print(response.text)

The other is more simply ['x-snc-api-key'] = 'key' or whatnot

inconsistent get behavior

When doing something as such:

gr = client.GlideRecord(table)
gr.initialize()
gr.field = 'some value'
gr.get('non_existant_id')

We expect the gr.field to now be None -- in actuality it is still some value as the failed get() did not update _current.

Actual GlideRecord behaves in this matter:

let gr = new GlideRecord('incident')
gr.initialize()
gr.short_description = 'this is a test'
gs.info(gr.short_description)
gr.get('sys_id')
gs.info(gr.short_description)

will give us

my_scope: this is a test
my_scope: 

Object of type GlideElement is not JSON serializable

I'm using PySNC to create records in my ServiceNow instance.
Used Python version: 3.10
Last known working version: 1.0.7
Bug seen in versions: 1.1.2, 1.1.3

My code worked with version 1.0.7 and then stopped working in 1.1.2 (and still didn't work in 1.1.3). I'm getting the following exception when calling GlideRecord.insert:

Traceback (most recent call last):
  File "/home/vsts/work/1/s/create-ticket.py", line 147, in <module>
    call.insert()
  File "/home/vsts/work/1/s/antenv/lib/python3.10/site-packages/pysnc/record.py", line 538, in insert
    response = self._client.table_api.post(self)
  File "/home/vsts/work/1/s/antenv/lib/python3.10/site-packages/pysnc/client.py", line 224, in post
    return self._send(req)
  File "/home/vsts/work/1/s/antenv/lib/python3.10/site-packages/pysnc/client.py", line 176, in _send
    request = self.session.prepare_request(req)
  File "/home/vsts/work/1/s/antenv/lib/python3.10/site-packages/requests/sessions.py", line 484, in prepare_request
    p.prepare(
  File "/home/vsts/work/1/s/antenv/lib/python3.10/site-packages/requests/models.py", line 371, in prepare
    self.prepare_body(data, files, json)
  File "/home/vsts/work/1/s/antenv/lib/python3.10/site-packages/requests/models.py", line 511, in prepare_body
    body = complexjson.dumps(json, allow_nan=False)
  File "/opt/hostedtoolcache/Python/3.10.11/x64/lib/python3.10/json/__init__.py", line 238, in dumps
    **kw).encode(obj)
  File "/opt/hostedtoolcache/Python/3.10.11/x64/lib/python3.10/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/opt/hostedtoolcache/Python/3.10.11/x64/lib/python3.10/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/opt/hostedtoolcache/Python/3.10.11/x64/lib/python3.10/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type GlideElement is not JSON serializable

Export Query and QueryCondition classes

By exporting Query and QueryCondition classes in the __init__.py file will help to create custom queries programatically.

from pysnc import Query, QueryCondition, GlideRecord

# Using Query
q = Query("incident")

q.add_active_query()
q.add_query("description", "=", "123456")

raw_query = q.generate_query()

gr = GlideRecord("ServiceNowClient", "incident")

gr.add_encoded_query(raw_query)

# Using now the QueryCondition
q = QueryCondition("description", "CONTAINS", "testing")
q.add_or_query("impact", "=", "2")

raw_condition = q.generate()

gr = GlideRecord("instance", "incident")
gr.add_encoded_query(raw_query)

Another important point will be to unify the interface for Query and QueryCondition. Perhaps, Query.generate_query() and QueryCondition.generate()

Support API debugging/session messages

Support the headers

X-WantSessionDebugMessages: true
X-WantSessionNotificationMessages: true

For:

"session":{"notifications":[],"debug_logs":[]}

These, however, require actual sessions

`to_pandas` function - update docs

Good afternoon,
First, thank you for all the work you've put into creating this Python package.

Problem Statement
to_pandas() call is extremely slow if the returned data has a lot of columns.

Example: a simple query to the user table will return 7 rows of data, but will also return 100-200 columns. The to_pandas() call in this case will take several minutes to complete even though there are only 7 rows.

Request

  1. Print a warning when running that function if number of columns is larger than 20.
  2. Update the function docstring and recommend specifying the desired fields with gr.fields

`pysnc/client.py in _validate_response` fails when not json returned

Good afternoon! 👋

I ran into an interesting error today when querying a table with pysnc: JSONDecodeError: Expecting value: line 1 column 1 (char 0).

Looking at the full error trace (attached at the bottom of this issue) I see that the line that is failing is in pysnc/client.py in _validate_response. It appears as though it is attempting to parse the server response as json but unfortunately the data that is being returned looks like HTML (at bottom of this issue).

Using my dapper debugger, I see that the pertinent lines in this HTML response are http.400 and java.lang.IllegalArgumentException: Request header is too large. It doesn't like the size of my request. If I make my request smaller and send it again it does not error out.

I would recommend modifying the below piece of code to first check whether the returned data is json or not before attempting to parse it. Let me know if you have questions!

pysnc/client.py in _validate_response(self, response)
    116             raise AuthenticationException(rjson)
    117         if code == 400:
--> 118             rjson = response.json()
    119             raise RequestException(rjson)

Repro steps

sys_ids = [<SYS_IDS>] # place 300+ sys ids here
company_sys_ids_joined = ",".join(sys_ids)

gr = client_cpt.GlideRecord('<TABLE_NAME>')
query = 'companyIN' + company_sys_ids_joined # this is a string that contains ~300 sys ids
gr.add_encoded_query(query)
gr.fields = ['company',  'name']
gr.query()

HTML server response

<html><head><title>ServiceNow - Error report</title><style><!--h1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} h2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} h3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} body {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} b {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} p {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;} a {color:black;} a.name {color:black;} .line {height:1px;background-color:#525D76;border:none;}--></style> </head><body><h1>HTTP Status 400 – </h1><HR size="1" noshade="noshade"><p><b>type</b> Exception Report</p><p><b>Message</b> <u></u></p><p><b>Description</b> <u>http.400</u></p><p><b>Exception</b> <pre>java.lang.IllegalArgumentException: Request header is too large
	org.apache.coyote.http11.Http11InputBuffer.fill(Http11InputBuffer.java:726)
	org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:464)
	org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:682)
	org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:810)
	org.apache.tomcat.util.net.Nio2Endpoint$SocketProcessor.doRun(Nio2Endpoint.java:1777)
	org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	org.apache.tomcat.util.net.AbstractEndpoint.processSocket(AbstractEndpoint.java:1082)
	org.apache.tomcat.util.net.Nio2Endpoint$Nio2SocketWrapper$2.completed(Nio2Endpoint.java:569)
	org.apache.tomcat.util.net.Nio2Endpoint$Nio2SocketWrapper$2.completed(Nio2Endpoint.java:547)
	java.base/sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:127)
	java.base/sun.nio.ch.Invoker$2.run(Invoker.java:219)
	java.base/sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:112)
	java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	java.base/java.lang.Thread.run(Thread.java:834)
</pre></p><p><b>Note</b> <u>The full stack trace of the root cause is available in the server logs.</u></p><HR size="1" noshade="noshade"><h3>ServiceNow</h3></body></html>

Error trace

---------------------------------------------------------------------------
JSONDecodeError                           Traceback (most recent call last)
<ipython-input-25-cdc177364535> in <module>
----> 1 get_company_instances(0)

<ipython-input-24-98142c971225> in get_company_instances(index_start, index_end)
     13     gr.add_encoded_query(query)
     14     gr.fields = ['company',  'name']
---> 15     gr.query()
     16 
     17     return pd.DataFrame(gr.to_pandas())

~/Documents/projects/sandbox-python/.venv/lib/python3.9/site-packages/pysnc/record.py in query(self)
    237             :RequestException: If the transaction is canceled due to execution time
    238         """
--> 239         response = self._client._list(self)
    240         code = response.status_code
    241         if code == 200:

~/Documents/projects/sandbox-python/.venv/lib/python3.9/site-packages/pysnc/client.py in _list(self, record)
    125                              params=params,
    126                              headers=dict(Accept="application/json"))
--> 127         self._validate_response(r)
    128         return r
    129 

~/Documents/projects/sandbox-python/.venv/lib/python3.9/site-packages/pysnc/client.py in _validate_response(self, response)
    116             raise AuthenticationException(rjson)
    117         if code == 400:
--> 118             rjson = response.json()
    119             raise RequestException(rjson)
    120 

~/Documents/projects/sandbox-python/.venv/lib/python3.9/site-packages/requests/models.py in json(self, **kwargs)
    898                     # used.
    899                     pass
--> 900         return complexjson.loads(self.text, **kwargs)
    901 
    902     @property

~/.pyenv/versions/3.9.1/lib/python3.9/json/__init__.py in loads(s, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
    344             parse_int is None and parse_float is None and
    345             parse_constant is None and object_pairs_hook is None and not kw):
--> 346         return _default_decoder.decode(s)
    347     if cls is None:
    348         cls = JSONDecoder

~/.pyenv/versions/3.9.1/lib/python3.9/json/decoder.py in decode(self, s, _w)
    335 
    336         """
--> 337         obj, end = self.raw_decode(s, idx=_w(s, 0).end())
    338         end = _w(s, end).end()
    339         if end != len(s):

~/.pyenv/versions/3.9.1/lib/python3.9/json/decoder.py in raw_decode(self, s, idx)
    353             obj, end = self.scan_once(s, idx)
    354         except StopIteration as err:
--> 355             raise JSONDecodeError("Expecting value", s, err.value) from None
    356         return obj, end

JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Unhelpful error when using http instead of https

On insert, for example, you get a 200 return with a JSON blob instead of anything meaningful.

The ask is to improve feedback to make this easier to debug.

In [26]: gr.insert()
---------------------------------------------------------------------------
InsertException                           Traceback (most recent call last)
<ipython-input-26-38bda16632a5> in <module>
----> 1 gr.insert()
/usr/local/lib/python3.8/site-packages/pysnc/record.py in insert(self)
    304             raise AuthenticationException(response.json()['error'])
    305         else:
--> 306             raise InsertException(response.json(), status_code=code)
    307
    308     def update(self):
InsertException: (InsertException(...), "200 - {'result': [...

Update does not work when sys_id is not a field

If you specify gr.fields = 'active,short_description' for example and then try to update it will error - because sys_id is never pulled and we don't know what record we're pulling.

Should always pull sys_id no matter what.

Binding that uses the /api/now/cmdbrelation/relation/

In the following knowledge base documentation : https://support.servicenow.com/kb?id=kb_article_view&sysparm_article=KB0854577 a ReST API to extract information from relations with a depth level seems to indicate the possibility of getting related items in ServiceNow. This type of functionality would be super useful for the way we use PySNC. Any plans of looking into this and offering a binding to this functionality ?

(probably related is #54)

Dependency problem with pip install

In the pyproject.toml, it defines this:

PySNC/pyproject.toml

Lines 19 to 24 in f1fed33

[tool.poetry.dependencies]
python = "^3.8"
requests = "2.31.0"
requests-oauthlib = { version = ">=1.2.0", optional = true}
certifi = "2023.7.22"
pip = "^23.3.1"

The carat is causing the required pip version to be required at >=23.3.1<24.0.0. Since pip 24.0.0 is already released, anyone that's already updated pip can no longer install 1.1.6 without a forced downgrade.

Maybe >= would be better than carat if there's a pip dependency in 23.x?

Tasks

No tasks being tracked yet.

Attachments Get is Broken

attachment = self.client.Attachment(raw_case["sys_class_name"])
attachment.get(raw_case["sys_id"])

image

Many errors and warnings from tests

Wrong functions called and unclosed sockets e.g.

test_serialize_all_batch (test_snc_serialization.TestSerialization) ... /Users/matthew.gill/.pyenv/versions/anaconda3-5.3.1/lib/python3.7/_collections_abc.py:848: ResourceWarning: unclosed <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('192.168.2.177', 61001), raddr=('149.96.6.119', 443)>
  for key, value in kwds.items():
/Users/matthew.gill/.pyenv/versions/anaconda3-5.3.1/lib/python3.7/_collections_abc.py:848: ResourceWarning: unclosed <socket.socket fd=9, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('192.168.2.177', 61002), raddr=('149.96.6.119', 443)>
  for key, value in kwds.items():
/Users/matthew.gill/.pyenv/versions/anaconda3-5.3.1/lib/python3.7/_collections_abc.py:848: ResourceWarning: unclosed <socket.socket fd=10, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('192.168.2.177', 61004), raddr=('149.96.6.119', 443)>
  for key, value in kwds.items():
/Users/matthew.gill/.pyenv/versions/anaconda3-5.3.1/lib/python3.7/_collections_abc.py:848: ResourceWarning: unclosed <socket.socket fd=12, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('192.168.2.177', 61005), raddr=('149.96.6.119', 443)>
  for key, value in kwds.items():
ok

attachment list bug

tried using get_attachments() and it gave me zero records back when manually querying them worked. Need to figure out why.

SSLCertVerificationError exceptions with PySNC 1.1.0 and 1.1.1

Hello,

PySNC 1.1.0 and 1.1.1 seem to be causing ssl.SSLCertVerificationError when SSL is being intercepted in an enterprise environment.

Upgrading to Python 3.11 does not help. Locking PySNC to 1.0.7 does resolve the issue.

{"pysnc":"1.1.0","severity":"INFO"}
Traceback (most recent call last):
  File "/home/gokeefe/.local/share/virtualenvs/servicenow-active-tasks-report-AWneSsyF/lib/python3.9/site-packages/urllib3/connectionpool.py", line 703, in urlopen
    httplib_response = self._make_request(
  File "/home/gokeefe/.local/share/virtualenvs/servicenow-active-tasks-report-AWneSsyF/lib/python3.9/site-packages/urllib3/connectionpool.py", line 386, in _make_request
    self._validate_conn(conn)
  File "/home/gokeefe/.local/share/virtualenvs/servicenow-active-tasks-report-AWneSsyF/lib/python3.9/site-packages/urllib3/connectionpool.py", line 1042, in _validate_conn
    conn.connect()
  File "/home/gokeefe/.local/share/virtualenvs/servicenow-active-tasks-report-AWneSsyF/lib/python3.9/site-packages/urllib3/connection.py", line 419, in connect
    self.sock = ssl_wrap_socket(
  File "/home/gokeefe/.local/share/virtualenvs/servicenow-active-tasks-report-AWneSsyF/lib/python3.9/site-packages/urllib3/util/ssl_.py", line 449, in ssl_wrap_socket
    ssl_sock = _ssl_wrap_socket_impl(
  File "/home/gokeefe/.local/share/virtualenvs/servicenow-active-tasks-report-AWneSsyF/lib/python3.9/site-packages/urllib3/util/ssl_.py", line 493, in _ssl_wrap_socket_impl
    return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
  File "/home/gokeefe/.pyenv/versions/3.9.13/lib/python3.9/ssl.py", line 501, in wrap_socket
    return self.sslsocket_class._create(
  File "/home/gokeefe/.pyenv/versions/3.9.13/lib/python3.9/ssl.py", line 1041, in _create
    self.do_handshake()
  File "/home/gokeefe/.pyenv/versions/3.9.13/lib/python3.9/ssl.py", line 1310, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate in certificate chain (_ssl.c:1129)
During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/gokeefe/.local/share/virtualenvs/servicenow-active-tasks-report-AWneSsyF/lib/python3.9/site-packages/requests/adapters.py", line 487, in send
    resp = conn.urlopen(
  File "/home/gokeefe/.local/share/virtualenvs/servicenow-active-tasks-report-AWneSsyF/lib/python3.9/site-packages/urllib3/connectionpool.py", line 787, in urlopen
    retries = retries.increment(
  File "/home/gokeefe/.local/share/virtualenvs/servicenow-active-tasks-report-AWneSsyF/lib/python3.9/site-packages/urllib3/util/retry.py", line 592, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='gokeefe.service-now.com', port=443): Max retries exceeded with url: /api/now/table/sc_task?sysparm_query=assignment_group%3D117db1491bdd7b408f04caad1e4bcbcd%5EORassignment_group%3Db697561adb1017807037572e5e9619b7%5Eactive%3Dtrue%5EORDERBYopened_at&sysparm_limit=100&sysparm_offset=0&sysparm_display_value=all&sysparm_exclude_reference_link=true&sysparm_suppress_pagination_header=true (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate in certificate chain (_ssl.c:1129)')))
During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/gokeefe/gitlab/devops/devops-automation/automated-reports/servicenow-active-tasks-report/./main.py", line 168, in <module>
    main(start_time)
  File "/home/gokeefe/gitlab/devops/devops-automation/automated-reports/servicenow-active-tasks-report/./main.py", line 123, in main
    gr.query()
  File "/home/gokeefe/.local/share/virtualenvs/servicenow-active-tasks-report-AWneSsyF/lib/python3.9/site-packages/pysnc/record.py", line 453, in query
    response = self._client.table_api.list(self)
  File "/home/gokeefe/.local/share/virtualenvs/servicenow-active-tasks-report-AWneSsyF/lib/python3.9/site-packages/pysnc/client.py", line 194, in list
    return self._send(req)
  File "/home/gokeefe/.local/share/virtualenvs/servicenow-active-tasks-report-AWneSsyF/lib/python3.9/site-packages/pysnc/client.py", line 176, in _send
    r = self.session.send(request, stream=stream)
  File "/home/gokeefe/.local/share/virtualenvs/servicenow-active-tasks-report-AWneSsyF/lib/python3.9/site-packages/requests/sessions.py", line 701, in send
    r = adapter.send(request, **kwargs)
  File "/home/gokeefe/.local/share/virtualenvs/servicenow-active-tasks-report-AWneSsyF/lib/python3.9/site-packages/requests/adapters.py", line 518, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='gokeefe.service-now.com', port=443): Max retries exceeded with url: /api/now/table/sc_task?sysparm_query=assignment_group%3D117db1491bdd7b408f04caad1e4bcbcd%5EORassignment_group%3Db697561adb1017807037572e5e9619b7%5Eactive%3Dtrue%5EORDERBYopened_at&sysparm_limit=100&sysparm_offset=0&sysparm_display_value=all&sysparm_exclude_reference_link=true&sysparm_suppress_pagination_header=true (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate in certificate chain (_ssl.c:1129)')))

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.