This repository has been archived by the owner on Jun 6, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
24 changed files
with
375 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
KONG_MANAGEMENT=http://localhost:8000/management | ||
KONG_USERNAME=kong | ||
KONG_PASSWORD=kong |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
KONG_MANAGEMENT=http://localhost:8000/management | ||
KONG_USERNAME=kong | ||
KONG_PASSWORD=kong |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,3 +60,5 @@ target/ | |
|
||
# pyenv python configuration file | ||
.python-version | ||
venv | ||
.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import requests | ||
from .errors import KongError | ||
|
||
|
||
class Client(object): | ||
|
||
def __init__(self, base_url, username=None, password=None): | ||
|
||
if base_url[-1:] != '/': | ||
base_url = base_url + '/' | ||
|
||
self.base_url = base_url | ||
self.username = username | ||
self.password = password | ||
|
||
self.rate_limit_details = {} | ||
self.http_session = requests.Session() | ||
|
||
@property | ||
def _auth(self): | ||
if self.username and self.password: | ||
return self.username, self.password | ||
return None | ||
|
||
@property | ||
def status(self): | ||
from .service import status | ||
return status.Status(self) | ||
|
||
def _execute_request(self, request, params): | ||
result = request.execute(self.base_url, self._auth, params) | ||
return result | ||
|
||
def get(self, path, params={}): | ||
from . import request | ||
req = request.Request('GET', path, self.http_session) | ||
return self._execute_request(req, params) | ||
|
||
def post(self, path, params): | ||
from . import request | ||
req = request.Request('POST', path, self.http_session) | ||
return self._execute_request(req, params) | ||
|
||
def put(self, path, params): | ||
from . import request | ||
req = request.Request('PUT', path, self.http_session) | ||
return self._execute_request(req, params) | ||
|
||
def patch(self, path, params): | ||
from . import request | ||
req = request.Request('PATCH', path, self.http_session) | ||
return self._execute_request(req, params) | ||
|
||
def delete(self, path, params): | ||
from . import request | ||
req = request.Request('DELETE', path, self.http_session) | ||
return self._execute_request(req, params) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
|
||
class KongError(Exception): | ||
|
||
def __init__(self, message=None, context=None): | ||
super(KongError, self).__init__(message) | ||
self.message = message | ||
self.context = context | ||
|
||
|
||
class ArgumentError(ValueError, KongError): | ||
pass | ||
|
||
|
||
class HttpError(KongError): | ||
pass | ||
|
||
|
||
class ResourceNotFound(KongError): | ||
pass | ||
|
||
|
||
class AuthenticationError(KongError): | ||
pass | ||
|
||
|
||
class ServerError(KongError): | ||
pass | ||
|
||
|
||
class BadGatewayError(KongError): | ||
pass | ||
|
||
|
||
class ServiceUnavailableError(KongError): | ||
pass | ||
|
||
|
||
class BadRequestError(KongError): | ||
pass | ||
|
||
|
||
class RateLimitExceeded(KongError): | ||
pass | ||
|
||
|
||
class MultipleMatchingUsersError(KongError): | ||
pass | ||
|
||
|
||
class UnexpectedError(KongError): | ||
pass | ||
|
||
|
||
class TokenUnauthorizedError(KongError): | ||
pass | ||
|
||
|
||
error_codes = { | ||
'unauthorized': AuthenticationError, | ||
'forbidden': AuthenticationError, | ||
'bad_request': BadRequestError, | ||
'action_forbidden': BadRequestError, | ||
'missing_parameter': BadRequestError, | ||
'parameter_invalid': BadRequestError, | ||
'parameter_not_found': BadRequestError, | ||
'not_found': ResourceNotFound, | ||
'service_unavailable': ServiceUnavailableError, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
from . import errors | ||
|
||
import certifi | ||
import json | ||
import logging | ||
import os | ||
import requests | ||
|
||
logger = logging.getLogger('kong.request') | ||
|
||
|
||
def configure_timeout(): | ||
"""Configure the request timeout.""" | ||
timeout = os.getenv('KONG_REQUEST_TIMEOUT', '90') | ||
try: | ||
return int(timeout) | ||
except ValueError: | ||
logger.warning('%s is not a valid timeout value.', timeout) | ||
return 90 | ||
|
||
|
||
class Request(object): | ||
|
||
timeout = configure_timeout() | ||
|
||
def __init__(self, http_method, path, http_session=None): | ||
self.http_method = http_method | ||
self.path = path | ||
self.http_session = http_session | ||
|
||
def execute(self, base_url, auth, params): | ||
return self.send_request_to_path(base_url, auth, params) | ||
|
||
def send_request_to_path(self, base_url, auth, params=None): | ||
""" Construct an API request, send it to the API, and parse the | ||
response. """ | ||
from . import __version__ | ||
req_params = {} | ||
|
||
if auth: | ||
req_params['auth'] = auth | ||
|
||
# full URL | ||
url = base_url + self.path | ||
|
||
headers = { | ||
'User-Agent': 'python-kong/' + __version__, | ||
'AcceptEncoding': 'gzip, deflate', | ||
'Accept': 'application/json', | ||
} | ||
|
||
if self.http_method in ('POST', 'PUT', 'DELETE'): | ||
headers['content-type'] = 'application/json' | ||
req_params['data'] = json.dumps(params, cls=ResourceEncoder) | ||
elif self.http_method == 'GET': | ||
req_params['params'] = params | ||
req_params['headers'] = headers | ||
|
||
# request logging | ||
if logger.isEnabledFor(logging.DEBUG): | ||
logger.debug("Sending %s request to: %s", self.http_method, url) | ||
logger.debug(" headers: %s", headers) | ||
if self.http_method == 'GET': | ||
logger.debug(" params: %s", req_params['params']) | ||
else: | ||
logger.debug(" params: %s", req_params['data']) | ||
|
||
if self.http_session is None: | ||
resp = requests.request( | ||
self.http_method, url, timeout=self.timeout, | ||
verify=certifi.where(), **req_params) | ||
else: | ||
resp = self.http_session.request( | ||
self.http_method, url, timeout=self.timeout, verify=certifi.where(), **req_params) | ||
|
||
# response logging | ||
if logger.isEnabledFor(logging.DEBUG): | ||
logger.debug("Response received from %s", url) | ||
logger.debug(" encoding=%s status:%s", | ||
resp.encoding, resp.status_code) | ||
logger.debug(" content:\n%s", resp.content) | ||
|
||
parsed_body = self.parse_body(resp) | ||
self.raise_errors_on_failure(resp) | ||
return parsed_body | ||
|
||
def parse_body(self, resp): | ||
if resp.content and resp.content.strip(): | ||
try: | ||
# use supplied or inferred encoding to decode the | ||
# response content | ||
decoded_body = resp.content.decode( | ||
resp.encoding or resp.apparent_encoding) | ||
body = json.loads(decoded_body) | ||
#if body.get('type') == 'error.list': | ||
# self.raise_application_errors_on_failure(body, resp.status_code) # noqa | ||
return body | ||
except ValueError: | ||
self.raise_errors_on_failure(resp) | ||
|
||
def raise_errors_on_failure(self, resp): | ||
if resp.status_code == 404: | ||
raise errors.ResourceNotFound('Resource Not Found') | ||
elif resp.status_code == 401: | ||
raise errors.AuthenticationError('Unauthorized') | ||
elif resp.status_code == 403: | ||
raise errors.AuthenticationError('Forbidden') | ||
elif resp.status_code == 500: | ||
raise errors.ServerError('Server Error') | ||
elif resp.status_code == 502: | ||
raise errors.BadGatewayError('Bad Gateway Error') | ||
elif resp.status_code == 503: | ||
raise errors.ServiceUnavailableError('Service Unavailable') | ||
|
||
def raise_application_errors_on_failure(self, error_list_details, http_code): # noqa | ||
# Currently, we don't support multiple errors | ||
error_details = error_list_details['errors'][0] | ||
error_code = error_details.get('type') | ||
if error_code is None: | ||
error_code = error_details.get('code') | ||
error_context = { | ||
'http_code': http_code, | ||
'application_error_code': error_code | ||
} | ||
error_class = errors.error_codes.get(error_code) | ||
if error_class is None: | ||
# unexpected error | ||
if error_code: | ||
message = self.message_for_unexpected_error_with_type( | ||
error_details, http_code) | ||
else: | ||
message = self.message_for_unexpected_error_without_type( | ||
error_details, http_code) | ||
error_class = errors.UnexpectedError | ||
else: | ||
message = error_details.get('message') | ||
raise error_class(message, error_context) | ||
|
||
def message_for_unexpected_error_with_type(self, error_details, http_code): # noqa | ||
error_type = error_details.get('type') | ||
message = error_details.get('message') | ||
return "The error of type '%s' is not recognized. It occurred with the message: %s and http_code: '%s'. Please contact Kong with these details." % (error_type, message, http_code) # noqa | ||
|
||
def message_for_unexpected_error_without_type(self, error_details, http_code): # noqa | ||
message = error_details['message'] | ||
return "An unexpected error occured. It occurred with the message: %s and http_code: '%s'. Please contact Kong with these details." % (message, http_code) # noqa | ||
|
||
|
||
class ResourceEncoder(json.JSONEncoder): | ||
def default(self, o): | ||
if hasattr(o, 'attributes'): | ||
# handle API resources | ||
return o.attributes | ||
return super(ResourceEncoder, self).default(o) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
|
||
class BaseService(object): | ||
|
||
def __init__(self, client): | ||
self.client = client |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from .base_service import BaseService | ||
from kong.errors import KongError | ||
|
||
|
||
class Status(BaseService): | ||
def get(self): | ||
""" | ||
:return: | ||
""" | ||
response = self.client.get('status/') | ||
return response |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[pytest] | ||
testpaths = tests |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,4 +19,5 @@ exclude = docs | |
|
||
[aliases] | ||
test = pytest | ||
# Define setup.py command aliases here | ||
unit = pytest te | ||
|
Oops, something went wrong.