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
16 changes: 8 additions & 8 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
pbr==5.1.1
webob==1.8.4
six==1.12.0
SQLAlchemy==1.0.13
requests==2.20.0
pbr==1.8.1
webob==1.6.1
six==1.10.0
SQLAlchemy==1.0.11
requests==2.6.0
mysql-connector==2.1.3
oslo.config==6.7.0
-e git+https://github.com/phantomii/bazooka.git@0.0.3#egg=bazooka
-e git+https://github.com/phantomii/pyretries.git@0.0.3#egg=pyretries
oslo.config==3.22.0
-e git+https://github.com/phantomii/bazooka.git@centos-req#egg=bazooka
-e git+https://github.com/phantomii/pyretries.git@centos-req#egg=pyretries
19 changes: 16 additions & 3 deletions restalchemy/api/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,20 @@ def get_locator(cls, uri):
@classmethod
def get_resource(cls, request, uri):
resource_locator = cls.get_locator(uri)
return resource_locator.get_resource(request, uri)

# has parent resource?
pstack = resource_locator.path_stack
parent_resource = None

for pice in reversed(pstack[:-1]):
if not isinstance(pice, six.string_types):
parent_uri = '/'.join(uri.split('/')[:pstack.index(pice) + 2])
parent_locator = cls.get_locator(parent_uri)
parent_resource = parent_locator.get_resource(
request, parent_uri)
break

return resource_locator.get_resource(request, uri, parent_resource)

@classmethod
def set_resource_map(cls, resource_map):
Expand Down Expand Up @@ -174,8 +187,8 @@ def get_resource_field_name(self, model_field_name):
return name.replace('_', '-') if self._convert_underscore else name

def is_public_field(self, model_field_name):
return not (model_field_name.startswith('_') or
model_field_name in self._hidden_model_fields)
return not (model_field_name.startswith('_')
or model_field_name in self._hidden_model_fields)

def get_model(self):
return self._model_class
Expand Down
7 changes: 6 additions & 1 deletion restalchemy/api/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,13 @@ def get_uri(self, model):
# FIXME(Eugene Frolov): Header must be string. Not unicode.
return str(posixpath.join('/', path))

def get_resource(self, request, uri):
def get_resource(self, request, uri, parent_resource=None):
uuid = posixpath.basename(uri)
if parent_resource:
return (self._controller(request=request)
.get_resource_by_uuid(
uuid=uuid,
parent_resource=parent_resource))
return self._controller(request=request).get_resource_by_uuid(
uuid)

Expand Down
Empty file.
85 changes: 85 additions & 0 deletions restalchemy/storage/rest/contexts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2018 Mail.ru Group
#
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import bazooka

from restalchemy.storage.rest import utils


class Context(object):

def __init__(self, request_id=None, request_id_header_name=None,
enable_cache=False):
super(Context, self).__init__()
self._http_client = {}
self._request_id = request_id
self._request_id_header_name = (
request_id_header_name or 'correlation-id')
self._cache = {}
self._enable_cache = enable_cache

def _get_client(self, endpoint):
if endpoint in self._http_client:
return self._http_client[endpoint]
cli = bazooka.Client(
correlation_id=self._request_id,
correlation_id_header_name=self._request_id_header_name)
self._http_client[endpoint] = cli
return cli

def make_post_request(self, endpoint, uri, params):
cli = self._get_client(endpoint)
url = utils.build_collection_uri(endpoint, uri)
response = cli.post(url, json=params)
response_dict = response.json()
if self._enable_cache:
location = response.headers['Location']
self._cache[location] = response_dict
return response_dict

def make_put_request(self, endpoint, uri, params):
cli = self._get_client(endpoint)
url = utils.build_resource_uri(endpoint, uri)
response = cli.put(url, json=params)
response_dict = response.json()
if self._enable_cache:
self._cache[url] = response_dict
return response_dict

def make_list_request(self, endpoint, uri, params):
cli = self._get_client(endpoint)
url = utils.build_collection_uri(endpoint, uri)
response = cli.get(url, params=params)
response_dict = response.json()
return response_dict

def make_get_request(self, endpoint, uri, params):
url = utils.build_resource_uri(endpoint, uri)
if self._enable_cache and url in self._cache:
return self._cache[url]
cli = self._get_client(endpoint)
response = cli.get(url, params=params)
response_dict = response.json()
if self._enable_cache:
self._cache[url] = response_dict
return response_dict

def make_delete_request(self, endpoint, uri):
url = utils.build_resource_uri(endpoint, uri)
self._get_client(endpoint).delete(url)
self._cache.pop(url, None)
74 changes: 74 additions & 0 deletions restalchemy/storage/rest/engines.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2018 Mail.ru Group
#
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

from restalchemy.common import singletons


class RESTEngine(object):

def __init__(self, api_endpoint, config=None):
super(RESTEngine, self).__init__()
self._api_endpoint = api_endpoint
self._config = config or {}

def post(self, uri, params, context):
return context.make_post_request(self._api_endpoint, uri, params)

def put(self, uri, params, context):
return context.make_put_request(self._api_endpoint, uri, params)

def list(self, uri, params, context):
return context.make_list_request(self._api_endpoint, uri, params)

def get(self, uri, params, context):
return context.make_get_request(self._api_endpoint, uri, params)

def delete(self, uri, context):
return context.make_delete_request(self._api_endpoint, uri)


class EngineFactory(singletons.InheritSingleton):

def __init__(self):
super(EngineFactory, self).__init__()
self._engine = None
self._engines_map = {
'http': RESTEngine,
'https': RESTEngine
}

def configure_factory(self, api_endpoint, config=None):
"""Configure_factory

@property db_url: str. For example driver://user:passwd@host:port/db
"""
schema = api_endpoint.split(':')[0]
try:
self._engine = self._engines_map[schema.lower()](api_endpoint,
config)
except KeyError:
raise ValueError("Can not find driver for schema %s" % schema)

def get_engine(self):
if self._engine:
return self._engine
raise ValueError("Can not return engine. Please configure "
"EngineFactory")


engine_factory = EngineFactory()
Loading