rename neutron/api to tacker/api

Change-Id: I7dd1c76e2df0aefa618ba28064ce9100f1e0c651
This commit is contained in:
Isaku Yamahata 2014-06-26 17:08:54 +09:00
parent ea44fc81bc
commit 70be577f35
13 changed files with 135 additions and 478 deletions

View File

@ -1,115 +0,0 @@
# Copyright (c) 2012 OpenStack Foundation.
#
# 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
import routes as routes_mapper
import six.moves.urllib.parse as urlparse
import webob
import webob.dec
import webob.exc
from neutron.api import extensions
from neutron.api.v2 import attributes
from neutron.api.v2 import base
from neutron import manager
from neutron.openstack.common import log as logging
from neutron import wsgi
LOG = logging.getLogger(__name__)
RESOURCES = {'network': 'networks',
'subnet': 'subnets',
'port': 'ports'}
SUB_RESOURCES = {}
COLLECTION_ACTIONS = ['index', 'create']
MEMBER_ACTIONS = ['show', 'update', 'delete']
REQUIREMENTS = {'id': attributes.UUID_PATTERN, 'format': 'xml|json'}
class Index(wsgi.Application):
def __init__(self, resources):
self.resources = resources
@webob.dec.wsgify(RequestClass=wsgi.Request)
def __call__(self, req):
metadata = {'application/xml': {'attributes': {
'resource': ['name', 'collection'],
'link': ['href', 'rel']}}}
layout = []
for name, collection in self.resources.iteritems():
href = urlparse.urljoin(req.path_url, collection)
resource = {'name': name,
'collection': collection,
'links': [{'rel': 'self',
'href': href}]}
layout.append(resource)
response = dict(resources=layout)
content_type = req.best_match_content_type()
body = wsgi.Serializer(metadata=metadata).serialize(response,
content_type)
return webob.Response(body=body, content_type=content_type)
class APIRouter(wsgi.Router):
@classmethod
def factory(cls, global_config, **local_config):
return cls(**local_config)
def __init__(self, **local_config):
mapper = routes_mapper.Mapper()
plugin = manager.NeutronManager.get_plugin()
ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
ext_mgr.extend_resources("2.0", attributes.RESOURCE_ATTRIBUTE_MAP)
col_kwargs = dict(collection_actions=COLLECTION_ACTIONS,
member_actions=MEMBER_ACTIONS)
def _map_resource(collection, resource, params, parent=None):
allow_bulk = cfg.CONF.allow_bulk
allow_pagination = cfg.CONF.allow_pagination
allow_sorting = cfg.CONF.allow_sorting
controller = base.create_resource(
collection, resource, plugin, params, allow_bulk=allow_bulk,
parent=parent, allow_pagination=allow_pagination,
allow_sorting=allow_sorting)
path_prefix = None
if parent:
path_prefix = "/%s/{%s_id}/%s" % (parent['collection_name'],
parent['member_name'],
collection)
mapper_kwargs = dict(controller=controller,
requirements=REQUIREMENTS,
path_prefix=path_prefix,
**col_kwargs)
return mapper.collection(collection, resource,
**mapper_kwargs)
mapper.connect('index', '/', controller=Index(RESOURCES))
for resource in RESOURCES:
_map_resource(RESOURCES[resource], resource,
attributes.RESOURCE_ATTRIBUTE_MAP.get(
RESOURCES[resource], dict()))
for resource in SUB_RESOURCES:
_map_resource(SUB_RESOURCES[resource]['collection_name'], resource,
attributes.RESOURCE_ATTRIBUTE_MAP.get(
SUB_RESOURCES[resource]['collection_name'],
dict()),
SUB_RESOURCES[resource]['parent'])
super(APIRouter, self).__init__(mapper)

View File

@ -18,9 +18,9 @@ import urllib
from oslo.config import cfg
from webob import exc
from neutron.common import constants
from neutron.common import exceptions
from neutron.openstack.common import log as logging
from tacker.common import constants
from tacker.common import exceptions
from tacker.openstack.common import log as logging
LOG = logging.getLogger(__name__)
@ -290,14 +290,14 @@ class NoSortingHelper(SortingHelper):
pass
class NeutronController(object):
"""Base controller class for Neutron API."""
class TackerController(object):
"""Base controller class for Tacker API."""
# _resource_name will be redefined in sub concrete controller
_resource_name = None
def __init__(self, plugin):
self._plugin = plugin
super(NeutronController, self).__init__()
super(TackerController, self).__init__()
def _prepare_request_body(self, body, params):
"""Verifies required parameters are in request body.

View File

@ -16,7 +16,6 @@
import abc
import imp
import itertools
import os
from oslo.config import cfg
@ -25,13 +24,12 @@ import six
import webob.dec
import webob.exc
from neutron.api.v2 import attributes
from neutron.common import exceptions
import neutron.extensions
from neutron import manager
from neutron.openstack.common import log as logging
from neutron import policy
from neutron import wsgi
from tacker.api.v1 import attributes
from tacker.common import exceptions
import tacker.extensions
from tacker.openstack.common import log as logging
from tacker import policy
from tacker import wsgi
LOG = logging.getLogger(__name__)
@ -384,10 +382,10 @@ class ExtensionMiddleware(wsgi.Middleware):
return app
def plugin_aware_extension_middleware_factory(global_config, **local_config):
def extension_middleware_factory(global_config, **local_config):
"""Paste factory."""
def _factory(app):
ext_mgr = PluginAwareExtensionManager.get_instance()
ext_mgr = ExtensionManager.get_instance()
return ExtensionMiddleware(app, ext_mgr=ext_mgr)
return _factory
@ -399,6 +397,14 @@ class ExtensionManager(object):
example extension implementation.
"""
_instance = None
@classmethod
def get_instance(cls):
if cls._instance is None:
cls._instance = cls(get_extensions_path())
return cls._instance
def __init__(self, path):
LOG.info(_('Initializing extension manager.'))
self.path = path
@ -539,7 +545,7 @@ class ExtensionManager(object):
def _load_all_extensions_from_path(self, path):
# Sorting the extension list makes the order in which they
# are loaded predictable across a cluster of load-balanced
# Neutron Servers
# Tacker Servers
for f in sorted(os.listdir(path)):
try:
LOG.debug(_('Loading extension file: %s'), f)
@ -574,68 +580,11 @@ class ExtensionManager(object):
self.extensions[alias] = ext
class PluginAwareExtensionManager(ExtensionManager):
_instance = None
def __init__(self, path, plugins):
self.plugins = plugins
super(PluginAwareExtensionManager, self).__init__(path)
self.check_if_plugin_extensions_loaded()
def _check_extension(self, extension):
"""Check if an extension is supported by any plugin."""
extension_is_valid = super(PluginAwareExtensionManager,
self)._check_extension(extension)
return (extension_is_valid and
self._plugins_support(extension) and
self._plugins_implement_interface(extension))
def _plugins_support(self, extension):
alias = extension.get_alias()
supports_extension = any((hasattr(plugin,
"supported_extension_aliases") and
alias in plugin.supported_extension_aliases)
for plugin in self.plugins.values())
if not supports_extension:
LOG.warn(_("Extension %s not supported by any of loaded plugins"),
alias)
return supports_extension
def _plugins_implement_interface(self, extension):
if(not hasattr(extension, "get_plugin_interface") or
extension.get_plugin_interface() is None):
return True
for plugin in self.plugins.values():
if isinstance(plugin, extension.get_plugin_interface()):
return True
LOG.warn(_("Loaded plugins do not implement extension %s interface"),
extension.get_alias())
return False
@classmethod
def get_instance(cls):
if cls._instance is None:
cls._instance = cls(get_extensions_path(),
manager.NeutronManager.get_service_plugins())
return cls._instance
def check_if_plugin_extensions_loaded(self):
"""Check if an extension supported by a plugin has been loaded."""
plugin_extensions = set(itertools.chain.from_iterable([
getattr(plugin, "supported_extension_aliases", [])
for plugin in self.plugins.values()]))
missing_aliases = plugin_extensions - set(self.extensions)
if missing_aliases:
raise exceptions.ExtensionsNotFound(
extensions=list(missing_aliases))
class RequestExtension(object):
"""Extend requests and responses of core Neutron OpenStack API controllers.
"""Extend requests and responses of core Tacker OpenStack API controllers.
Provide a way to add data to responses and handle custom request data
that is sent to core Neutron OpenStack API controllers.
that is sent to core Tacker OpenStack API controllers.
"""
def __init__(self, method, url_route, handler):
@ -646,7 +595,7 @@ class RequestExtension(object):
class ActionExtension(object):
"""Add custom actions to core Neutron OpenStack API controllers."""
"""Add custom actions to core Tacker OpenStack API controllers."""
def __init__(self, collection, action_name, handler):
self.collection = collection
@ -655,7 +604,7 @@ class ActionExtension(object):
class ResourceExtension(object):
"""Add top level resources to the OpenStack API in Neutron."""
"""Add top level resources to the OpenStack API in Tacker."""
def __init__(self, collection, controller, parent=None, path_prefix="",
collection_actions={}, member_actions={}, attr_map={}):
@ -669,9 +618,9 @@ class ResourceExtension(object):
# Returns the extension paths from a config entry and the __path__
# of neutron.extensions
# of tacker.extensions
def get_extensions_path():
paths = ':'.join(neutron.extensions.__path__)
paths = ':'.join(tacker.extensions.__path__)
if cfg.CONF.api_extensions_path:
paths = ':'.join([cfg.CONF.api_extensions_path, paths])

View File

@ -18,10 +18,10 @@
import netaddr
import re
from neutron.common import constants
from neutron.common import exceptions as n_exc
from neutron.openstack.common import log as logging
from neutron.openstack.common import uuidutils
from tacker.common import constants
from tacker.common import exceptions as n_exc
from tacker.openstack.common import log as logging
from tacker.openstack.common import uuidutils
LOG = logging.getLogger(__name__)
@ -580,12 +580,7 @@ validators = {'type:dict': _validate_dict,
'type:boolean': _validate_boolean}
# Define constants for base resource name
NETWORK = 'network'
NETWORKS = '%ss' % NETWORK
PORT = 'port'
PORTS = '%ss' % PORT
SUBNET = 'subnet'
SUBNETS = '%ss' % SUBNET
# Note: a default of ATTR_NOT_SPECIFIED indicates that an
# attribute is not required, but will be generated by the plugin
# if it is not specified. Particularly, a value of ATTR_NOT_SPECIFIED
@ -609,156 +604,11 @@ SUBNETS = '%ss' % SUBNET
# enforce_policy: the attribute is actively part of the policy enforcing
# mechanism, ie: there might be rules which refer to this attribute.
RESOURCE_ATTRIBUTE_MAP = {
NETWORKS: {
'id': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid': None},
'is_visible': True,
'primary_key': True},
'name': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'default': '', 'is_visible': True},
'subnets': {'allow_post': False, 'allow_put': False,
'default': [],
'is_visible': True},
'admin_state_up': {'allow_post': True, 'allow_put': True,
'default': True,
'convert_to': convert_to_boolean,
'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True,
'is_visible': True},
SHARED: {'allow_post': True,
'allow_put': True,
'default': False,
'convert_to': convert_to_boolean,
'is_visible': True,
'required_by_policy': True,
'enforce_policy': True},
},
PORTS: {
'id': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid': None},
'is_visible': True,
'primary_key': True},
'name': {'allow_post': True, 'allow_put': True, 'default': '',
'validate': {'type:string': None},
'is_visible': True},
'network_id': {'allow_post': True, 'allow_put': False,
'required_by_policy': True,
'validate': {'type:uuid': None},
'is_visible': True},
'admin_state_up': {'allow_post': True, 'allow_put': True,
'default': True,
'convert_to': convert_to_boolean,
'is_visible': True},
'mac_address': {'allow_post': True, 'allow_put': False,
'default': ATTR_NOT_SPECIFIED,
'validate': {'type:mac_address': None},
'enforce_policy': True,
'is_visible': True},
'fixed_ips': {'allow_post': True, 'allow_put': True,
'default': ATTR_NOT_SPECIFIED,
'convert_list_to': convert_kvp_list_to_dict,
'validate': {'type:fixed_ips': None},
'enforce_policy': True,
'is_visible': True},
'device_id': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'default': '',
'is_visible': True},
'device_owner': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'default': '',
'is_visible': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True,
'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
},
SUBNETS: {
'id': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid': None},
'is_visible': True,
'primary_key': True},
'name': {'allow_post': True, 'allow_put': True, 'default': '',
'validate': {'type:string': None},
'is_visible': True},
'ip_version': {'allow_post': True, 'allow_put': False,
'convert_to': convert_to_int,
'validate': {'type:values': [4, 6]},
'is_visible': True},
'network_id': {'allow_post': True, 'allow_put': False,
'required_by_policy': True,
'validate': {'type:uuid': None},
'is_visible': True},
'cidr': {'allow_post': True, 'allow_put': False,
'validate': {'type:subnet': None},
'is_visible': True},
'gateway_ip': {'allow_post': True, 'allow_put': True,
'default': ATTR_NOT_SPECIFIED,
'validate': {'type:ip_address_or_none': None},
'is_visible': True},
'allocation_pools': {'allow_post': True, 'allow_put': True,
'default': ATTR_NOT_SPECIFIED,
'validate': {'type:ip_pools': None},
'is_visible': True},
'dns_nameservers': {'allow_post': True, 'allow_put': True,
'convert_to': convert_none_to_empty_list,
'default': ATTR_NOT_SPECIFIED,
'validate': {'type:nameservers': None},
'is_visible': True},
'host_routes': {'allow_post': True, 'allow_put': True,
'convert_to': convert_none_to_empty_list,
'default': ATTR_NOT_SPECIFIED,
'validate': {'type:hostroutes': None},
'is_visible': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True,
'is_visible': True},
'enable_dhcp': {'allow_post': True, 'allow_put': True,
'default': True,
'convert_to': convert_to_boolean,
'is_visible': True},
'ipv6_ra_mode': {'allow_post': True, 'allow_put': True,
'default': ATTR_NOT_SPECIFIED,
'validate': {'type:values': constants.IPV6_MODES},
'is_visible': True},
'ipv6_address_mode': {'allow_post': True, 'allow_put': True,
'default': ATTR_NOT_SPECIFIED,
'validate': {'type:values':
constants.IPV6_MODES},
'is_visible': True},
SHARED: {'allow_post': False,
'allow_put': False,
'default': False,
'convert_to': convert_to_boolean,
'is_visible': False,
'required_by_policy': True,
'enforce_policy': True},
}
}
# Identify the attribute used by a resource to reference another resource
RESOURCE_FOREIGN_KEYS = {
NETWORKS: 'network_id'
}
RESOURCE_ATTRIBUTE_MAP = {}
PLURALS = {NETWORKS: NETWORK,
PORTS: PORT,
SUBNETS: SUBNET,
'dns_nameservers': 'dns_nameserver',
'host_routes': 'host_route',
'allocation_pools': 'allocation_pool',
'fixed_ips': 'fixed_ip',
'extensions': 'extension'}
PLURALS = {'extensions': 'extension'}
EXT_NSES = {}
# Namespaces to be added for backward compatibility

View File

@ -15,22 +15,18 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
import netaddr
import webob.exc
from oslo.config import cfg
from neutron.api import api_common
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
from neutron.api.v2 import attributes
from neutron.api.v2 import resource as wsgi_resource
from neutron.common import constants as const
from neutron.common import exceptions
from neutron.common import rpc as n_rpc
from neutron.openstack.common import log as logging
from neutron import policy
from neutron import quota
from tacker.api import api_common
from tacker.api.v1 import attributes
from tacker.api.v1 import resource as wsgi_resource
from tacker.common import exceptions
from tacker.common import rpc as n_rpc
from tacker.openstack.common import log as logging
from tacker import policy
LOG = logging.getLogger(__name__)
@ -70,15 +66,9 @@ class Controller(object):
self._policy_attrs = [name for (name, info) in self._attr_info.items()
if info.get('required_by_policy')]
self._notifier = n_rpc.get_notifier('network')
# use plugin's dhcp notifier, if this is already instantiated
agent_notifiers = getattr(plugin, 'agent_notifiers', {})
self._dhcp_agent_notifier = (
agent_notifiers.get(const.AGENT_TYPE_DHCP) or
dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
)
if cfg.CONF.notify_nova_on_port_data_changes:
from neutron.notifiers import nova
self._nova_notifier = nova.Notifier()
# if cfg.CONF.notify_nova_on_port_data_changes:
# from tacker.notifiers import nova
# self._nova_notifier = nova.Notifier()
self._member_actions = member_actions
self._primary_key = self._get_primary_key()
if self._allow_pagination and self._native_pagination:
@ -153,7 +143,7 @@ class Controller(object):
def _view(self, context, data, fields_to_strip=None):
"""Build a view of an API resource.
:param context: the neutron context
:param context: the tacker context
:param data: the object for which a view is being created
:param fields_to_strip: attributes to remove from the view
@ -288,19 +278,6 @@ class Controller(object):
policy.enforce(request.context, action, obj)
return obj
def _send_dhcp_notification(self, context, data, methodname):
if cfg.CONF.dhcp_agent_notification:
if self._collection in data:
for body in data[self._collection]:
item = {self._resource: body}
self._dhcp_agent_notifier.notify(context, item, methodname)
else:
self._dhcp_agent_notifier.notify(context, data, methodname)
def _send_nova_notification(self, action, orig, returned):
if hasattr(self, '_nova_notifier'):
self._nova_notifier.send_network_change(action, orig, returned)
def index(self, request, **kwargs):
"""Returns a list of the requested entity."""
parent_id = kwargs.get(self._parent_id_name)
@ -383,46 +360,20 @@ class Controller(object):
if self._collection in body:
# Have to account for bulk create
items = body[self._collection]
deltas = {}
bulk = True
else:
items = [body]
bulk = False
# Ensure policy engine is initialized
policy.init()
for item in items:
self._validate_network_tenant_ownership(request,
item[self._resource])
policy.enforce(request.context,
action,
item[self._resource])
try:
tenant_id = item[self._resource]['tenant_id']
count = quota.QUOTAS.count(request.context, self._resource,
self._plugin, self._collection,
tenant_id)
if bulk:
delta = deltas.get(tenant_id, 0) + 1
deltas[tenant_id] = delta
else:
delta = 1
kwargs = {self._resource: count + delta}
except exceptions.QuotaResourceUnknown as e:
# We don't want to quota this resource
LOG.debug(e)
else:
quota.QUOTAS.limit_check(request.context,
item[self._resource]['tenant_id'],
**kwargs)
def notify(create_result):
notifier_method = self._resource + '.create.end'
self._notifier.info(request.context,
notifier_method,
create_result)
self._send_dhcp_notification(request.context,
create_result,
notifier_method)
return create_result
kwargs = {self._parent_id_name: parent_id} if parent_id else {}
@ -447,8 +398,6 @@ class Controller(object):
else:
kwargs.update({self._resource: body})
obj = obj_creator(request.context, **kwargs)
self._send_nova_notification(action, {},
{self._resource: obj})
return notify({self._resource: self._view(request.context,
obj)})
@ -479,11 +428,6 @@ class Controller(object):
self._notifier.info(request.context,
notifier_method,
{self._resource + '_id': id})
result = {self._resource: self._view(request.context, obj)}
self._send_nova_notification(action, {}, result)
self._send_dhcp_notification(request.context,
result,
notifier_method)
def update(self, request, id, body=None, **kwargs):
"""Updates the specified entity's attributes."""
@ -512,7 +456,6 @@ class Controller(object):
policy.init()
orig_obj = self._item(request, id, field_list=field_list,
parent_id=parent_id)
orig_object_copy = copy.copy(orig_obj)
orig_obj.update(body[self._resource])
try:
policy.enforce(request.context,
@ -532,10 +475,6 @@ class Controller(object):
result = {self._resource: self._view(request.context, obj)}
notifier_method = self._resource + '.update.end'
self._notifier.info(request.context, notifier_method, result)
self._send_dhcp_notification(request.context,
result,
notifier_method)
self._send_nova_notification(action, orig_object_copy, result)
return result
@staticmethod
@ -644,29 +583,6 @@ class Controller(object):
msg = _("Unrecognized attribute(s) '%s'") % ', '.join(extra_keys)
raise webob.exc.HTTPBadRequest(msg)
def _validate_network_tenant_ownership(self, request, resource_item):
# TODO(salvatore-orlando): consider whether this check can be folded
# in the policy engine
if (request.context.is_admin or
self._resource not in ('port', 'subnet')):
return
network = self._plugin.get_network(
request.context,
resource_item['network_id'])
# do not perform the check on shared networks
if network.get('shared'):
return
network_owner = network['tenant_id']
if network_owner != resource_item['tenant_id']:
msg = _("Tenant %(tenant_id)s not allowed to "
"create %(resource)s on this network")
raise webob.exc.HTTPForbidden(msg % {
"tenant_id": resource_item['tenant_id'],
"resource": self._resource,
})
def create_resource(collection, resource, plugin, params, allow_bulk=False,
member_actions=None, parent=None, allow_pagination=False,

View File

@ -24,11 +24,11 @@ import six
import webob.dec
import webob.exc
from neutron.api.v2 import attributes
from neutron.common import exceptions
from neutron.openstack.common import gettextutils
from neutron.openstack.common import log as logging
from neutron import wsgi
from tacker.api.v1 import attributes
from tacker.common import exceptions
from tacker.openstack.common import gettextutils
from tacker.openstack.common import log as logging
from tacker import wsgi
LOG = logging.getLogger(__name__)
@ -85,7 +85,7 @@ def Resource(controller, faults=None, deserializers=None, serializers=None):
method = getattr(controller, action)
result = method(request=request, **args)
except (exceptions.NeutronException,
except (exceptions.TackerException,
netaddr.AddrFormatError) as e:
for fault in faults:
if isinstance(e, fault):
@ -99,17 +99,17 @@ def Resource(controller, faults=None, deserializers=None, serializers=None):
else:
LOG.exception(_('%s failed'), action)
e = translate(e, language)
# following structure is expected by python-neutronclient
# following structure is expected by python-tackerclient
err_data = {'type': e.__class__.__name__,
'message': e, 'detail': ''}
body = serializer.serialize({'NeutronError': err_data})
body = serializer.serialize({'TackerError': err_data})
kwargs = {'body': body, 'content_type': content_type}
raise mapped_exc(**kwargs)
except webob.exc.HTTPException as e:
type_, value, tb = sys.exc_info()
LOG.exception(_('%s failed'), action)
translate(e, language)
value.body = serializer.serialize({'NeutronError': e})
value.body = serializer.serialize({'TackerError': e})
value.content_type = content_type
six.reraise(type_, value, tb)
except NotImplementedError as e:
@ -131,7 +131,7 @@ def Resource(controller, faults=None, deserializers=None, serializers=None):
msg = _('Request Failed: internal server error while '
'processing your request.')
msg = translate(msg, language)
body = serializer.serialize({'NeutronError': msg})
body = serializer.serialize({'TackerError': msg})
kwargs = {'body': body, 'content_type': content_type}
raise webob.exc.HTTPInternalServerError(**kwargs)
@ -161,7 +161,7 @@ def translate(translatable, locale):
was not translated
"""
localize = gettextutils.translate
if isinstance(translatable, exceptions.NeutronException):
if isinstance(translatable, exceptions.TackerException):
translatable.msg = localize(translatable.msg, locale)
elif isinstance(translatable, webob.exc.HTTPError):
translatable.detail = localize(translatable.detail, locale)

View File

@ -16,11 +16,10 @@
from oslo.config import cfg
from neutron.api import extensions
from neutron.api.v2 import base
from neutron import manager
from neutron.plugins.common import constants
from neutron import quota
from tacker.api import extensions
from tacker.api.v1 import base
from tacker import manager
from tacker.plugins.common import constants
def build_plural_mappings(special_mappings, resource_map):
@ -38,7 +37,7 @@ def build_plural_mappings(special_mappings, resource_map):
def build_resource_info(plural_mappings, resource_map, which_service,
action_map=None, register_quota=False,
action_map=None,
translate_name=False, allow_bulk=False):
"""Build resources for advanced services.
@ -55,8 +54,6 @@ def build_resource_info(plural_mappings, resource_map, which_service,
It can be set to None or "CORE"to create WSGI
resources for the the core plugin
:param action_map: custom resource actions
:param register_quota: it can be set to True to register quotas for the
resource(s) being created
:param translate_name: replaces underscores with dashes
:param allow_bulk: True if bulk create are allowed
"""
@ -65,17 +62,12 @@ def build_resource_info(plural_mappings, resource_map, which_service,
which_service = constants.CORE
if action_map is None:
action_map = {}
if which_service != constants.CORE:
plugin = manager.NeutronManager.get_service_plugins()[which_service]
else:
plugin = manager.NeutronManager.get_plugin()
plugin = manager.TackerManager.get_service_plugins()[which_service]
for collection_name in resource_map:
resource_name = plural_mappings[collection_name]
params = resource_map.get(collection_name, {})
if translate_name:
collection_name = collection_name.replace('_', '-')
if register_quota:
quota.QUOTAS.register_resource_by_name(resource_name)
member_actions = action_map.get(resource_name, {})
controller = base.create_resource(
collection_name, resource_name, plugin, params,

65
tacker/api/v1/router.py Normal file
View File

@ -0,0 +1,65 @@
# Copyright (c) 2012 OpenStack Foundation.
#
# 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 routes as routes_mapper
import six.moves.urllib.parse as urlparse
import webob
import webob.dec
import webob.exc
from tacker.api import extensions
from tacker.api.v1 import attributes
from tacker.openstack.common import log as logging
from tacker import wsgi
LOG = logging.getLogger(__name__)
class Index(wsgi.Application):
def __init__(self, resources):
self.resources = resources
@webob.dec.wsgify(RequestClass=wsgi.Request)
def __call__(self, req):
metadata = {'application/xml': {'attributes': {
'resource': ['name', 'collection'],
'link': ['href', 'rel']}}}
layout = []
for name, collection in self.resources.iteritems():
href = urlparse.urljoin(req.path_url, collection)
resource = {'name': name,
'collection': collection,
'links': [{'rel': 'self',
'href': href}]}
layout.append(resource)
response = dict(resources=layout)
content_type = req.best_match_content_type()
body = wsgi.Serializer(metadata=metadata).serialize(response,
content_type)
return webob.Response(body=body, content_type=content_type)
class APIRouter(wsgi.Router):
@classmethod
def factory(cls, global_config, **local_config):
return cls(**local_config)
def __init__(self, **local_config):
mapper = routes_mapper.Mapper()
ext_mgr = extensions.ExtensionManager.get_instance()
ext_mgr.extend_resources("1.0", attributes.RESOURCE_ATTRIBUTE_MAP)
super(APIRouter, self).__init__(mapper)

View File

@ -15,10 +15,10 @@
import webob.dec
from neutron.api.views import versions as versions_view
from neutron.openstack.common import gettextutils
from neutron.openstack.common import log as logging
from neutron import wsgi
from tacker.api.views import versions as versions_view
from tacker.openstack.common import gettextutils
from tacker.openstack.common import log as logging
from tacker import wsgi
LOG = logging.getLogger(__name__)
@ -32,10 +32,10 @@ class Versions(object):
@webob.dec.wsgify(RequestClass=wsgi.Request)
def __call__(self, req):
"""Respond to a request for all Neutron API versions."""
"""Respond to a request for all Tacker API versions."""
version_objs = [
{
"id": "v2.0",
"id": "v1.0",
"status": "CURRENT",
},
]