rename neutron/api to tacker/api
Change-Id: I7dd1c76e2df0aefa618ba28064ce9100f1e0c651
This commit is contained in:
parent
ea44fc81bc
commit
70be577f35
@ -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)
|
@ -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.
|
@ -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])
|
||||
|
@ -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
|
@ -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,
|
@ -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)
|
@ -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
65
tacker/api/v1/router.py
Normal 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)
|
@ -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",
|
||||
},
|
||||
]
|
Loading…
Reference in New Issue
Block a user