Skip to content

Commit

Permalink
Merge pull request #123 from Geotab/certificate-fixes
Browse files Browse the repository at this point in the history
Updates SSL context options to find default system certificates
  • Loading branch information
aaront authored Jun 5, 2024
2 parents a03c5d4 + b798735 commit 35bc3ea
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 173 deletions.
202 changes: 101 additions & 101 deletions Pipfile.lock

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion mygeotab/altitude/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
from .wrapper import AltitudeAPI

from .daas_definition import DaasResult, DaasGetJobStatusResult, DaasGetQueryResult, DaasError, NOT_FULL_API_CALL_EXCEPTION
from .daas_definition import (
DaasResult,
DaasGetJobStatusResult,
DaasGetQueryResult,
DaasError,
NOT_FULL_API_CALL_EXCEPTION,
)

__all__ = [
"AltitudeAPI",
Expand Down
75 changes: 30 additions & 45 deletions mygeotab/altitude/daas_definition.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@

class DaasError:
def __init__(self, error: dict):
self.error = error
self.code = self.error['code']
self.domain = self.error['domain']
self.message = self.error['message']
self.code = self.error["code"]
self.domain = self.error["domain"]
self.message = self.error["message"]


NOT_FULL_API_CALL_EXCEPTION = Exception("api return did not have all expected attributes, please retry again.")


class DaasResult:
"""DaasResult class, the base class for all results returned from calling our application from the gateway
Expand All @@ -19,10 +21,9 @@ class DaasResult:
api_result_errors (list): possible errors list that happened on the altitude application.
api_result_error_message (str): possible single error message that happened on the altitude application.
api_result_error (DaasError): possible single error object that happened on the altitude application.
errors (list): list of all the errors (gateway and altitude application) combined together.
errors (list): list of all the errors (gateway and altitude application) combined together.
"""


def __init__(self, call_result: dict):

if not call_result:
Expand All @@ -32,10 +33,7 @@ def __init__(self, call_result: dict):
self.call_result = call_result

self.daas_errors = [DaasError(error) for error in self.call_result.get("errors", [])]
self.errors = [
Exception(error.message) for error in self.daas_errors
]

self.errors = [Exception(error.message) for error in self.daas_errors]

if "apiResult" not in call_result:
self.errors += [Exception("apiResult not present"), NOT_FULL_API_CALL_EXCEPTION]
Expand All @@ -45,33 +43,24 @@ def __init__(self, call_result: dict):
self.jobs = self.api_result["results"]
self.job = self.jobs[0]


self.api_result_errors = [DaasError(error) for error in self.api_result.get("errors", [])]
self.api_result_error_message = self.api_result.get("errorMessage", None)
self.api_result_error = None

self.errors += [Exception(error.message) for error in self.api_result_errors]



self.errors += [
Exception(error.message) for error in self.api_result_errors
]


if "error" in self.api_result and self.api_result["error"]:
if "error" in self.api_result and self.api_result["error"]:
self.api_result_error = DaasError(self.api_result["error"])
self.errors += [
Exception(self.api_result_error.message)
]
self.errors += [Exception(self.api_result_error.message)]

if self.api_result_error_message and isinstance(self.api_result_error_message, str) and len(self.api_result_error_message):
self.errors += [
Exception(self.api_result_error_message)
]
elif self.api_result_error_message and isinstance(self.api_result_error_message, dict):
self.errors += [
Exception(self.api_result_error_message["message"])
]
if (
self.api_result_error_message
and isinstance(self.api_result_error_message, str)
and len(self.api_result_error_message)
):
self.errors += [Exception(self.api_result_error_message)]
elif self.api_result_error_message and isinstance(self.api_result_error_message, dict):
self.errors += [Exception(self.api_result_error_message["message"])]


class DaasGetJobStatusResult(DaasResult):
Expand All @@ -82,23 +71,22 @@ class DaasGetJobStatusResult(DaasResult):
status (dict): the status of the job
state (str): the state of the job (from the status object)
"""



def __init__(self, call_result: dict):
super().__init__(call_result)
self.id = self.job['id']
self.status = self.job.get("status", {'state': 'FAILED'})
self.id = self.job["id"]
self.status = self.job.get("status", {"state": "FAILED"})
self.state = self.status.get("state", "FAILED")

def has_finished(self):
if self.state == 'DONE':
if self.state == "DONE":
return True
elif self.state != 'FAILED':
elif self.state != "FAILED":
return False
elif self.state == 'FAILED' and self.errors and len(self.errors) > 0:
elif self.state == "FAILED" and self.errors and len(self.errors) > 0:
return False
else:
raise Exception("got to failed state with no error, please reach out.")



class DaasGetQueryResult(DaasResult):
Expand All @@ -109,12 +97,9 @@ class DaasGetQueryResult(DaasResult):
rows (list): the rows including the data
pageToken (str): the token of the page
"""



def __init__(self, call_result: dict):
super().__init__(call_result)
self.total_rows = self.job.get('totalRows', None)
self.rows = self.job.get('rows', None)
self.page_token = self.job.get('pageToken', None)


self.total_rows = self.job.get("totalRows", None)
self.rows = self.job.get("rows", None)
self.page_token = self.job.get("pageToken", None)
37 changes: 12 additions & 25 deletions mygeotab/altitude/wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,14 @@ def __init__(
proxies=proxies,
cert=cert,
)
_ = logging.basicConfig(stream=sys.stdout, level=logging.INFO, format='%(asctime)s.%(msecs)03d %(levelname)-8s %(message)s', datefmt='%Y-%m-%d %H:%M:%S')


_ = logging.basicConfig(
stream=sys.stdout,
level=logging.INFO,
format="%(asctime)s.%(msecs)03d %(levelname)-8s %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)

def _call_api(
self, service_name: str, function_name: str, function_parameters: dict
) -> dict:
def _call_api(self, service_name: str, function_name: str, function_parameters: dict) -> dict:
results = self.call(
method="GetBigDataResults",
serviceName=service_name,
Expand All @@ -64,12 +65,10 @@ def _call_api(
)
return results



def call_api(self, function_name: str, params: dict) -> dict :
'''
def call_api(self, function_name: str, params: dict) -> dict:
"""
Supports getJobStatus calls, and getQueryResults calls. Retries in case of errors like connection rest.
'''
"""
assert function_name in ["getJobStatus", "getQueryResults", "createQueryJob"]
max_tries = 5
for try_index in range(max_tries):
Expand All @@ -87,7 +86,7 @@ def call_api(self, function_name: str, params: dict) -> dict :
raise e
else:
print(f"encountered error trying to parse to api response {str(call_result)}, retrying....")
time.sleep((try_index + 1)*10)
time.sleep((try_index + 1) * 10)
else:
raise e

Expand Down Expand Up @@ -139,8 +138,6 @@ def wait_for_job_to_complete(self, params: dict) -> dict:
raise e
return daas_status.job



def fetch_data(self, params: dict) -> dict:
"""
fetch data for the given params. jobId needs to be included in params.
Expand Down Expand Up @@ -194,7 +191,7 @@ def get_data(self, params: dict) -> list:
logging.error(f"error: error while combining data:: {e}")
raise e
return data

def do(self, params: dict) -> list:
"""
given the parameters, will call the request, wait on it to finish and return the combined data.
Expand All @@ -210,13 +207,3 @@ def do(self, params: dict) -> list:
data = self.get_data(params)
logging.info(f"data gathered")
return data










2 changes: 2 additions & 0 deletions mygeotab/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,10 +351,12 @@ class GeotabHTTPAdapter(HTTPAdapter):

def init_poolmanager(self, connections, maxsize, block=False, **pool_kwargs):
ssl_context = create_urllib3_context(ssl_version=ssl.PROTOCOL_TLS)
ssl_context.load_default_certs()
ssl_context.options |= ssl.OP_NO_SSLv2
ssl_context.options |= ssl.OP_NO_SSLv3
ssl_context.options |= ssl.OP_NO_TLSv1
ssl_context.options |= ssl.OP_NO_TLSv1_1
ssl_context.options |= ssl.OP_ENABLE_MIDDLEBOX_COMPAT
self.poolmanager = urllib3.poolmanager.PoolManager(
num_pools=connections, maxsize=maxsize, block=block, ssl_context=ssl_context, **pool_kwargs
)
Expand Down
2 changes: 2 additions & 0 deletions mygeotab/api_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,10 +203,12 @@ async def _query(server, method, parameters, timeout=DEFAULT_TIMEOUT, verify_ssl
ssl_context = False
if verify_ssl or cert:
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS)
ssl_context.load_default_certs()
ssl_context.options |= ssl.OP_NO_SSLv2
ssl_context.options |= ssl.OP_NO_SSLv3
ssl_context.options |= ssl.OP_NO_TLSv1
ssl_context.options |= ssl.OP_NO_TLSv1_1
ssl_context.options |= ssl.OP_ENABLE_MIDDLEBOX_COMPAT
if cert:
if isinstance(cert, str):
ssl_context.load_cert_chain(cert)
Expand Down
10 changes: 9 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,15 @@
packages=packages,
package_data={"": ["LICENSE"]},
license="Apache 2.0",
install_requires=["requests", "urllib3", "click", "pytz", "arrow", "aiohttp>=3.8.1,<4", "python-rapidjson"],
install_requires=[
"requests",
"urllib3",
"click",
"pytz",
"arrow",
"aiohttp>=3.8.1,<4",
"python-rapidjson",
],
setup_requires=["wheel"],
entry_points="""
[console_scripts]
Expand Down

0 comments on commit 35bc3ea

Please sign in to comment.