Merge "add cyborg-api v1 & hooks"

This commit is contained in:
Jenkins 2017-08-18 14:36:59 +00:00 committed by Gerrit Code Review
commit 55e0b2bcb7
7 changed files with 186 additions and 2 deletions

View File

@ -16,6 +16,7 @@
import pecan
from cyborg.api import config
from cyborg.api import hooks
from cyborg.api import middleware
@ -26,7 +27,8 @@ def get_pecan_config():
def setup_app(pecan_config=None, extra_hooks=None):
app_hooks = []
app_hooks = [hooks.ConfigHook(),
hooks.PublicUrlHook()]
if extra_hooks:
app_hooks.extend(extra_hooks)
@ -45,3 +47,12 @@ def setup_app(pecan_config=None, extra_hooks=None):
)
return app
class VersionSelectorApplication(object):
def __init__(self):
pc = get_pecan_config()
self.v1 = setup_app(pecan_config=pc)
def __call__(self, environ, start_response):
return self.v1(environ, start_response)

View File

@ -0,0 +1,48 @@
# Copyright 2017 Huawei Technologies Co.,LTD.
# 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 pecan
from wsme import types as wtypes
from cyborg.api.controllers import base
def build_url(resource, resource_args, bookmark=False, base_url=None):
if base_url is None:
base_url = pecan.request.public_url
template = '%(url)s/%(res)s' if bookmark else '%(url)s/v1/%(res)s'
template += '%(args)s' if resource_args.startswith('?') else '/%(args)s'
return template % {'url': base_url, 'res': resource, 'args': resource_args}
class Link(base.APIBase):
"""A link representation."""
href = wtypes.text
"""The url of a link."""
rel = wtypes.text
"""The name of a link."""
type = wtypes.text
"""Indicates the type of document/link."""
@staticmethod
def make_link(rel_name, url, resource, resource_args,
bookmark=False, type=wtypes.Unset):
href = build_url(resource, resource_args,
bookmark=bookmark, base_url=url)
return Link(href=href, rel=rel_name, type=type)

View File

@ -13,13 +13,18 @@
# License for the specific language governing permissions and limitations
# under the License.
import pecan
from pecan import rest
from wsme import types as wtypes
from cyborg.api.controllers import base
from cyborg.api.controllers import v1
from cyborg.api import expose
VERSION1 = 'v1'
class Root(base.APIBase):
name = wtypes.text
"""The name of the API"""
@ -42,6 +47,26 @@ class Root(base.APIBase):
class RootController(rest.RestController):
_versions = [VERSION1]
"""All supported API versions"""
_default_version = VERSION1
"""The default API version"""
v1 = v1.Controller()
@expose.expose(Root)
def get(self):
return Root.convert()
@pecan.expose()
def _route(self, args, request=None):
"""Overrides the default routing behavior.
It redirects the request to the default version of the cyborg API
if the version number is not specified in the url.
"""
if args[0] and args[0] not in self._versions:
args = [self._default_version] + args
return super(RootController, self)._route(args)

View File

@ -0,0 +1,57 @@
# Copyright 2017 Huawei Technologies Co.,LTD.
# 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.
"""Version 1 of the Cyborg API"""
import pecan
from pecan import rest
from wsme import types as wtypes
from cyborg.api.controllers import base
from cyborg.api.controllers import link
from cyborg.api import expose
class V1(base.APIBase):
"""The representation of the version 1 of the API."""
id = wtypes.text
"""The ID of the version"""
accelerator = [link.Link]
"""Links to the accelerator resource"""
@staticmethod
def convert():
v1 = V1()
v1.id = 'v1'
v1.accelerator = [
link.Link.make_link('self', pecan.request.public_url,
'accelerator', ''),
link.Link.make_link('bookmark', pecan.request.public_url,
'accelerator', '', bookmark=True)
]
return v1
class Controller(rest.RestController):
"""Version 1 API controller root"""
@expose.expose(V1)
def get(self):
return V1.convert()
__all__ = ('Controller',)

36
cyborg/api/hooks.py Normal file
View File

@ -0,0 +1,36 @@
# Copyright 2017 Huawei Technologies Co.,LTD.
# 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 oslo_config import cfg
from pecan import hooks
class ConfigHook(hooks.PecanHook):
"""Attach the config object to the request so controllers can get to it."""
def before(self, state):
state.request.cfg = cfg.CONF
class PublicUrlHook(hooks.PecanHook):
"""Attach the right public_url to the request.
Attach the right public_url to the request so resources can create
links even when the API service is behind a proxy or SSL terminator.
"""
def before(self, state):
state.request.public_url = (
cfg.CONF.api.public_endpoint or state.request.host_url)

View File

@ -56,7 +56,7 @@ class WSGIService(service.ServiceBase):
:returns: None
"""
self.name = name
self.app = app.setup_app()
self.app = app.VersionSelectorApplication()
self.workers = (CONF.api.api_workers or
processutils.get_worker_count())
if self.workers and self.workers < 1:

View File

@ -38,6 +38,13 @@ opts = [
"the service, this option should be False; note, you "
"will want to change public API endpoint to represent "
"SSL termination URL with 'public_endpoint' option.")),
cfg.StrOpt('public_endpoint',
help=_("Public URL to use when building the links to the API "
"resources (for example, \"https://cyborg.rocks:6666\")."
" If None the links will be built using the request's "
"host URL. If the API is operating behind a proxy, you "
"will want to change this to represent the proxy's URL. "
"Defaults to None.")),
]
opt_group = cfg.OptGroup(name='api',