Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ python:
- "3.7-dev" # 3.7 development branch
# command to install dependencies
install:
- pip install -r requirements.txt
- pip install .[tests]
- npm install
script:
- ./scripts/tests.sh
Expand Down
4 changes: 4 additions & 0 deletions kong/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
class SchemaViolation(Exception):
pass


class ObjectNotFound(Exception):
pass
39 changes: 33 additions & 6 deletions kong/kong_clients.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import logging
from abc import abstractmethod

from urllib3.util.url import Url, parse_url
from requests import session
from kong.structures import ApiData, ServiceData, ConsumerData, \
PluginData, RouteData, TargetData, UpstreamData
from kong.exceptions import SchemaViolation
from kong.exceptions import SchemaViolation, ObjectNotFound

logger = logging.getLogger(__name__)


class RestClient: # pylint:disable=too-few-public-methods
Expand Down Expand Up @@ -68,6 +72,19 @@ def _to_object_data(self, data_dict):
def _to_list_object_data(self, list_data_dict):
return map(self._to_object_data, list_data_dict)

def update_or_create(self, **kwargs):
pk_or_id = kwargs.pop(self._object_data_class.pk_identifier, None) or kwargs.get("name")

try:
data_dict = self._perform_retrieve(pk_or_id)
pk_or_id = data_dict.get(self._object_data_class.pk_identifier)
except ObjectNotFound:
return self.create(**kwargs), True

self.update(pk_or_id, **kwargs)

return self._to_object_data(data_dict), False

def create(self, **kwargs):
data_dict = self._perform_create(**kwargs)
return self._to_object_data(data_dict)
Expand Down Expand Up @@ -177,6 +194,9 @@ def _send_retrieve(self, name_or_id, endpoint=None):
response = self.session.get(url)

if response.status_code == 404:
if response.json().get('message') == "Not found":
raise ObjectNotFound(response.content)

raise NameError(response.content)

if response.status_code != 200:
Expand All @@ -188,7 +208,7 @@ def _validate_params(self, query_params, allowed_params):
validated_params = {}
for k, val in query_params.items():
if k in allowed_params:
validated_params[k] = self._stringify_if_list(val)
validated_params[k] = val # self._stringify_if_list(val)
else:
raise KeyError('invalid query parameter: %s' % k)
return validated_params
Expand Down Expand Up @@ -409,11 +429,11 @@ def _object_data_class(self):
def _allowed_update_params(self):
return 'name', 'protocol', 'host', 'port', 'path', \
'retries', 'connect_timeout', 'send_timeout', \
'read_timeout', 'url'
'read_timeout', 'url', "tags"

@property
def _allowed_query_params(self):
return []
return ["tags"]

@property
def _path(self):
Expand All @@ -432,9 +452,9 @@ def _object_data_class(self):

@property
def _allowed_update_params(self):
return 'protocols', 'methods', 'hosts',\
return 'name', 'protocols', 'methods', 'hosts',\
'paths', 'strip_path', 'preserve_host',\
'service',
'service', 'tags'

@property
def _allowed_query_params(self):
Expand All @@ -444,6 +464,13 @@ def _allowed_query_params(self):
def _path(self):
return 'routes/'

# pylint: disable=arguments-differ
def _perform_update(self, pk_or_id, **kwargs):
if 'service' in kwargs.keys():
kwargs['service'] = {"id": self.get_service_id(kwargs['service'])}

return super(RouteAdminClient, self)._perform_update(pk_or_id, **kwargs)

# pylint: disable=arguments-differ
def _perform_create(self, service, **kwargs):

Expand Down
11 changes: 7 additions & 4 deletions kong/structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ def __normalize_uri(uri):


class ServiceData(ObjectData):
pk_identifier = 'id'

def validate_semi_optional_parameters(self, **kwargs):
pass
Expand Down Expand Up @@ -128,7 +129,7 @@ def allowed_parameters(self):
return 'name', 'protocol', 'host', 'port', 'path',\
'retries', 'connect_timeout', 'send_timeout',\
'read_timeout', 'url', 'id', \
'created_at', 'updated_at', 'write_timeout'
'created_at', 'updated_at', 'write_timeout', 'tags'

@property
def url(self):
Expand Down Expand Up @@ -156,7 +157,7 @@ def validate_obligatory_parameters(self, **kwargs):

@property
def allowed_parameters(self):
return "id", "username", "custom_id", "created_at"
return "id", "username", "custom_id", "created_at", "tags"

def validate_semi_optional_parameters(self, **kwargs):
if ("username" not in kwargs) and ("custom_id" not in kwargs):
Expand All @@ -166,6 +167,7 @@ def validate_semi_optional_parameters(self, **kwargs):


class RouteData(ObjectData):
pk_identifier = 'id'

def validate_semi_optional_parameters(self, **kwargs):
if not ('hosts' in kwargs
Expand All @@ -178,10 +180,11 @@ def validate_obligatory_parameters(self, **kwargs):

@property
def allowed_parameters(self):
return "id", "created_at", "updated_at", \
return "name", "id", "created_at", "updated_at", \
"protocols", "methods", "hosts", \
"paths", "regex_priority", "strip_path", \
"preserve_host", "service"
"preserve_host", "service", "snis", "sources", \
"destinations", "tags"


class TargetData(ObjectData):
Expand Down
2 changes: 0 additions & 2 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
[pytest]
DJANGO_SETTINGS_MODULE = conf.settings.testing

python_files = tests.py test_*.py *_tests.py
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Supported Information Routes
- node_information

Supported operations for Services, Routes, Apis, Consumers, Plugins and Upstreams
- update_or_create
- create
- delete
- retrieve
Expand All @@ -33,7 +34,6 @@ Additional supported operations for Targets
- set_healthy

Not supported
- update_or_create
- count (dropped in 0.16/kong 0.13.0)
- Certificates object routes (yet)
- SNI object routes (yet)
Expand Down
1 change: 0 additions & 1 deletion requirements.txt

This file was deleted.

4 changes: 4 additions & 0 deletions requirements/testing.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
flake8 # This covers pycodestyle
pylint
pytest
Faker
24 changes: 21 additions & 3 deletions requirements/testing.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
-r base.txt
flake8==3.5.0 # This covers pycodestyle
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile ./testing.in
#
astroid==1.6.6 # via pylint
attrs==19.1.0 # via pytest
faker==1.0.5
flake8==3.5.0
isort==4.3.17 # via pylint
lazy-object-proxy==1.3.1 # via astroid
mccabe==0.6.1 # via flake8, pylint
pluggy==0.6.0 # via pytest
py==1.8.0 # via pytest
pycodestyle==2.3.1 # via flake8
pyflakes==1.6.0 # via flake8
pylint==1.8.2
pytest==3.4.0
Faker==0.8.10
python-dateutil==2.8.0 # via faker
six==1.12.0 # via astroid, faker, pylint, pytest, python-dateutil
text-unidecode==1.2 # via faker
wrapt==1.11.1 # via astroid
16 changes: 10 additions & 6 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
from os.path import dirname
from os.path import join

from pip.req import parse_requirements

from pip._internal.req import parse_requirements
from setuptools import setup

__version__ = '0.1.7'
Expand All @@ -19,9 +18,12 @@ def read(*names, **kwargs):
).read()


# parse_requirements() returns generator of pip.req.InstallRequirement objects
requirements = [str(ir.req) for ir in parse_requirements(os.path.join(BASE_DIR, './requirements/base.txt'), session=False)]
# requirements_test = [str(ir.req) for ir in parse_requirements('./requirements-test.txt', session=False)]
with open(os.path.join(BASE_DIR, 'requirements', 'base.txt')) as f:
requirements = f.read().splitlines()

with open(os.path.join(BASE_DIR, 'requirements', 'testing.txt')) as f:
requirements_test = f.read().splitlines()


setup(
name='python-kong-client',
Expand All @@ -43,5 +45,7 @@ def read(*names, **kwargs):
],
keywords=[],
install_requires=requirements,
extras_require={},
extras_require={
"tests": requirements_test
},
)