[composite:quantum]
use = egg:Paste#urlmap
/: quantumversions
-/v1.0: quantumapi_v1_0
-/v1.1: quantumapi_v1_1
/v2.0: quantumapi_v2_0
-[composite:quantumapi_v1_0]
-use = call:quantum.auth:pipeline_factory
-noauth = extensions quantumapiapp_v1_0
-keystone = authtoken keystonecontext extensions quantumapiapp_v1_0
-
-[composite:quantumapi_v1_1]
-use = call:quantum.auth:pipeline_factory
-noauth = extensions quantumapiapp_v1_1
-keystone = authtoken keystonecontext extensions quantumapiapp_v1_1
-
[composite:quantumapi_v2_0]
use = call:quantum.auth:pipeline_factory
noauth = extensions quantumapiapp_v2_0
[app:quantumversions]
paste.app_factory = quantum.api.versions:Versions.factory
-[app:quantumapiapp_v1_0]
-paste.app_factory = quantum.api:APIRouterV10.factory
-
-[app:quantumapiapp_v1_1]
-paste.app_factory = quantum.api:APIRouterV11.factory
-
[app:quantumapiapp_v2_0]
paste.app_factory = quantum.api.v2.router:APIRouter.factory
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright 2011 Citrix Systems
-# 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.
-# @author: Salvatore Orlando, Citrix Systems
-
-"""
-Quantum API controllers.
-"""
-
-import logging
-import routes
-import webob.dec
-import webob.exc
-
-from quantum.api import attachments
-from quantum.api import networks
-from quantum.api import ports
-from quantum.common import flags
-from quantum import manager
-from quantum import wsgi
-
-
-LOG = logging.getLogger('quantum.api')
-FLAGS = flags.FLAGS
-
-
-class APIRouter(wsgi.Router):
- """
- Base class for Quantum API routes.
- """
- _version = None
-
- def __init__(self):
- mapper = self._mapper()
- self._setup_routes(mapper)
- super(APIRouter, self).__init__(mapper)
-
- def _mapper(self):
- return routes.Mapper()
-
- def _setup_routes(self, mapper):
- self._setup_base_routes(mapper, self._version)
-
- def _setup_base_routes(self, mapper, version):
- """Routes common to all versions."""
- # Loads the quantum plugin
- # Note(salvatore-orlando): Should the plugin be versioned
- # I don't think so
- plugin = manager.QuantumManager.get_plugin()
-
- uri_prefix = '/tenants/{tenant_id}/'
- attachment_path = (
- '%snetworks/{network_id}/ports/{id}/attachment{.format}' %
- uri_prefix)
- mapper.resource('network', 'networks',
- controller=networks.create_resource(plugin, version),
- collection={'detail': 'GET'},
- member={'detail': 'GET'},
- path_prefix=uri_prefix)
- mapper.resource('port', 'ports',
- controller=ports.create_resource(plugin, version),
- collection={'detail': 'GET'},
- member={'detail': 'GET'},
- parent_resource=dict(
- member_name='network',
- collection_name='%snetworks' % uri_prefix))
- attachments_ctrl = attachments.create_resource(plugin, version)
- mapper.connect("get_resource",
- attachment_path,
- controller=attachments_ctrl,
- action="get_resource",
- conditions=dict(method=['GET']))
- mapper.connect("attach_resource",
- attachment_path,
- controller=attachments_ctrl,
- action="attach_resource",
- conditions=dict(method=['PUT']))
- mapper.connect("detach_resource",
- attachment_path,
- controller=attachments_ctrl,
- action="detach_resource",
- conditions=dict(method=['DELETE']))
-
-
-class APIRouterV10(APIRouter):
- """
- API routes mappings for Quantum API v1.0
- """
- _version = '1.0'
-
-
-class APIRouterV11(APIRouter):
- """
- API routes mappings for Quantum API v1.1
- """
- _version = '1.1'
LOG = logging.getLogger(__name__)
-XML_NS_V10 = 'http://openstack.org/quantum/api/v1.0'
-XML_NS_V11 = 'http://openstack.org/quantum/api/v1.1'
-
-
-class OperationalStatus:
- """ Enumeration for operational status
-
- UP : the resource is available (operationall up)
- DOWN : the resource is not operational; this might indicate
- a failure in the underlying switching fabric.
- PROVISIONING: the plugin is creating or updating the resource
- in the underlying switching fabric
- UNKNOWN: the plugin does not support the operational status concept.
- """
- UP = "UP"
- DOWN = "DOWN"
- PROVISIONING = "PROVISIONING"
- UNKNOWN = "UNKNOWN"
-
-
-def create_resource(version, controller_dict):
- """
- Generic function for creating a wsgi resource
- The function takes as input:
- - desired version
- - controller and metadata dictionary
- e.g.: {'1.0': [ctrl_v10, meta_v10, xml_ns],
- '1.1': [ctrl_v11, meta_v11, xml_ns]}
-
- """
- # the first element of the iterable is expected to be the controller
- controller = controller_dict[version][0]
- # the second element should be the metadata
- metadata = controller_dict[version][1]
- # and the third element the xml namespace
- xmlns = controller_dict[version][2]
- # and also the function for building the fault body
- fault_body_function = faults.fault_body_function(version)
-
- headers_serializers = {
- '1.0': HeaderSerializer10(),
- '1.1': HeaderSerializer11()
- }
- xml_serializer = wsgi.XMLDictSerializer(metadata, xmlns)
- json_serializer = wsgi.JSONDictSerializer()
- xml_deserializer = wsgi.XMLDeserializer(metadata)
- json_deserializer = wsgi.JSONDeserializer()
-
- body_serializers = {
- 'application/xml': xml_serializer,
- 'application/json': json_serializer,
- }
-
- body_deserializers = {
- 'application/xml': xml_deserializer,
- 'application/json': json_deserializer,
- }
-
- serializer = wsgi.ResponseSerializer(body_serializers,
- headers_serializers[version])
- deserializer = wsgi.RequestDeserializer(body_deserializers)
-
- return wsgi.Resource(controller,
- fault_body_function,
- deserializer,
- serializer)
-
-
-def APIFaultWrapper(errors=None):
-
- quantum_error_dict = {
- '1.0': faults.Quantum10HTTPError,
- '1.1': faults.Quantum11HTTPError
- }
-
- def wrapper(func, **kwargs):
-
- def the_func(*args, **kwargs):
- try:
- # Grab API version from type of controller
- controller = args[0]
- version = controller.version
- return func(*args, **kwargs)
- except Exception as e:
- if errors is not None and type(e) in errors:
- # Version-specific behaviour
- quantum_error_class = quantum_error_dict[version]
- raise quantum_error_class(e)
- # otherwise just re-raise
- raise
-
- the_func.__name__ = func.__name__
- return the_func
-
- return wrapper
-
-
-class HeaderSerializer10(wsgi.ResponseHeaderSerializer):
- """
- Defines default respone status codes for Quantum API 1.0 operations
- create - 200 OK
- update - 204 NOCONTENT
- delete - 204 NOCONTENT
- others - 200 OK (defined in base class)
-
- """
-
- def create(self, response, data):
- response.status_int = 200
-
- def delete(self, response, data):
- response.status_int = 204
-
- def update(self, response, data):
- response.status_int = 204
-
- def attach_resource(self, response, data):
- response.status_int = 204
-
- def detach_resource(self, response, data):
- response.status_int = 204
-
-
-class HeaderSerializer11(HeaderSerializer10):
- """
- Defines default respone status codes for Quantum API 1.0 operations
- create - 202 ACCEPTED
- update - 204 NOCONTENT
- delete - 204 NOCONTENT
- others - 200 OK (defined in base class)
-
- """
-
- def create(self, response, data):
- response.status_int = 202
-
-
class QuantumController(object):
""" Base controller class for Quantum API """
# _resource_name will be redefined in sub concrete controller
+++ /dev/null
-# Copyright 2011 Citrix Systems.
-# 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 logging
-
-from quantum.api import api_common as common
-from quantum.api.views import attachments as attachments_view
-from quantum.common import exceptions as exception
-
-
-LOG = logging.getLogger(__name__)
-
-
-def create_resource(plugin, version):
- controller_dict = {
- '1.0': [ControllerV10(plugin),
- ControllerV10._serialization_metadata,
- common.XML_NS_V10],
- '1.1': [ControllerV11(plugin),
- ControllerV11._serialization_metadata,
- common.XML_NS_V11],
- }
- return common.create_resource(version, controller_dict)
-
-
-class Controller(common.QuantumController):
- """ Port API controller for Quantum API """
- _resource_name = 'attachment'
- # version will be redefined by in child class
- version = None
- _attachment_ops_param_list = [
- {
- 'param-name': 'id',
- 'required': True,
- },
- ]
-
- _serialization_metadata = {
- "application/xml": {
- "attributes": {
- "attachment": ["id"],
- },
- },
- }
-
- @common.APIFaultWrapper([exception.NetworkNotFound,
- exception.PortNotFound])
- def get_resource(self, request, tenant_id, network_id, id):
- att_data = self._plugin.get_port_details(tenant_id, network_id, id)
- builder = attachments_view.get_view_builder(request)
- result = builder.build(att_data)['attachment']
- return dict(attachment=result)
-
- @common.APIFaultWrapper([exception.NetworkNotFound,
- exception.PortNotFound,
- exception.PortInUse,
- exception.AlreadyAttached])
- def attach_resource(self, request, tenant_id, network_id, id, body):
- body = self._prepare_request_body(body,
- self._attachment_ops_param_list)
- self._plugin.plug_interface(tenant_id, network_id, id,
- body['attachment']['id'])
-
- @common.APIFaultWrapper([exception.NetworkNotFound,
- exception.PortNotFound])
- def detach_resource(self, request, tenant_id, network_id, id):
- self._plugin.unplug_interface(tenant_id, network_id, id)
-
-
-class ControllerV10(Controller):
- """Attachment resources controller for Quantum v1.0 API"""
- version = "1.0"
-
-
-class ControllerV11(Controller):
- """Attachment resources controller for Quantum v1.1 API"""
- version = "1.1"
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 Citrix Systems.
-# 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 webob.exc
-
-from quantum.common import exceptions
-
-
-_NETNOTFOUND_EXPL = 'Unable to find a network with the specified identifier.'
-_NETINUSE_EXPL = 'Unable to remove the network: attachments still plugged.'
-_PORTNOTFOUND_EXPL = 'Unable to find a port with the specified identifier.'
-_STATEINVALID_EXPL = 'Unable to update port state with specified value.'
-_PORTINUSE_EXPL = 'A resource is currently attached to the logical port'
-_ALREADYATTACHED_EXPL = 'The resource is already attached to another port'
-_NOTIMPLEMENTED_EXPL = 'Not implemented'
-
-
-def fault_body_function_v10(wrapped_exc):
- """ This function creates the contents of the body for a fault
- response for Quantum API v1.0.
-
- :param wrapped_exc: Exception thrown by the Quantum service
- :type wrapped_exc: quantum.common.exceptions.QuantumException
- :returns: response body contents and serialization metadata
- :rtype: tuple
- """
- code = wrapped_exc.status_int
- fault_name = (hasattr(wrapped_exc, 'title') and
- wrapped_exc.title or "quantumServiceFault")
- fault_data = {
- fault_name: {
- 'code': code,
- 'message': wrapped_exc.explanation,
- 'detail': str(wrapped_exc.detail),
- },
- }
- metadata = {'attributes': {fault_name: ['code']}}
- return fault_data, metadata
-
-
-def fault_body_function_v11(wrapped_exc):
- """ This function creates the contents of the body for a fault
- response for Quantum API v1.1.
-
- :param wrapped_exc: Exception thrown by the Quantum service
- :type wrapped_exc: quantum.common.exceptions.QuantumException
- :returns: response body contents and serialization metadata
- :rtype: tuple
- """
- fault_name = (hasattr(wrapped_exc, 'type') and
- wrapped_exc.type or "QuantumServiceFault")
- # Ensure first letter is capital
- fault_name = fault_name[0].upper() + fault_name[1:]
- fault_data = {
- 'QuantumError': {
- 'type': fault_name,
- 'message': wrapped_exc.explanation,
- 'detail': str(wrapped_exc.detail),
- },
- }
- # Metadata not required for v11
- return fault_data, None
-
-
-def fault_body_function(version):
- # dict mapping API version to functions for building the
- # fault response body
- fault_body_function_dict = {
- '1.0': fault_body_function_v10,
- '1.1': fault_body_function_v11
- }
- return fault_body_function_dict.get(version, None)
-
-
-class Quantum10HTTPError(webob.exc.HTTPClientError):
-
- _fault_dict = {
- exceptions.NetworkNotFound: {
- 'code': 420,
- 'title': 'networkNotFound',
- 'explanation': _NETNOTFOUND_EXPL
- },
- exceptions.NetworkInUse: {
- 'code': 421,
- 'title': 'networkInUse',
- 'explanation': _NETINUSE_EXPL
- },
- exceptions.PortNotFound: {
- 'code': 430,
- 'title': 'portNotFound',
- 'explanation': _PORTNOTFOUND_EXPL
- },
- exceptions.StateInvalid: {
- 'code': 431,
- 'title': 'requestedStateInvalid',
- 'explanation': _STATEINVALID_EXPL
- },
- exceptions.PortInUse: {
- 'code': 432,
- 'title': 'portInUse',
- 'explanation': _PORTINUSE_EXPL
- },
- exceptions.AlreadyAttached: {
- 'code': 440,
- 'title': 'alreadyAttached',
- 'explanation': _ALREADYATTACHED_EXPL
- },
- exceptions.NotImplementedError: {
- 'code': 501,
- 'title': 'notImplemented',
- 'explanation': _NOTIMPLEMENTED_EXPL
- }
- }
-
- def __init__(self, inner_exc):
- _fault_data = self._fault_dict.get(type(inner_exc), None)
- if _fault_data:
- self.code = _fault_data['code']
- self.title = _fault_data['title']
- self.explanation = _fault_data['explanation']
- super(webob.exc.HTTPClientError, self).__init__(inner_exc)
-
-
-class Quantum11HTTPError(webob.exc.HTTPClientError):
-
- _fault_dict = {
- exceptions.NetworkNotFound: {
- 'code': webob.exc.HTTPNotFound.code,
- 'title': webob.exc.HTTPNotFound.title,
- 'type': 'NetworkNotFound',
- 'explanation': _NETNOTFOUND_EXPL
- },
- exceptions.NetworkInUse: {
- 'code': webob.exc.HTTPConflict.code,
- 'title': webob.exc.HTTPConflict.title,
- 'type': 'NetworkInUse',
- 'explanation': _NETINUSE_EXPL
- },
- exceptions.PortNotFound: {
- 'code': webob.exc.HTTPNotFound.code,
- 'title': webob.exc.HTTPNotFound.title,
- 'type': 'PortNotFound',
- 'explanation': _PORTNOTFOUND_EXPL
- },
- exceptions.StateInvalid: {
- 'code': webob.exc.HTTPBadRequest.code,
- 'title': webob.exc.HTTPBadRequest.title,
- 'type': 'RequestedStateInvalid',
- 'explanation': _STATEINVALID_EXPL
- },
- exceptions.PortInUse: {
- 'code': webob.exc.HTTPConflict.code,
- 'title': webob.exc.HTTPConflict.title,
- 'type': 'PortInUse',
- 'explanation': _PORTINUSE_EXPL
- },
- exceptions.AlreadyAttached: {
- 'code': webob.exc.HTTPConflict.code,
- 'title': webob.exc.HTTPConflict.title,
- 'type': 'AlreadyAttached',
- 'explanation': _ALREADYATTACHED_EXPL
- }
- }
-
- def __init__(self, inner_exc):
- _fault_data = self._fault_dict.get(type(inner_exc), None)
- if _fault_data:
- self.code = _fault_data['code']
- self.title = _fault_data['title']
- self.explanation = _fault_data['explanation']
- self.type = _fault_data['type']
- super(webob.exc.HTTPClientError, self).__init__(inner_exc)
+++ /dev/null
-# Copyright 2011 Citrix Systems.
-# 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 logging
-
-
-from quantum.api import api_common as common
-from quantum.api.views import filters
-from quantum.api.views import networks as networks_view
-from quantum.common import exceptions as exception
-
-
-LOG = logging.getLogger(__name__)
-
-
-def create_resource(plugin, version):
- controller_dict = {
- '1.0': [ControllerV10(plugin),
- ControllerV10._serialization_metadata,
- common.XML_NS_V10],
- '1.1': [ControllerV11(plugin),
- ControllerV11._serialization_metadata,
- common.XML_NS_V11],
- }
- return common.create_resource(version, controller_dict)
-
-
-class Controller(common.QuantumController):
- """ Network API controller for Quantum API """
- _resource_name = 'network'
- # version will be redefined in child class
- version = None
- _network_ops_param_list = [
- {'param-name': 'name', 'required': True},
- ]
-
- def _item(self, request, tenant_id, network_id,
- net_details=True, port_details=False):
- # We expect get_network_details to return information
- # concerning logical ports as well.
- network = self._plugin.get_network_details(tenant_id, network_id)
- # Doing this in the API is inefficient
- # TODO(salvatore-orlando): This should be fixed with Bug #834012
- # Don't pass filter options
- ports_data = None
- if port_details:
- port_list = self._plugin.get_all_ports(tenant_id, network_id)
- ports_data = [
- self._plugin.get_port_details(tenant_id, network_id,
- port['port-id'])
- for port in port_list]
- builder = networks_view.get_view_builder(request, self.version)
- result = builder.build(network, net_details,
- ports_data, port_details)['network']
- return dict(network=result)
-
- def _items(self, request, tenant_id, net_details=False):
- """ Returns a list of networks.
- Ideally, the plugin would perform filtering,
- returning only the items matching filters specified
- on the request query string.
- However, plugins are not required to support filtering.
- In this case, this function will filter the complete list
- of networks returned by the plugin
-
- """
- filter_opts = {}
- filter_opts.update(request.GET)
- networks = self._plugin.get_all_networks(tenant_id,
- filter_opts=filter_opts)
- # Inefficient, API-layer filtering
- # will be performed only for the filters not implemented by the plugin
- # NOTE(salvatore-orlando): the plugin is supposed to leave only filters
- # it does not implement in filter_opts
- networks = filters.filter_networks(networks,
- self._plugin,
- tenant_id,
- filter_opts)
- builder = networks_view.get_view_builder(request, self.version)
- result = [builder.build(network, net_details)['network']
- for network in networks]
- return dict(networks=result)
-
- @common.APIFaultWrapper()
- def index(self, request, tenant_id):
- """ Returns a list of network ids """
- return self._items(request, tenant_id)
-
- @common.APIFaultWrapper([exception.NetworkNotFound])
- def show(self, request, tenant_id, id):
- """ Returns network details for the given network id """
- return self._item(request, tenant_id, id,
- net_details=True, port_details=False)
-
- @common.APIFaultWrapper([exception.NetworkNotFound])
- def detail(self, request, **kwargs):
- tenant_id = kwargs.get('tenant_id')
- network_id = kwargs.get('id')
- if network_id:
- # show details for a given network
- return self._item(request, tenant_id, network_id,
- net_details=True, port_details=True)
- else:
- # show details for all networks
- return self._items(request, tenant_id, net_details=True)
-
- @common.APIFaultWrapper()
- def create(self, request, tenant_id, body):
- """ Creates a new network for a given tenant """
- # NOTE(bgh): We're currently passing both request_params['name'] and
- # the entire request_params dict because their may be pieces of
- # information (data extensions) inside the request params that the
- # actual plugin will want to parse. We could just pass only
- # request_params but that would mean all the plugins would need to
- # change.
- body = self._prepare_request_body(body, self._network_ops_param_list)
- network = self._plugin.create_network(tenant_id,
- body['network']['name'],
- **body)
- builder = networks_view.get_view_builder(request, self.version)
- result = builder.build(network)['network']
- return dict(network=result)
-
- @common.APIFaultWrapper([exception.NetworkNotFound])
- def update(self, request, tenant_id, id, body):
- """ Updates the name for the network with the given id """
- body = self._prepare_request_body(body, self._network_ops_param_list)
- self._plugin.update_network(tenant_id, id, **body['network'])
-
- @common.APIFaultWrapper([exception.NetworkNotFound,
- exception.NetworkInUse])
- def delete(self, request, tenant_id, id):
- """ Destroys the network with the given id """
- self._plugin.delete_network(tenant_id, id)
-
-
-class ControllerV10(Controller):
- """Network resources controller for Quantum v1.0 API"""
-
- _serialization_metadata = {
- "attributes": {
- "network": ["id", "name"],
- "port": ["id", "state"],
- "attachment": ["id"],
- },
- "plurals": {
- "networks": "network",
- "ports": "port",
- },
- }
-
- version = "1.0"
-
-
-class ControllerV11(Controller):
- """Network resources controller for Quantum v1.1 API
-
- Note: at this state this class only adds serialization
- metadata for the operational status concept.
- API filters, pagination, and atom links will be handled by
- this class as well.
- """
-
- _serialization_metadata = {
- "attributes": {
- "network": ["id", "name", "op-status"],
- "port": ["id", "state", "op-status"],
- "attachment": ["id"],
- },
- "plurals": {
- "networks": "network",
- "ports": "port",
- },
- }
-
- version = "1.1"
+++ /dev/null
-# Copyright 2011 Citrix Systems.
-# 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 logging
-
-from quantum.api import api_common as common
-from quantum.api.views import filters
-from quantum.api.views import ports as ports_view
-from quantum.common import exceptions as exception
-
-
-LOG = logging.getLogger(__name__)
-
-
-def create_resource(plugin, version):
- controller_dict = {
- '1.0': [ControllerV10(plugin),
- ControllerV10._serialization_metadata,
- common.XML_NS_V10],
- '1.1': [ControllerV11(plugin),
- ControllerV11._serialization_metadata,
- common.XML_NS_V11],
- }
- return common.create_resource(version, controller_dict)
-
-
-class Controller(common.QuantumController):
- """ Port API controller for Quantum API """
- _resource_name = 'port'
- # version will be redefined in child class
- version = None
- _port_ops_param_list = [
- {'param-name': 'state', 'default-value': 'DOWN', 'required': False},
- ]
-
- def _items(self, request, tenant_id, network_id,
- port_details=False):
- """ Returns a list of ports.
- Ideally, the plugin would perform filtering,
- returning only the items matching filters specified
- on the request query string.
- However, plugins are not required to support filtering.
- In this case, this function will filter the complete list
- of ports returned by the plugin
- """
- filter_opts = {}
- filter_opts.update(request.GET)
- port_list = self._plugin.get_all_ports(tenant_id,
- network_id,
- filter_opts=filter_opts)
-
- builder = ports_view.get_view_builder(request, self.version)
-
- # Load extra data for ports if required.
- # This can be inefficient.
- # TODO(salvatore-orlando): the fix for bug #834012 should deal with it
- if port_details:
- port_list_detail = [
- self._plugin.get_port_details(tenant_id, network_id,
- port['port-id'])
- for port in port_list]
- port_list = port_list_detail
-
- # Perform manual filtering if not supported by plugin
- # Inefficient, API-layer filtering
- # will be performed only if the plugin does
- # not support filtering
- # NOTE(salvatore-orlando): the plugin is supposed to leave only filters
- # it does not implement in filter_opts
- port_list = filters.filter_ports(port_list, self._plugin,
- tenant_id, network_id,
- filter_opts)
-
- result = [builder.build(port, port_details)['port']
- for port in port_list]
- return dict(ports=result)
-
- def _item(self, request, tenant_id, network_id, port_id,
- att_details=False):
- """ Returns a specific port. """
- port = self._plugin.get_port_details(tenant_id, network_id, port_id)
- builder = ports_view.get_view_builder(request, self.version)
- result = builder.build(port, port_details=True,
- att_details=att_details)['port']
- return dict(port=result)
-
- @common.APIFaultWrapper([exception.NetworkNotFound])
- def index(self, request, tenant_id, network_id):
- """ Returns a list of port ids for a given network """
- return self._items(request, tenant_id, network_id, port_details=False)
-
- @common.APIFaultWrapper([exception.NetworkNotFound,
- exception.PortNotFound])
- def show(self, request, tenant_id, network_id, id):
- """ Returns port details for given port and network """
- return self._item(request, tenant_id, network_id, id)
-
- @common.APIFaultWrapper([exception.NetworkNotFound,
- exception.PortNotFound])
- def detail(self, request, **kwargs):
- tenant_id = kwargs.get('tenant_id')
- network_id = kwargs.get('network_id')
- port_id = kwargs.get('id')
- if port_id:
- # show details for a given network
- return self._item(request, tenant_id,
- network_id, port_id, att_details=True)
- else:
- # show details for all port
- return self._items(request, tenant_id,
- network_id, port_details=True)
-
- @common.APIFaultWrapper([exception.NetworkNotFound,
- exception.StateInvalid])
- def create(self, request, tenant_id, network_id, body=None):
- """ Creates a new port for a given network
- The request body is optional for a port object.
-
- """
- body = self._prepare_request_body(body, self._port_ops_param_list)
- port = self._plugin.create_port(tenant_id,
- network_id, body['port']['state'],
- **body)
- builder = ports_view.get_view_builder(request, self.version)
- result = builder.build(port)['port']
- return dict(port=result)
-
- @common.APIFaultWrapper([exception.NetworkNotFound,
- exception.PortNotFound,
- exception.StateInvalid])
- def update(self, request, tenant_id, network_id, id, body):
- """ Updates the state of a port for a given network """
- body = self._prepare_request_body(body, self._port_ops_param_list)
- self._plugin.update_port(tenant_id, network_id, id, **body['port'])
-
- @common.APIFaultWrapper([exception.NetworkNotFound,
- exception.PortNotFound,
- exception.PortInUse])
- def delete(self, request, tenant_id, network_id, id):
- """ Destroys the port with the given id """
- self._plugin.delete_port(tenant_id, network_id, id)
-
-
-class ControllerV10(Controller):
- """Port resources controller for Quantum v1.0 API"""
-
- _serialization_metadata = {
- "attributes": {
- "port": ["id", "state"],
- "attachment": ["id"],
- },
- "plurals": {
- "ports": "port",
- },
- }
-
- version = "1.0"
-
-
-class ControllerV11(Controller):
- """Port resources controller for Quantum v1.1 API"""
-
- _serialization_metadata = {
- "attributes": {
- "port": ["id", "state", "op-status"],
- "attachment": ["id"],
- },
- "plurals": {
- "ports": "port",
- },
- }
-
- version = "1.1"
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 Citrix Systems
-# 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.
-
-
-def get_view_builder(req):
- base_url = req.application_url
- return ViewBuilder(base_url)
-
-
-class ViewBuilder(object):
-
- def __init__(self, base_url):
- """
- :param base_url: url of the root wsgi application
- """
- self.base_url = base_url
-
- def build(self, attachment_data):
- """Generic method used to generate an attachment entity."""
- if attachment_data['attachment']:
- return dict(attachment=dict(id=attachment_data['attachment']))
- else:
- return dict(attachment={})
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2012 Citrix Systems
-# 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 logging
-
-
-LOG = logging.getLogger(__name__)
-
-
-def _load_network_ports_details(network, **kwargs):
- plugin = kwargs.get('plugin', None)
- tenant_id = kwargs.get('tenant_id', None)
- #load network details only if required
- if not 'net-ports' in network:
- # Don't pass filter options, don't care about unused filters
- port_list = plugin.get_all_ports(tenant_id, network['net-id'])
- ports_data = [plugin.get_port_details(
- tenant_id, network['net-id'],
- port['port-id'])
- for port in port_list]
- network['net-ports'] = ports_data
-
-
-def _filter_network_by_name(network, name, **kwargs):
- return network.get('net-name', None) == name
-
-
-def _filter_network_with_operational_port(network, port_op_status,
- **kwargs):
- _load_network_ports_details(network, **kwargs)
- return any([port['port-op-status'] == port_op_status
- for port in network['net-ports']])
-
-
-def _filter_network_with_active_port(network, port_state, **kwargs):
- _load_network_ports_details(network, **kwargs)
- return any([port['port-state'] == port_state
- for port in network['net-ports']])
-
-
-def _filter_network_has_interface(network, has_interface, **kwargs):
- _load_network_ports_details(network, **kwargs)
- # convert to bool
- match_has_interface = has_interface.lower() == 'true'
- really_has_interface = any([port['attachment'] is not None
- for port in network['net-ports']])
- return match_has_interface == really_has_interface
-
-
-def _filter_network_by_port(network, port_id, **kwargs):
- _load_network_ports_details(network, **kwargs)
- return any([port['port-id'] == port_id
- for port in network['net-ports']])
-
-
-def _filter_network_by_interface(network, interface_id, **kwargs):
- _load_network_ports_details(network, **kwargs)
- return any([port.get('attachment', None) == interface_id
- for port in network['net-ports']])
-
-
-def _filter_port_by_state(port, state, **kwargs):
- return port.get('port-state', None) == state
-
-
-def _filter_network_by_op_status(network, op_status, **kwargs):
- return network.get('net-op-status', None) == op_status
-
-
-def _filter_port_by_op_status(port, op_status, **kwargs):
- return port.get('port-op-status', None) == op_status
-
-
-def _filter_port_by_interface(port, interface_id, **kwargs):
- return port.get('attachment', None) == interface_id
-
-
-def _filter_port_has_interface(port, has_interface, **kwargs):
- # convert to bool
- match_has_interface = has_interface.lower() == 'true'
- really_has_interface = ('attachment' in port and
- port['attachment'] is not None)
- return match_has_interface == really_has_interface
-
-
-def _do_filtering(items, filters, filter_opts, plugin,
- tenant_id, network_id=None):
- filtered_items = []
- for item in items:
- is_filter_match = False
- for flt in filters:
- if flt in filter_opts:
- is_filter_match = filters[flt](item,
- filter_opts[flt],
- plugin=plugin,
- tenant_id=tenant_id,
- network_id=network_id)
- if not is_filter_match:
- break
- if is_filter_match:
- filtered_items.append(item)
- return filtered_items
-
-
-def filter_networks(networks, plugin, tenant_id, filter_opts):
- # Do filtering only if the plugin supports it
- # and if filtering options have been specific
- if len(filter_opts) == 0:
- return networks
-
- # load filter functions
- filters = {
- 'name': _filter_network_by_name,
- 'op-status': _filter_network_by_op_status,
- 'port-op-status': _filter_network_with_operational_port,
- 'port-state': _filter_network_with_active_port,
- 'has-attachment': _filter_network_has_interface,
- 'attachment': _filter_network_by_interface,
- 'port': _filter_network_by_port}
- # filter networks
- return _do_filtering(networks, filters, filter_opts, plugin, tenant_id)
-
-
-def filter_ports(ports, plugin, tenant_id, network_id, filter_opts):
- # Do filtering only if the plugin supports it
- # and if filtering options have been specific
- if len(filter_opts) == 0:
- return ports
-
- # load filter functions
- filters = {
- 'state': _filter_port_by_state,
- 'op-status': _filter_port_by_op_status,
- 'has-attachment': _filter_port_has_interface,
- 'attachment': _filter_port_by_interface}
- # port details are need for filtering
- ports = [plugin.get_port_details(tenant_id, network_id,
- port['port-id']) for port in ports]
- # filter ports
- return _do_filtering(ports,
- filters,
- filter_opts,
- plugin,
- tenant_id,
- network_id)
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 Citrix Systems
-# 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 quantum.api.api_common import OperationalStatus
-
-
-def get_view_builder(req, version):
- base_url = req.application_url
- view_builder = {
- '1.0': ViewBuilder10,
- '1.1': ViewBuilder11,
- }[version](base_url)
- return view_builder
-
-
-class ViewBuilder10(object):
-
- def __init__(self, base_url=None):
- """
- :param base_url: url of the root wsgi application
- """
- self.base_url = base_url
-
- def build(self, network_data, net_detail=False,
- ports_data=None, port_detail=False):
- """Generic method used to generate a network entity."""
- if net_detail:
- network = self._build_detail(network_data)
- else:
- network = self._build_simple(network_data)
- if port_detail:
- ports = [self._build_port(port_data) for port_data in ports_data]
- network['network']['ports'] = ports
- return network
-
- def _build_simple(self, network_data):
- """Return a simple model of a network."""
- return dict(network=dict(id=network_data['net-id']))
-
- def _build_detail(self, network_data):
- """Return a detailed model of a network."""
- return dict(network=dict(id=network_data['net-id'],
- name=network_data['net-name']))
-
- def _build_port(self, port_data):
- """Return details about a specific logical port."""
- port_dict = dict(id=port_data['port-id'],
- state=port_data['port-state'])
- if port_data['attachment']:
- port_dict['attachment'] = dict(id=port_data['attachment'])
- return port_dict
-
-
-class ViewBuilder11(ViewBuilder10):
-
- def _build_simple(self, network_data):
- """Return a simple model of a network."""
- return dict(network=dict(id=network_data['net-id']))
-
- def _build_detail(self, network_data):
- """Return a detailed model of a network. """
- op_status = network_data.get('net-op-status',
- OperationalStatus.UNKNOWN)
- return dict(network={'id': network_data['net-id'],
- 'name': network_data['net-name'],
- 'op-status': op_status})
-
- def _build_port(self, port_data):
- """Return details about a specific logical port."""
- op_status = port_data.get('port-op-status',
- OperationalStatus.UNKNOWN)
- port_dict = {'id': port_data['port-id'],
- 'state': port_data['port-state'],
- 'op-status': op_status}
- if port_data['attachment']:
- port_dict['attachment'] = dict(id=port_data['attachment'])
- return port_dict
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 Citrix Systems
-# 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 quantum.api.api_common import OperationalStatus
-
-
-def get_view_builder(req, version):
- base_url = req.application_url
- view_builder = {
- '1.0': ViewBuilder10,
- '1.1': ViewBuilder11,
- }[version](base_url)
- return view_builder
-
-
-class ViewBuilder10(object):
-
- def __init__(self, base_url=None):
- """
- :param base_url: url of the root wsgi application
- """
- self.base_url = base_url
-
- def build(self, port_data, port_details=False, att_details=False):
- """Generic method used to generate a port entity."""
- port = dict(port=dict(id=port_data['port-id']))
- if port_details:
- port['port']['state'] = port_data['port-state']
- if att_details and port_data['attachment']:
- port['port']['attachment'] = dict(id=port_data['attachment'])
- return port
-
-
-class ViewBuilder11(ViewBuilder10):
-
- def build(self, port_data, port_details=False, att_details=False):
- """Generates a port entity with operation status info"""
- port = dict(port=dict(id=port_data['port-id']))
- if port_details:
- port['port']['state'] = port_data['port-state']
- port['port']['op-status'] = port_data.get('port-op-status',
- OperationalStatus.
- UNKNOWN)
- if att_details and port_data['attachment']:
- port['port']['attachment'] = dict(id=port_data['attachment'])
- return port
from sqlalchemy.exc import DisconnectionError
from sqlalchemy.orm import sessionmaker, exc
-from quantum.api.api_common import OperationalStatus
from quantum.common import exceptions as q_exc
-from quantum.db import model_base, models
-
+from quantum.db import model_base
LOG = logging.getLogger(__name__)
global _ENGINE
assert _ENGINE
base.metadata.drop_all(_ENGINE)
-
-
-def network_create(tenant_id, name, op_status=OperationalStatus.UNKNOWN):
- session = get_session()
-
- with session.begin():
- net = models.Network(tenant_id, name, op_status)
- session.add(net)
- session.flush()
- return net
-
-
-def network_all_tenant_list():
- session = get_session()
- return session.query(models.Network).all()
-
-
-def network_list(tenant_id):
- session = get_session()
- return (session.query(models.Network).
- filter_by(tenant_id=tenant_id).
- all())
-
-
-def network_get(net_id):
- session = get_session()
- try:
- return (session.query(models.Network).
- filter_by(uuid=net_id).
- one())
- except exc.NoResultFound:
- raise q_exc.NetworkNotFound(net_id=net_id)
-
-
-def network_update(net_id, tenant_id, **kwargs):
- session = get_session()
- net = network_get(net_id)
- for key in kwargs.keys():
- net[key] = kwargs[key]
- session.merge(net)
- session.flush()
- return net
-
-
-def network_destroy(net_id):
- session = get_session()
- try:
- net = (session.query(models.Network).
- filter_by(uuid=net_id).
- one())
-
- ports = (session.query(models.Port).
- filter_by(network_id=net_id).
- all())
- for p in ports:
- session.delete(p)
-
- session.delete(net)
- session.flush()
- return net
- except exc.NoResultFound:
- raise q_exc.NetworkNotFound(net_id=net_id)
-
-
-def validate_network_ownership(tenant_id, net_id):
- session = get_session()
- try:
- return (session.query(models.Network).
- filter_by(uuid=net_id).
- filter_by(tenant_id=tenant_id).
- one())
- except exc.NoResultFound:
- raise q_exc.NetworkNotFound(net_id=net_id)
-
-
-def port_create(net_id, state=None, op_status=OperationalStatus.UNKNOWN):
- # confirm network exists
- network_get(net_id)
-
- session = get_session()
- with session.begin():
- port = models.Port(net_id, op_status)
- if state is None:
- state = 'DOWN'
- elif state not in ('ACTIVE', 'DOWN'):
- raise q_exc.StateInvalid(port_state=state)
- port['state'] = state
- session.add(port)
- session.flush()
- return port
-
-
-def port_list(net_id):
- # confirm network exists
- network_get(net_id)
- session = get_session()
- return (session.query(models.Port).
- filter_by(network_id=net_id).
- all())
-
-
-def port_get(port_id, net_id, session=None):
- # confirm network exists
- network_get(net_id)
- if not session:
- session = get_session()
- try:
- return (session.query(models.Port).
- filter_by(uuid=port_id).
- filter_by(network_id=net_id).
- one())
- except exc.NoResultFound:
- raise q_exc.PortNotFound(net_id=net_id, port_id=port_id)
-
-
-def port_update(port_id, net_id, **kwargs):
- # confirm network exists
- network_get(net_id)
- port = port_get(port_id, net_id)
- session = get_session()
- for key in kwargs:
- if key == "state":
- if kwargs[key] not in ('ACTIVE', 'DOWN'):
- raise q_exc.StateInvalid(port_state=kwargs[key])
- port[key] = kwargs[key]
- session.merge(port)
- session.flush()
- return port
-
-
-def port_set_attachment(port_id, net_id, new_interface_id):
- # confirm network exists
- network_get(net_id)
-
- session = get_session()
- port = port_get(port_id, net_id)
-
- if new_interface_id != "":
- # We are setting, not clearing, the attachment-id
- if port['interface_id']:
- raise q_exc.PortInUse(net_id=net_id, port_id=port_id,
- att_id=port['interface_id'])
-
- try:
- port = (session.query(models.Port).
- filter_by(interface_id=new_interface_id).
- one())
- raise q_exc.AlreadyAttached(net_id=net_id,
- port_id=port_id,
- att_id=new_interface_id,
- att_port_id=port['uuid'])
- except exc.NoResultFound:
- # this is what should happen
- pass
- port.interface_id = new_interface_id
- session.merge(port)
- session.flush()
- return port
-
-
-def port_unset_attachment(port_id, net_id):
- # confirm network exists
- network_get(net_id)
-
- session = get_session()
- port = port_get(port_id, net_id, session)
- port.interface_id = None
- session.add(port)
- session.flush()
-
-
-def port_destroy(port_id, net_id):
- # confirm network exists
- network_get(net_id)
-
- session = get_session()
- try:
- port = (session.query(models.Port).
- filter_by(uuid=port_id).
- filter_by(network_id=net_id).
- one())
- if port['interface_id']:
- raise q_exc.PortInUse(net_id=net_id, port_id=port_id,
- att_id=port['interface_id'])
- session.delete(port)
- session.flush()
- return port
- except exc.NoResultFound:
- raise q_exc.PortNotFound(port_id=port_id)
-
-
-def validate_port_ownership(tenant_id, net_id, port_id, session=None):
- validate_network_ownership(tenant_id, net_id)
- port_get(port_id, net_id)
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright 2011 Nicira Networks, Inc.
-# 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.
-# @author: Somik Behera, Nicira Networks, Inc.
-# @author: Brad Hall, Nicira Networks, Inc.
-# @author: Dan Wendlandt, Nicira Networks, Inc.
-# @author: Salvatore Orlando, Citrix Systems
-
-import uuid
-
-from sqlalchemy import Column, String, ForeignKey
-from sqlalchemy.orm import relation
-
-from quantum.api import api_common as common
-from quantum.db import model_base
-
-
-BASE = model_base.BASE
-
-
-class Port(model_base.BASE):
- """Represents a port on a quantum network"""
- __tablename__ = 'ports'
-
- uuid = Column(String(255), primary_key=True)
- network_id = Column(String(255), ForeignKey("networks.uuid"),
- nullable=False)
- interface_id = Column(String(255), nullable=True)
- # Port state - Hardcoding string value at the moment
- state = Column(String(8))
- op_status = Column(String(16))
-
- def __init__(self, network_id, op_status=common.OperationalStatus.UNKNOWN):
- self.uuid = str(uuid.uuid4())
- self.network_id = network_id
- self.interface_id = None
- self.state = "DOWN"
- self.op_status = op_status
-
- def __repr__(self):
- return "<Port(%s,%s,%s,%s,%s)>" % (self.uuid, self.network_id,
- self.state, self.op_status,
- self.interface_id)
-
-
-class Network(model_base.BASE):
- """Represents a quantum network"""
- __tablename__ = 'networks'
-
- uuid = Column(String(255), primary_key=True)
- tenant_id = Column(String(255), nullable=False)
- name = Column(String(255))
- ports = relation(Port, order_by=Port.uuid, backref="network")
- op_status = Column(String(16))
-
- def __init__(self, tenant_id, name,
- op_status=common.OperationalStatus.UNKNOWN):
- self.uuid = str(uuid.uuid4())
- self.tenant_id = tenant_id
- self.name = name
- self.op_status = op_status
-
- def __repr__(self):
- return "<Network(%s,%s,%s,%s)>" % (self.uuid, self.name,
- self.op_status, self.tenant_id)
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright 2011 Nicira Networks, Inc. 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.
-#
-# @author: Brad Hall, Nicira Networks, Inc
-#
-
-
-def get_view_builder(req):
- """get view builder"""
- base_url = req.application_url
- return ViewBuilder(base_url)
-
-
-class ViewBuilder(object):
- """
- ViewBuilder for Port statistics.
-
- Port stats coming back from the plugin will look like this:
- {
- "rx_packets": 0,
- "rx_bytes": 0,
- "tx_errors": 0,
- "rx_errors": 0,
- "tx_bytes": 0,
- "tx_packets": 0
- }
- """
- def __init__(self, base_url):
- self.base_url = base_url
-
- def build(self, portstat_data, is_detail=True):
- # We just ignore is_detail -- it doesn't make sense in this context.
- return self._build(portstat_data)
-
- def _build(self, portstat_data):
- return portstat_data
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright 2011 Nicira Networks, Inc. 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.
-#
-# @author: Brad Hall, Nicira Networks, Inc
-
-import logging
-
-from quantum.api import faults
-from quantum.common import exceptions as qexception
-from quantum.common import extensions
-from quantum.extensions import _portstats_view as portstats_view
-from quantum.manager import QuantumManager
-from quantum import wsgi
-
-
-LOG = logging.getLogger("quantum.api.portstats")
-
-
-class Portstats(object):
- def __init__(self):
- pass
-
- @classmethod
- def get_name(cls):
- return "Port Statistics"
-
- @classmethod
- def get_alias(cls):
- return "portstats"
-
- @classmethod
- def get_description(cls):
- return "Port Statistics"
-
- @classmethod
- def get_namespace(cls):
- return "http://docs.openstack.org/ext/portstats/api/v1.0"
-
- @classmethod
- def get_updated(cls):
- return "2011-12-20T10:00:00-00:00"
-
- @classmethod
- def get_resources(cls):
- """ Returns all defined resources """
- controller = StatsController(QuantumManager.get_plugin())
- parent_resource = dict(member_name="port",
- collection_name="extensions/ovs/tenants/"
- ":(tenant_id)/ networks/:(network_id)/ports")
- return [extensions.ResourceExtension('stats', controller,
- parent=parent_resource)]
-
-
-class StatsController(wsgi.Controller):
- _serialization_metadata = {
- "application/xml": {
- "attributes": {
- "stats": ["rx_bytes", "rx_packets", "rx_errors",
- "tx_bytes", "tx_packets", "tx_errors"]
- }
- }
- }
-
- def __init__(self, plugin):
- self._resource_name = 'stats'
- self._plugin = plugin
-
- def _show(self, request, tenant_id, network_id, port_id):
- """Returns port statistics for a given port"""
- if not hasattr(self._plugin, "get_port_stats"):
- return faults.QuantumHTTPError(
- qexception.NotImplementedError("get_port_stats"))
-
- stats = self._plugin.get_port_stats(tenant_id, network_id, port_id)
- builder = portstats_view.get_view_builder(request)
- result = builder.build(stats, True)
- return dict(stats=result)
-
- def index(self, request, tenant_id, network_id, port_id):
- return self._show(request, tenant_id, network_id, port_id)
-
- def show(self, request, tenant_id, network_id, port_id, id):
- return self._show(request, tenant_id, network_id, port_id)
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright 2012, Cisco Systems, Inc.
-#
-# 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.
-# @author: Sumit Naiksatam, Cisco Systems, Inc.
-
-import logging
-
-from quantum.api.api_common import OperationalStatus
-from quantum.common import exceptions as exc
-from quantum.db import api as db
-from quantum.plugins.linuxbridge.common import constants as const
-from quantum.plugins.linuxbridge.common import utils as cutil
-from quantum.plugins.linuxbridge.db import l2network_db as cdb
-from quantum.quantum_plugin_base import QuantumPluginBase
-
-
-LOG = logging.getLogger(__name__)
-
-
-class LinuxBridgePlugin(QuantumPluginBase):
- """
- LinuxBridgePlugin provides support for Quantum abstractions
- using LinuxBridge. A new VLAN is created for each network.
- It relies on an agent to perform the actual bridge configuration
- on each host.
- """
-
- def __init__(self, configfile=None):
- cdb.initialize()
- LOG.debug("Linux Bridge Plugin initialization done successfully")
-
- def _get_vlan_for_tenant(self, tenant_id, **kwargs):
- """Get an available VLAN ID"""
- try:
- return cdb.reserve_vlanid()
- except:
- raise Exception("Failed to reserve VLAN ID for network")
-
- def _release_vlan_for_tenant(self, tenant_id, net_id, **kwargs):
- """Release the ID"""
- vlan_binding = cdb.get_vlan_binding(net_id)
- return cdb.release_vlanid(vlan_binding[const.VLANID])
-
- def _validate_port_state(self, port_state):
- if port_state.upper() not in ('ACTIVE', 'DOWN'):
- raise exc.StateInvalid(port_state=port_state)
- return True
-
- def get_all_networks(self, tenant_id, **kwargs):
- """
- Returns a dictionary containing all
- <network_uuid, network_name> for
- the specified tenant.
- """
- LOG.debug("LinuxBridgePlugin.get_all_networks() called")
- networks_list = db.network_list(tenant_id)
- new_networks_list = []
- for network in networks_list:
- new_network_dict = cutil.make_net_dict(network[const.UUID],
- network[const.NETWORKNAME],
- [], network[const.OPSTATUS])
- new_networks_list.append(new_network_dict)
-
- # This plugin does not perform filtering at the moment
- return new_networks_list
-
- def get_network_details(self, tenant_id, net_id):
- """
- retrieved a list of all the remote vifs that
- are attached to the network
- """
- LOG.debug("LinuxBridgePlugin.get_network_details() called")
- db.validate_network_ownership(tenant_id, net_id)
- network = db.network_get(net_id)
- ports_list = db.port_list(net_id)
- ports_on_net = []
- for port in ports_list:
- new_port = cutil.make_port_dict(port)
- ports_on_net.append(new_port)
-
- new_network = cutil.make_net_dict(network[const.UUID],
- network[const.NETWORKNAME],
- ports_on_net,
- network[const.OPSTATUS])
-
- return new_network
-
- def create_network(self, tenant_id, net_name, **kwargs):
- """
- Creates a new Virtual Network, and assigns it
- a symbolic name.
- """
- LOG.debug("LinuxBridgePlugin.create_network() called")
- new_network = db.network_create(tenant_id, net_name,
- op_status=OperationalStatus.UP)
- new_net_id = new_network[const.UUID]
- vlan_id = self._get_vlan_for_tenant(tenant_id)
- cdb.add_vlan_binding(vlan_id, new_net_id)
- new_net_dict = {
- const.NET_ID: new_net_id,
- const.NET_NAME: net_name,
- const.NET_PORTS: [],
- const.NET_OP_STATUS: new_network[const.OPSTATUS],
- }
- return new_net_dict
-
- def delete_network(self, tenant_id, net_id):
- """
- Deletes the network with the specified network identifier
- belonging to the specified tenant.
- """
- LOG.debug("LinuxBridgePlugin.delete_network() called")
- db.validate_network_ownership(tenant_id, net_id)
- net = db.network_get(net_id)
- if net:
- ports_on_net = db.port_list(net_id)
- if len(ports_on_net) > 0:
- for port in ports_on_net:
- if port[const.INTERFACEID]:
- raise exc.NetworkInUse(net_id=net_id)
- for port in ports_on_net:
- self.delete_port(tenant_id, net_id, port[const.UUID])
-
- net_dict = cutil.make_net_dict(net[const.UUID],
- net[const.NETWORKNAME],
- [], net[const.OPSTATUS])
- try:
- self._release_vlan_for_tenant(tenant_id, net_id)
- cdb.remove_vlan_binding(net_id)
- except Exception as excp:
- LOG.warning("Exception: %s" % excp)
- db.network_update(net_id, tenant_id, {const.OPSTATUS:
- OperationalStatus.DOWN})
- db.network_destroy(net_id)
- return net_dict
- # Network not found
- raise exc.NetworkNotFound(net_id=net_id)
-
- def update_network(self, tenant_id, net_id, **kwargs):
- """
- Updates the attributes of a particular Virtual Network.
- """
- LOG.debug("LinuxBridgePlugin.update_network() called")
- db.validate_network_ownership(tenant_id, net_id)
- network = db.network_update(net_id, tenant_id, **kwargs)
- net_dict = cutil.make_net_dict(network[const.UUID],
- network[const.NETWORKNAME],
- [], network[const.OPSTATUS])
- return net_dict
-
- def get_all_ports(self, tenant_id, net_id, **kwargs):
- """
- Retrieves all port identifiers belonging to the
- specified Virtual Network.
- """
- LOG.debug("LinuxBridgePlugin.get_all_ports() called")
- db.validate_network_ownership(tenant_id, net_id)
- ports_list = db.port_list(net_id)
- ports_on_net = []
- for port in ports_list:
- new_port = cutil.make_port_dict(port)
- ports_on_net.append(new_port)
-
- # This plugin does not perform filtering at the moment
- return ports_on_net
-
- def get_port_details(self, tenant_id, net_id, port_id):
- """
- This method allows the user to retrieve a remote interface
- that is attached to this particular port.
- """
- LOG.debug("LinuxBridgePlugin.get_port_details() called")
- db.validate_port_ownership(tenant_id, net_id, port_id)
- port = db.port_get(port_id, net_id)
- new_port_dict = cutil.make_port_dict(port)
- return new_port_dict
-
- def create_port(self, tenant_id, net_id, port_state=None, **kwargs):
- """
- Creates a port on the specified Virtual Network.
- """
- LOG.debug("LinuxBridgePlugin.create_port() called")
- db.validate_network_ownership(tenant_id, net_id)
- port = db.port_create(net_id, port_state,
- op_status=OperationalStatus.DOWN)
- new_port_dict = cutil.make_port_dict(port)
- return new_port_dict
-
- def update_port(self, tenant_id, net_id, port_id, **kwargs):
- """
- Updates the attributes of a port on the specified Virtual Network.
- """
- LOG.debug("LinuxBridgePlugin.update_port() called")
- db.validate_port_ownership(tenant_id, net_id, port_id)
- self._validate_port_state(kwargs["state"])
- port = db.port_update(port_id, net_id, **kwargs)
-
- new_port_dict = cutil.make_port_dict(port)
- return new_port_dict
-
- def delete_port(self, tenant_id, net_id, port_id):
- """
- Deletes a port on a specified Virtual Network,
- if the port contains a remote interface attachment,
- the remote interface is first un-plugged and then the port
- is deleted.
- """
- LOG.debug("LinuxBridgePlugin.delete_port() called")
- db.validate_port_ownership(tenant_id, net_id, port_id)
- port = db.port_get(port_id, net_id)
- attachment_id = port[const.INTERFACEID]
- if not attachment_id:
- db.port_destroy(port_id, net_id)
- new_port_dict = cutil.make_port_dict(port)
- return new_port_dict
- else:
- raise exc.PortInUse(port_id=port_id, net_id=net_id,
- att_id=attachment_id)
-
- def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id):
- """
- Attaches a remote interface to the specified port on the
- specified Virtual Network.
- """
- LOG.debug("LinuxBridgePlugin.plug_interface() called")
- db.validate_port_ownership(tenant_id, net_id, port_id)
- port = db.port_get(port_id, net_id)
- attachment_id = port[const.INTERFACEID]
- if attachment_id:
- raise exc.PortInUse(port_id=port_id, net_id=net_id,
- att_id=attachment_id)
- db.port_set_attachment(port_id, net_id, remote_interface_id)
-
- def unplug_interface(self, tenant_id, net_id, port_id):
- """
- Detaches a remote interface from the specified port on the
- specified Virtual Network.
- """
- LOG.debug("LinuxBridgePlugin.unplug_interface() called")
- db.validate_port_ownership(tenant_id, net_id, port_id)
- port = db.port_get(port_id, net_id)
- attachment_id = port[const.INTERFACEID]
- if attachment_id is None:
- return
- db.port_unset_attachment(port_id, net_id)
- db.port_update(port_id, net_id, op_status=OperationalStatus.DOWN)
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright 2012 Cisco Systems, Inc. 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.
-#
-# @author: Sumit Naiksatam, Cisco Systems, Inc.
-
-import logging
-
-from quantum.api.api_common import OperationalStatus
-from quantum.plugins.linuxbridge.common import constants as const
-
-
-LOG = logging.getLogger(__name__)
-
-
-def make_net_dict(net_id, net_name, ports, op_status):
- """Helper funciton"""
- res = {
- const.NET_ID: net_id,
- const.NET_NAME: net_name,
- const.NET_OP_STATUS: op_status,
- }
- if ports:
- res[const.NET_PORTS] = ports
- return res
-
-
-def make_port_dict(port):
- """Helper funciton"""
- if port[const.PORTSTATE] == const.PORT_UP:
- op_status = port[const.OPSTATUS]
- else:
- op_status = OperationalStatus.DOWN
-
- return {
- const.PORT_ID: str(port[const.UUID]),
- const.PORT_STATE: port[const.PORTSTATE],
- const.PORT_OP_STATUS: op_status,
- const.NET_ID: port[const.NETWORKID],
- const.ATTACHMENT: port[const.INTERFACEID],
- }
from quantum.openstack.common import cfg
from quantum.plugins.linuxbridge.common import config
from quantum.plugins.linuxbridge.common import exceptions as c_exc
-from quantum.plugins.linuxbridge.db import l2network_models
from quantum.plugins.linuxbridge.db import l2network_models_v2
LOG = logging.getLogger(__name__)
# The global variable for the database version model
-L2_MODEL = l2network_models
+L2_MODEL = l2network_models_v2
def initialize(base=None):
cfg.CONF.DATABASE.reconnect_interval})
if base:
options.update({"base": base})
- L2_MODEL = l2network_models_v2
db.configure_db(options)
create_vlanids()
raise q_exc.InvalidInput(error_message=msg)
session = db.get_session()
try:
- rvlanid = (session.query(l2network_models.VlanID).
+ rvlanid = (session.query(l2network_models_v2.VlanID).
filter_by(vlan_id=vlan_id).
one())
if rvlanid["vlan_used"]:
rvlanid["vlan_used"] = True
session.merge(rvlanid)
except exc.NoResultFound:
- rvlanid = l2network_models.VlanID(vlan_id)
+ rvlanid = l2network_models_v2.VlanID(vlan_id)
LOG.debug("reserving non-dynamic vlanid %s" % vlan_id)
rvlanid["vlan_used"] = True
session.add(rvlanid)
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2012, Cisco Systems, Inc.
-#
-# 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.
-# @author: Rohit Agarwalla, Cisco Systems, Inc.
-
-from sqlalchemy import Column, Integer, String, Boolean
-
-from quantum.db.models import BASE
-
-
-class VlanID(BASE):
- """Represents a vlan_id usage"""
- __tablename__ = 'vlan_ids'
-
- vlan_id = Column(Integer, primary_key=True)
- vlan_used = Column(Boolean)
-
- def __init__(self, vlan_id):
- self.vlan_id = vlan_id
- self.vlan_used = False
-
- def __repr__(self):
- return "<VlanID(%d,%s)>" % (self.vlan_id, self.vlan_used)
-
-
-class VlanBinding(BASE):
- """Represents a binding of vlan_id to network_id"""
- __tablename__ = 'vlan_bindings'
-
- vlan_id = Column(Integer, primary_key=True)
- network_id = Column(String(255), nullable=False)
-
- def __init__(self, vlan_id, network_id):
- self.vlan_id = vlan_id
- self.network_id = network_id
-
- def __repr__(self):
- return "<VlanBinding(%d,%s)>" % (self.vlan_id, self.network_id)
sys.path.append(os.path.dirname(__file__))
-from quantum.api.api_common import OperationalStatus
from quantum.common.test_lib import run_tests, test_config
import quantum.tests.unit
# we should only invoked the tests once
invoke_once = len(sys.argv) > 1
- test_config['plugin_name'] = "LinuxBridgePlugin.LinuxBridgePlugin"
test_config['plugin_name_v2'] = "lb_quantum_plugin.LinuxBridgePluginV2"
- test_config['default_net_op_status'] = OperationalStatus.UP
- test_config['default_port_op_status'] = OperationalStatus.DOWN
cwd = os.getcwd()
c = config.Config(stream=sys.stdout,
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright 2012, Cisco Systems, Inc.
-#
-# 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.
-# @author: Rohit Agarwalla, Cisco Systems, Inc.
-
-"""
-test_database.py is an independent test suite
-that tests the database api method calls
-"""
-
-import logging
-import unittest2 as unittest
-
-import quantum.db.api as db
-from quantum.openstack.common import cfg
-import quantum.plugins.linuxbridge.common.exceptions as c_exc
-import quantum.plugins.linuxbridge.db.l2network_db as l2network_db
-
-
-LOG = logging.getLogger(__name__)
-
-
-class L2networkDB(object):
-
- """Class conisting of methods to call L2network db methods"""
- def get_all_vlan_bindings(self):
- """Get all vlan binding into a list of dict"""
- vlans = []
- try:
- for vlan_bind in l2network_db.get_all_vlan_bindings():
- LOG.debug("Getting vlan bindings for vlan: %s" %
- vlan_bind.vlan_id)
- vlan_dict = {}
- vlan_dict["vlan-id"] = str(vlan_bind.vlan_id)
- vlan_dict["net-id"] = str(vlan_bind.network_id)
- vlans.append(vlan_dict)
- except Exception, exc:
- LOG.error("Failed to get all vlan bindings: %s" % str(exc))
- return vlans
-
- def get_vlan_binding(self, network_id):
- """Get a vlan binding"""
- vlan = []
- try:
- for vlan_bind in l2network_db.get_vlan_binding(network_id):
- LOG.debug("Getting vlan binding for vlan: %s" %
- vlan_bind.vlan_id)
- vlan_dict = {}
- vlan_dict["vlan-id"] = str(vlan_bind.vlan_id)
- vlan_dict["net-id"] = str(vlan_bind.network_id)
- vlan.append(vlan_dict)
- except Exception, exc:
- LOG.error("Failed to get vlan binding: %s" % str(exc))
- return vlan
-
- def create_vlan_binding(self, vlan_id, network_id):
- """Create a vlan binding"""
- vlan_dict = {}
- try:
- res = l2network_db.add_vlan_binding(vlan_id, network_id)
- LOG.debug("Created vlan binding for vlan: %s" % res.vlan_id)
- vlan_dict["vlan-id"] = str(res.vlan_id)
- vlan_dict["net-id"] = str(res.network_id)
- return vlan_dict
- except Exception, exc:
- LOG.error("Failed to create vlan binding: %s" % str(exc))
-
- def delete_vlan_binding(self, network_id):
- """Delete a vlan binding"""
- try:
- res = l2network_db.remove_vlan_binding(network_id)
- LOG.debug("Deleted vlan binding for vlan: %s" % res.vlan_id)
- vlan_dict = {}
- vlan_dict["vlan-id"] = str(res.vlan_id)
- return vlan_dict
- except Exception, exc:
- raise Exception("Failed to delete vlan binding: %s" % str(exc))
-
- def update_vlan_binding(self, network_id, vlan_id):
- """Update a vlan binding"""
- try:
- res = l2network_db.update_vlan_binding(network_id, vlan_id)
- LOG.debug("Updating vlan binding for vlan: %s" % res.vlan_id)
- vlan_dict = {}
- vlan_dict["vlan-id"] = str(res.vlan_id)
- vlan_dict["net-id"] = str(res.network_id)
- return vlan_dict
- except Exception, exc:
- raise Exception("Failed to update vlan binding: %s" % str(exc))
-
-
-class QuantumDB(object):
- """Class conisting of methods to call Quantum db methods"""
- def get_all_networks(self, tenant_id):
- """Get all networks"""
- nets = []
- try:
- for net in db.network_list(tenant_id):
- LOG.debug("Getting network: %s" % net.uuid)
- net_dict = {}
- net_dict["tenant-id"] = net.tenant_id
- net_dict["net-id"] = str(net.uuid)
- net_dict["net-name"] = net.name
- nets.append(net_dict)
- except Exception, exc:
- LOG.error("Failed to get all networks: %s" % str(exc))
- return nets
-
- def create_network(self, tenant_id, net_name):
- """Create a network"""
- net_dict = {}
- try:
- res = db.network_create(tenant_id,
- net_name,
- op_status="UP")
- LOG.debug("Created network: %s" % res.uuid)
- net_dict["tenant-id"] = res.tenant_id
- net_dict["net-id"] = str(res.uuid)
- net_dict["net-name"] = res.name
- return net_dict
- except Exception, exc:
- LOG.error("Failed to create network: %s" % str(exc))
-
- def delete_network(self, net_id):
- """Delete a network"""
- try:
- net = db.network_destroy(net_id)
- LOG.debug("Deleted network: %s" % net.uuid)
- net_dict = {}
- net_dict["net-id"] = str(net.uuid)
- return net_dict
- except Exception, exc:
- raise Exception("Failed to delete port: %s" % str(exc))
-
-
-class L2networkDBTest(unittest.TestCase):
- """Class conisting of L2network DB unit tests"""
- def setUp(self):
- """Setup for tests"""
- l2network_db.initialize()
- l2network_db.create_vlanids()
- self.dbtest = L2networkDB()
- self.quantum = QuantumDB()
- LOG.debug("Setup")
-
- def tearDown(self):
- """Tear Down"""
- db.clear_db()
-
- def test_create_vlanbinding(self):
- net1 = self.quantum.create_network("t1", "netid1")
- vlan1 = self.dbtest.create_vlan_binding(10, net1["net-id"])
- self.assertTrue(vlan1["vlan-id"] == "10")
- self.teardown_vlanbinding()
- self.teardown_network()
-
- def test_getall_vlanbindings(self):
- net1 = self.quantum.create_network("t1", "netid1")
- net2 = self.quantum.create_network("t1", "netid2")
- vlan1 = self.dbtest.create_vlan_binding(10, net1["net-id"])
- self.assertTrue(vlan1["vlan-id"] == "10")
- vlan2 = self.dbtest.create_vlan_binding(20, net2["net-id"])
- self.assertTrue(vlan2["vlan-id"] == "20")
- vlans = self.dbtest.get_all_vlan_bindings()
- self.assertTrue(len(vlans) == 2)
- self.teardown_vlanbinding()
- self.teardown_network()
-
- def test_delete_vlanbinding(self):
- net1 = self.quantum.create_network("t1", "netid1")
- vlan1 = self.dbtest.create_vlan_binding(10, net1["net-id"])
- self.assertTrue(vlan1["vlan-id"] == "10")
- self.dbtest.delete_vlan_binding(net1["net-id"])
- vlans = self.dbtest.get_all_vlan_bindings()
- count = 0
- for vlan in vlans:
- if vlan["vlan-id"] is "10":
- count += 1
- self.assertTrue(count == 0)
- self.teardown_vlanbinding()
- self.teardown_network()
-
- def test_update_vlanbinding(self):
- net1 = self.quantum.create_network("t1", "netid1")
- vlan1 = self.dbtest.create_vlan_binding(10, net1["net-id"])
- self.assertTrue(vlan1["vlan-id"] == "10")
- vlan1 = self.dbtest.update_vlan_binding(net1["net-id"], 11)
- self.assertTrue(vlan1["vlan-id"] == "11")
- self.teardown_vlanbinding()
- self.teardown_network()
-
- def test_vlanids(self):
- l2network_db.create_vlanids()
- vlanids = l2network_db.get_all_vlanids()
- self.assertGreater(len(vlanids), 0)
- vlanid = l2network_db.reserve_vlanid()
- used = l2network_db.is_vlanid_used(vlanid)
- self.assertTrue(used)
- used = l2network_db.release_vlanid(vlanid)
- self.assertFalse(used)
- self.teardown_vlanbinding()
- self.teardown_network()
-
- def test_specific_vlanid_outside(self):
- l2network_db.create_vlanids()
- orig_count = len(l2network_db.get_all_vlanids())
- self.assertGreater(orig_count, 0)
- vlan_id = 7 # outside range dynamically allocated
- with self.assertRaises(c_exc.VlanIDNotFound):
- l2network_db.is_vlanid_used(vlan_id)
- l2network_db.reserve_specific_vlanid(vlan_id)
- self.assertTrue(l2network_db.is_vlanid_used(vlan_id))
- count = len(l2network_db.get_all_vlanids())
- self.assertEqual(count, orig_count + 1)
- used = l2network_db.release_vlanid(vlan_id)
- self.assertFalse(used)
- with self.assertRaises(c_exc.VlanIDNotFound):
- l2network_db.is_vlanid_used(vlan_id)
- count = len(l2network_db.get_all_vlanids())
- self.assertEqual(count, orig_count)
- self.teardown_vlanbinding()
- self.teardown_network()
-
- def test_specific_vlanid_inside(self):
- l2network_db.create_vlanids()
- orig_count = len(l2network_db.get_all_vlanids())
- self.assertGreater(orig_count, 0)
- vlan_id = 1007 # inside range dynamically allocated
- self.assertFalse(l2network_db.is_vlanid_used(vlan_id))
- l2network_db.reserve_specific_vlanid(vlan_id)
- self.assertTrue(l2network_db.is_vlanid_used(vlan_id))
- count = len(l2network_db.get_all_vlanids())
- self.assertEqual(count, orig_count)
- used = l2network_db.release_vlanid(vlan_id)
- self.assertFalse(used)
- self.assertFalse(l2network_db.is_vlanid_used(vlan_id))
- count = len(l2network_db.get_all_vlanids())
- self.assertEqual(count, orig_count)
- self.teardown_vlanbinding()
- self.teardown_network()
-
- def teardown_network(self):
- """tearDown Network table"""
- LOG.debug("Tearing Down Network")
- nets = self.quantum.get_all_networks("t1")
- for net in nets:
- netid = net["net-id"]
- self.quantum.delete_network(netid)
-
- def teardown_vlanbinding(self):
- """tearDown VlanBinding table"""
- LOG.debug("Tearing Down Vlan Binding")
- vlans = self.dbtest.get_all_vlan_bindings()
- for vlan in vlans:
- netid = vlan["net-id"]
- self.dbtest.delete_vlan_binding(netid)
-
-
-class ConfigurationTest(unittest.TestCase):
-
- def test_defaults(self):
- self.assertEqual('sqlite://',
- cfg.CONF.DATABASE.sql_connection)
- self.assertEqual(-1,
- cfg.CONF.DATABASE.sql_max_retries)
- self.assertEqual(2,
- cfg.CONF.DATABASE.reconnect_interval)
- self.assertEqual(2,
- cfg.CONF.AGENT.polling_interval)
- self.assertEqual('sudo',
- cfg.CONF.AGENT.root_helper)
- self.assertEqual(1000,
- cfg.CONF.VLANS.vlan_start)
- self.assertEqual(3000,
- cfg.CONF.VLANS.vlan_end)
- self.assertEqual('eth1',
- cfg.CONF.LINUX_BRIDGE.physical_interface)
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright 2011 Nicira Networks, Inc.
-# 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.
-# @author: Somik Behera, Nicira Networks, Inc.
-# @author: Brad Hall, Nicira Networks, Inc.
-# @author: Dan Wendlandt, Nicira Networks, Inc.
-
-from sqlalchemy.orm import exc
-
-import quantum.db.api as db
-from quantum.plugins.openvswitch import ovs_models
-
-
-def get_vlans():
- session = db.get_session()
- try:
- bindings = (session.query(ovs_models.VlanBinding).
- all())
- except exc.NoResultFound:
- return []
- res = []
- for x in bindings:
- res.append((x.vlan_id, x.network_id))
- return res
-
-
-def add_vlan_binding(vlanid, netid):
- session = db.get_session()
- binding = ovs_models.VlanBinding(vlanid, netid)
- session.add(binding)
- session.flush()
- return binding.vlan_id
-
-
-def remove_vlan_binding(netid):
- session = db.get_session()
- try:
- binding = (session.query(ovs_models.VlanBinding).
- filter_by(network_id=netid).
- one())
- session.delete(binding)
- except exc.NoResultFound:
- pass
- session.flush()
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright 2011 Nicira Networks, Inc.
-# 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.
-# @author: Somik Behera, Nicira Networks, Inc.
-# @author: Brad Hall, Nicira Networks, Inc.
-# @author: Dan Wendlandt, Nicira Networks, Inc.
-
-from sqlalchemy import Column, Integer, String
-
-from quantum.db.models import BASE
-
-
-class VlanBinding(BASE):
- """Represents a binding of network_id, vlan_id"""
- __tablename__ = 'vlan_bindings'
-
- vlan_id = Column(Integer, primary_key=True)
- network_id = Column(String(255))
-
- def __init__(self, vlan_id, network_id):
- self.network_id = network_id
- self.vlan_id = vlan_id
-
- def __repr__(self):
- return "<VlanBinding(%s,%s)>" % (self.vlan_id, self.network_id)
-
-
-class TunnelIP(BASE):
- """Represents a remote IP in tunnel mode"""
- __tablename__ = 'tunnel_ips'
-
- ip_address = Column(String(255), primary_key=True)
-
- def __init__(self, ip_address):
- self.ip_address = ip_address
-
- def __repr__(self):
- return "<TunnelIP(%s)>" % (self.ip_address)
import logging
import os
-from quantum.api.api_common import OperationalStatus
from quantum.api.v2 import attributes
from quantum.common import exceptions as q_exc
from quantum.common.utils import find_config_file
from quantum.db import models_v2
from quantum.openstack.common import cfg
from quantum.plugins.openvswitch.common import config
-from quantum.plugins.openvswitch import ovs_db
from quantum.plugins.openvswitch import ovs_db_v2
-from quantum.quantum_plugin_base import QuantumPluginBase
from quantum import policy
LOG = logging.getLogger("ovs_quantum_plugin")
-# Exception thrown if no more VLANs are available
-class NoFreeVLANException(Exception):
- # TODO(rkukura) Remove this class when removing V1 API
- pass
-
-
-class VlanMap(object):
- # TODO(rkukura) Remove this class when removing V1 API
- vlans = {}
- net_ids = {}
- free_vlans = set()
-
- def __init__(self, vlan_min=1, vlan_max=4094):
- if vlan_min > vlan_max:
- LOG.warn("Using default VLAN values! vlan_min = %s is larger"
- " than vlan_max = %s!" % (vlan_min, vlan_max))
- vlan_min = 1
- vlan_max = 4094
-
- self.vlan_min = vlan_min
- self.vlan_max = vlan_max
- self.vlans.clear()
- self.net_ids.clear()
- self.free_vlans = set(xrange(self.vlan_min, self.vlan_max + 1))
-
- def already_used(self, vlan_id, network_id):
- self.free_vlans.remove(vlan_id)
- self.set_vlan(vlan_id, network_id)
-
- def set_vlan(self, vlan_id, network_id):
- self.vlans[vlan_id] = network_id
- self.net_ids[network_id] = vlan_id
-
- def acquire(self, network_id):
- if len(self.free_vlans):
- vlan = self.free_vlans.pop()
- self.set_vlan(vlan, network_id)
- LOG.debug("Allocated VLAN %s for network %s" % (vlan, network_id))
- return vlan
- else:
- raise NoFreeVLANException("No VLAN free for network %s" %
- network_id)
-
- def acquire_specific(self, vlan_id, network_id):
- LOG.debug("Allocating specific VLAN %s for network %s"
- % (vlan_id, network_id))
- if vlan_id < 1 or vlan_id > 4094:
- msg = _("Specified VLAN %s outside legal range (1-4094)") % vlan_id
- raise q_exc.InvalidInput(error_message=msg)
- if self.vlans.get(vlan_id):
- raise q_exc.VlanIdInUse(vlan_id=vlan_id)
- self.free_vlans.discard(vlan_id)
- self.set_vlan(vlan_id, network_id)
-
- def release(self, network_id):
- vlan = self.net_ids.get(network_id, None)
- if vlan is not None:
- if vlan >= self.vlan_min and vlan <= self.vlan_max:
- self.free_vlans.add(vlan)
- del self.vlans[vlan]
- del self.net_ids[network_id]
- LOG.debug("Deallocated VLAN %s (used by network %s)" %
- (vlan, network_id))
- else:
- LOG.error("No vlan found with network \"%s\"", network_id)
-
- def populate_already_used(self, vlans):
- for vlan_id, network_id in vlans:
- LOG.debug("Adding already populated vlan %s -> %s" %
- (vlan_id, network_id))
- self.already_used(vlan_id, network_id)
-
-
-class OVSQuantumPlugin(QuantumPluginBase):
- # TODO(rkukura) Remove this class when removing V1 API
-
- def __init__(self, configfile=None):
- options = {"sql_connection": cfg.CONF.DATABASE.sql_connection}
- sql_max_retries = cfg.CONF.DATABASE.sql_max_retries
- options.update({"sql_max_retries": sql_max_retries})
- reconnect_interval = cfg.CONF.DATABASE.reconnect_interval
- options.update({"reconnect_interval": reconnect_interval})
- db.configure_db(options)
-
- self.vmap = VlanMap(cfg.CONF.OVS.vlan_min, cfg.CONF.OVS.vlan_max)
- # Populate the map with anything that is already present in the
- # database
- self.vmap.populate_already_used(ovs_db.get_vlans())
-
- def get_all_networks(self, tenant_id, **kwargs):
- nets = []
- for x in db.network_list(tenant_id):
- LOG.debug("Adding network: %s" % x.uuid)
- nets.append(self._make_net_dict(str(x.uuid), x.name,
- None, x.op_status))
- return nets
-
- def _make_net_dict(self, net_id, net_name, ports, op_status):
- res = {
- 'net-id': net_id,
- 'net-name': net_name,
- 'net-op-status': op_status,
- }
- if ports:
- res['net-ports'] = ports
- return res
-
- def create_network(self, tenant_id, net_name, **kwargs):
- net = db.network_create(tenant_id, net_name,
- op_status=OperationalStatus.UP)
- try:
- vlan_id = self.vmap.acquire(str(net.uuid))
- except NoFreeVLANException:
- db.network_destroy(net.uuid)
- raise
-
- LOG.debug("Created network: %s" % net)
- ovs_db.add_vlan_binding(vlan_id, str(net.uuid))
- return self._make_net_dict(str(net.uuid), net.name, [], net.op_status)
-
- def delete_network(self, tenant_id, net_id):
- db.validate_network_ownership(tenant_id, net_id)
- net = db.network_get(net_id)
-
- # Verify that no attachments are plugged into the network
- for port in db.port_list(net_id):
- if port.interface_id:
- raise q_exc.NetworkInUse(net_id=net_id)
- net = db.network_destroy(net_id)
- ovs_db.remove_vlan_binding(net_id)
- self.vmap.release(net_id)
- return self._make_net_dict(str(net.uuid), net.name, [], net.op_status)
-
- def get_network_details(self, tenant_id, net_id):
- db.validate_network_ownership(tenant_id, net_id)
- net = db.network_get(net_id)
- ports = self.get_all_ports(tenant_id, net_id)
- return self._make_net_dict(str(net.uuid), net.name,
- ports, net.op_status)
-
- def update_network(self, tenant_id, net_id, **kwargs):
- db.validate_network_ownership(tenant_id, net_id)
- net = db.network_update(net_id, tenant_id, **kwargs)
- return self._make_net_dict(str(net.uuid), net.name,
- None, net.op_status)
-
- def _make_port_dict(self, port):
- if port.state == "ACTIVE":
- op_status = port.op_status
- else:
- op_status = OperationalStatus.DOWN
-
- return {
- 'port-id': str(port.uuid),
- 'port-state': port.state,
- 'port-op-status': op_status,
- 'net-id': port.network_id,
- 'attachment': port.interface_id,
- }
-
- def get_all_ports(self, tenant_id, net_id, **kwargs):
- ids = []
- db.validate_network_ownership(tenant_id, net_id)
- ports = db.port_list(net_id)
- # This plugin does not perform filtering at the moment
- return [{'port-id': str(p.uuid)} for p in ports]
-
- def create_port(self, tenant_id, net_id, port_state=None, **kwargs):
- LOG.debug("Creating port with network_id: %s" % net_id)
- db.validate_network_ownership(tenant_id, net_id)
- port = db.port_create(net_id, port_state,
- op_status=OperationalStatus.DOWN)
- return self._make_port_dict(port)
-
- def delete_port(self, tenant_id, net_id, port_id):
- db.validate_port_ownership(tenant_id, net_id, port_id)
- port = db.port_destroy(port_id, net_id)
- return self._make_port_dict(port)
-
- def update_port(self, tenant_id, net_id, port_id, **kwargs):
- """
- Updates the state of a port on the specified Virtual Network.
- """
- db.validate_port_ownership(tenant_id, net_id, port_id)
- port = db.port_get(port_id, net_id)
- db.port_update(port_id, net_id, **kwargs)
- return self._make_port_dict(port)
-
- def get_port_details(self, tenant_id, net_id, port_id):
- db.validate_port_ownership(tenant_id, net_id, port_id)
- port = db.port_get(port_id, net_id)
- return self._make_port_dict(port)
-
- def plug_interface(self, tenant_id, net_id, port_id, remote_iface_id):
- db.validate_port_ownership(tenant_id, net_id, port_id)
- db.port_set_attachment(port_id, net_id, remote_iface_id)
-
- def unplug_interface(self, tenant_id, net_id, port_id):
- db.validate_port_ownership(tenant_id, net_id, port_id)
- db.port_set_attachment(port_id, net_id, "")
- db.port_update(port_id, net_id, op_status=OperationalStatus.DOWN)
-
- def get_interface_details(self, tenant_id, net_id, port_id):
- db.validate_port_ownership(tenant_id, net_id, port_id)
- res = db.port_get(port_id, net_id)
- return res.interface_id
-
-
class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2):
"""Implement the Quantum abstractions using Open vSwitch.
sys.path.append(os.getcwd())
sys.path.append(os.path.dirname(__file__))
-from quantum.api.api_common import OperationalStatus
from quantum.common.test_lib import run_tests, test_config
import quantum.tests.unit
# we should only invoked the tests once
invoke_once = len(sys.argv) > 1
- test_config['plugin_name'] = "ovs_quantum_plugin.OVSQuantumPlugin"
test_config['plugin_name_v2'] = "ovs_quantum_plugin.OVSQuantumPluginV2"
- test_config['default_net_op_status'] = OperationalStatus.UP
- test_config['default_port_op_status'] = OperationalStatus.DOWN
cwd = os.getcwd()
c = config.Config(stream=sys.stdout,
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright 2011 Nicira Networks, Inc.
-# 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 unittest
-
-from quantum.plugins.openvswitch.ovs_quantum_plugin import (
- NoFreeVLANException,
- VlanMap,
-)
-
-
-class VlanMapTest(unittest.TestCase):
- # TODO(rkukura) Remove this class when removing V1 API
-
- def setUp(self):
- self.vmap = VlanMap()
-
- def tearDown(self):
- pass
-
- def testAddVlan(self):
- vlan_id = self.vmap.acquire("foobar")
- self.assertTrue(vlan_id >= self.vmap.vlan_min)
- self.assertTrue(vlan_id <= self.vmap.vlan_max)
-
- def testReleaseVlan(self):
- vlan_id = self.vmap.acquire("foobar")
- self.vmap.release("foobar")
-
- def testAddRelease4kVlans(self):
- vlan_id = None
- num_vlans = self.vmap.vlan_max - self.vmap.vlan_min
- for id in xrange(num_vlans):
- vlan_id = self.vmap.acquire("net-%s" % id)
- self.assertTrue(vlan_id >= self.vmap.vlan_min)
- self.assertTrue(vlan_id <= self.vmap.vlan_max)
- for id in xrange(num_vlans):
- self.vmap.release("net-%s" % id)
-
- def testAlreadyUsed(self):
- existing_vlan = 2
- self.vmap.already_used(existing_vlan, "net1")
- try:
- # this value is high enough that we will exhaust
- # all VLANs. We want to make sure 'existing_vlan'
- # is never reallocated.
- num_vlans = self.vmap.vlan_max - self.vmap.vlan_min + 1
- for x in xrange(num_vlans):
- vlan_id = self.vmap.acquire("net-%x" % x)
- self.assertTrue(vlan_id != existing_vlan)
-
- self.fail("Did not run out of VLANs as expected")
- except NoFreeVLANException:
- pass # Expected exit
class OVSQuantumOFPRyuAgent:
- def __init__(self, integ_br, db, root_helper, target_v2_api=False):
+ def __init__(self, integ_br, db, root_helper):
self.root_helper = root_helper
(ofp_controller_addr, ofp_rest_api_addr) = check_ofp_mode(db)
self.nw_id_external = rest_nw_id.NW_ID_EXTERNAL
self.api = OFPClient(ofp_rest_api_addr)
- self.target_v2_api = target_v2_api
self._setup_integration_br(integ_br, ofp_controller_addr)
def _setup_integration_br(self, integ_br, ofp_controller_addr):
def _all_bindings(self, db):
"""return interface id -> port which include network id bindings"""
- if self.target_v2_api:
- return dict((port.device_id, port) for port in db.ports.all())
- else:
- return dict((port.interface_id, port) for port in db.ports.all())
+ return dict((port.device_id, port) for port in db.ports.all())
def _set_port_status(self, port, status):
- if self.target_v2_api:
- port.status = status
- else:
- port.op_status = status
+ port.status = status
def daemon_loop(self, db):
# on startup, register all existing ports
integ_br = cfg.CONF.OVS.integration_bridge
root_helper = cfg.CONF.AGENT.root_helper
- target_v2_api = cfg.CONF.AGENT.target_v2_api
options = {"sql_connection": cfg.CONF.DATABASE.sql_connection}
db = SqlSoup(options["sql_connection"])
LOG.info("Connecting to database \"%s\" on %s",
db.engine.url.database, db.engine.url.host)
- plugin = OVSQuantumOFPRyuAgent(integ_br, db, root_helper, target_v2_api)
+ plugin = OVSQuantumOFPRyuAgent(integ_br, db, root_helper)
plugin.daemon_loop(db)
sys.exit(0)
]
agent_opts = [
- cfg.BoolOpt('target_v2_api', default=True),
cfg.IntOpt('polling_interval', default=2),
cfg.StrOpt('root_helper', default='sudo'),
]
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright 2012 Isaku Yamahata <yamahata at private email ne jp>
-# 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 quantum.db.api as db
-from quantum.plugins.ryu.db import models
-
-
-def set_ofp_servers(hosts):
- session = db.get_session()
- session.query(models.OFPServer).delete()
- for (host_address, host_type) in hosts:
- host = models.OFPServer(host_address, host_type)
- session.add(host)
- session.flush()
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright 2012 Isaku Yamahata <yamahata at private email ne jp>
-# 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 sqlalchemy import Column, Integer, String
-
-from quantum.db.models import BASE
-
-
-class OFPServer(BASE):
- """Openflow Server/API address"""
- __tablename__ = 'ofp_server'
-
- id = Column(Integer, primary_key=True, autoincrement=True)
- address = Column(String(255)) # netloc <host ip address>:<port>
- host_type = Column(String(255)) # server type
- # Controller, REST_API
-
- def __init__(self, address, host_type):
- self.address = address
- self.host_type = host_type
-
- def __repr__(self):
- return "<OFPServer(%s,%s,%s)>" % (self.id, self.address,
- self.host_type)
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright 2012 Isaku Yamahata
-# 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.
-# @author: Isaku Yamahata
-
-from abc import ABCMeta, abstractmethod
-import logging as LOG
-import os
-
-from quantum.api.api_common import OperationalStatus
-from quantum.common import exceptions as q_exc
-import quantum.db.api as db
-from quantum.openstack.common import cfg
-from quantum.plugins.ryu.common import config
-from quantum.quantum_plugin_base import QuantumPluginBase
-
-
-LOG.getLogger(__name__)
-
-
-class OVSQuantumPluginDriverBase(object):
- """
- Base class for OVS quantum plugin driver
- """
- __metaclass__ = ABCMeta
-
- @abstractmethod
- def create_network(self, net):
- pass
-
- @abstractmethod
- def delete_network(self, net):
- pass
-
-
-class OVSQuantumPluginBase(QuantumPluginBase):
- """
- Base class for OVS-based plugin which referes to a subclass of
- OVSQuantumPluginDriverBase which is defined above.
- Subclass of OVSQuantumPluginBase must set self.driver to a subclass of
- OVSQuantumPluginDriverBase.
- """
- def __init__(self, conf_file, mod_file, configfile=None):
- super(OVSQuantumPluginBase, self).__init__()
- options = {"sql_connection": cfg.CONF.DATABASE.sql_connection}
- sql_max_retries = cfg.CONF.DATABASE.sql_max_retries
- options.update({"sql_max_retries": sql_max_retries})
- reconnect_interval = cfg.CONF.DATABASE.reconnect_interval
- options.update({"reconnect_interval": reconnect_interval})
- db.configure_db(options)
-
- self.conf = cfg.CONF
- # Subclass must set self.driver to its own OVSQuantumPluginDriverBase
- self.driver = None
-
- def get_all_networks(self, tenant_id, **kwargs):
- nets = []
- for net in db.network_list(tenant_id):
- LOG.debug("Adding network: %s", net.uuid)
- nets.append(self._make_net_dict(str(net.uuid), net.name,
- None, net.op_status))
- return nets
-
- def _make_net_dict(self, net_id, net_name, ports, op_status):
- res = {'net-id': net_id,
- 'net-name': net_name,
- 'net-op-status': op_status}
- if ports:
- res['net-ports'] = ports
- return res
-
- def create_network(self, tenant_id, net_name, **kwargs):
- net = db.network_create(tenant_id, net_name,
- op_status=OperationalStatus.UP)
- LOG.debug("Created network: %s", net)
- self.driver.create_network(net)
- return self._make_net_dict(str(net.uuid), net.name, [], net.op_status)
-
- def delete_network(self, tenant_id, net_id):
- db.validate_network_ownership(tenant_id, net_id)
- net = db.network_get(net_id)
-
- # Verify that no attachments are plugged into the network
- for port in db.port_list(net_id):
- if port.interface_id:
- raise q_exc.NetworkInUse(net_id=net_id)
- net = db.network_destroy(net_id)
- self.driver.delete_network(net)
- return self._make_net_dict(str(net.uuid), net.name, [], net.op_status)
-
- def get_network_details(self, tenant_id, net_id):
- db.validate_network_ownership(tenant_id, net_id)
- net = db.network_get(net_id)
- ports = self.get_all_ports(tenant_id, net_id)
- return self._make_net_dict(str(net.uuid), net.name,
- ports, net.op_status)
-
- def update_network(self, tenant_id, net_id, **kwargs):
- db.validate_network_ownership(tenant_id, net_id)
- net = db.network_update(net_id, tenant_id, **kwargs)
- return self._make_net_dict(str(net.uuid), net.name,
- None, net.op_status)
-
- def _make_port_dict(self, port):
- if port.state == "ACTIVE":
- op_status = port.op_status
- else:
- op_status = OperationalStatus.DOWN
-
- return {'port-id': str(port.uuid),
- 'port-state': port.state,
- 'port-op-status': op_status,
- 'net-id': port.network_id,
- 'attachment': port.interface_id}
-
- def get_all_ports(self, tenant_id, net_id, **kwargs):
- db.validate_network_ownership(tenant_id, net_id)
- ports = db.port_list(net_id)
- # This plugin does not perform filtering at the moment
- return [{'port-id': str(port.uuid)} for port in ports]
-
- def create_port(self, tenant_id, net_id, port_state=None, **kwargs):
- LOG.debug("Creating port with network_id: %s", net_id)
- port = db.port_create(net_id, port_state,
- op_status=OperationalStatus.DOWN)
- return self._make_port_dict(port)
-
- def delete_port(self, tenant_id, net_id, port_id):
- db.validate_port_ownership(tenant_id, net_id, port_id)
- port = db.port_destroy(port_id, net_id)
- return self._make_port_dict(port)
-
- def update_port(self, tenant_id, net_id, port_id, **kwargs):
- """
- Updates the state of a port on the specified Virtual Network.
- """
- LOG.debug("update_port() called\n")
- db.validate_port_ownership(tenant_id, net_id, port_id)
- port = db.port_get(port_id, net_id)
- db.port_update(port_id, net_id, **kwargs)
- return self._make_port_dict(port)
-
- def get_port_details(self, tenant_id, net_id, port_id):
- db.validate_port_ownership(tenant_id, net_id, port_id)
- port = db.port_get(port_id, net_id)
- return self._make_port_dict(port)
-
- def plug_interface(self, tenant_id, net_id, port_id, remote_iface_id):
- db.validate_port_ownership(tenant_id, net_id, port_id)
- db.port_set_attachment(port_id, net_id, remote_iface_id)
-
- def unplug_interface(self, tenant_id, net_id, port_id):
- db.validate_port_ownership(tenant_id, net_id, port_id)
- db.port_set_attachment(port_id, net_id, "")
- db.port_update(port_id, net_id, op_status=OperationalStatus.DOWN)
-
- def get_interface_details(self, tenant_id, net_id, port_id):
- db.validate_port_ownership(tenant_id, net_id, port_id)
- res = db.port_get(port_id, net_id)
- return res.interface_id
sys.path.append(os.getcwd())
sys.path.append(os.path.dirname(__file__))
-from quantum.api.api_common import OperationalStatus
from quantum.common.test_lib import run_tests, test_config
from quantum.plugins.ryu.tests.unit.utils import patch_fake_ryu_client
import quantum.tests.unit
# we should only invoked the tests once
invoke_once = len(sys.argv) > 1
- test_config['plugin_name'] = "ryu_quantum_plugin.RyuQuantumPlugin"
test_config['plugin_name_v2'] = "ryu_quantum_plugin.RyuQuantumPluginV2"
- test_config['default_net_op_status'] = OperationalStatus.UP
- test_config['default_port_op_status'] = OperationalStatus.DOWN
cwd = os.getcwd()
# patch modules for ryu.app.client and ryu.app.rest_nw_id
from quantum.db import db_base_plugin_v2
from quantum.db import models_v2
from quantum.openstack.common import cfg
-from quantum.plugins.ryu.db import api as db_api
from quantum.plugins.ryu.db import api_v2 as db_api_v2
from quantum.plugins.ryu import ofp_service_type
-from quantum.plugins.ryu import ovs_quantum_plugin_base
from quantum.plugins.ryu.common import config
LOG = logging.getLogger(__name__)
-class OFPRyuDriver(ovs_quantum_plugin_base.OVSQuantumPluginDriverBase):
- def __init__(self, conf):
- super(OFPRyuDriver, self).__init__()
- ofp_con_host = conf.OVS.openflow_controller
- ofp_api_host = conf.OVS.openflow_rest_api
-
- if ofp_con_host is None or ofp_api_host is None:
- raise q_exc.Invalid("invalid configuration. check ryu.ini")
-
- hosts = [(ofp_con_host, ofp_service_type.CONTROLLER),
- (ofp_api_host, ofp_service_type.REST_API)]
- db_api.set_ofp_servers(hosts)
-
- self.client = client.OFPClient(ofp_api_host)
- self.client.update_network(rest_nw_id.NW_ID_EXTERNAL)
-
- # register known all network list on startup
- self._create_all_tenant_network()
-
- def _create_all_tenant_network(self):
- networks = db.network_all_tenant_list()
- for net in networks:
- self.client.update_network(net.uuid)
-
- def create_network(self, net):
- self.client.create_network(net.uuid)
-
- def delete_network(self, net):
- self.client.delete_network(net.uuid)
-
-
-class RyuQuantumPlugin(ovs_quantum_plugin_base.OVSQuantumPluginBase):
- def __init__(self, configfile=None):
- super(RyuQuantumPlugin, self).__init__(__file__, configfile)
- self.driver = OFPRyuDriver(self.conf)
-
-
class RyuQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2):
def __init__(self, configfile=None):
options = {"sql_connection": cfg.CONF.DATABASE.sql_connection}
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright 2012 Isaku Yamahata <yamahata at private email ne jp>
-# 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 mox
-import stubout
-import unittest
-
-import quantum.db.api as db
-from quantum.plugins.ryu.tests.unit import utils
-
-
-class BaseRyuTest(unittest.TestCase):
- """base test class for Ryu unit tests"""
- def setUp(self):
- config = utils.get_config()
- options = {"sql_connection": config.get("DATABASE", "sql_connection")}
- db.configure_db(options)
-
- self.config = config
- self.mox = mox.Mox()
- self.stubs = stubout.StubOutForTesting()
-
- def tearDown(self):
- self.mox.UnsetStubs()
- self.stubs.UnsetAll()
- self.stubs.SmartUnsetAll()
- self.mox.VerifyAll()
- db.clear_db()
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright 2012 Isaku Yamahata <yamahata at private email ne jp>
-# <yamahata at valinux co jp>
-# 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 quantum.plugins.ryu import ovs_quantum_plugin_base
-
-
-class FakePluginDriver(ovs_quantum_plugin_base.OVSQuantumPluginDriverBase):
- def __init__(self, config):
- super(FakePluginDriver, self).__init__()
- conf = config.parse(config)
- self.conf = conf
-
- def create_network(self, net):
- pass
-
- def delete_network(self, net):
- pass
-
-
-class FakePlugin(ovs_quantum_plugin_base.OVSQuantumPluginBase):
- def __init__(self, configfile=None):
- super(FakePlugin, self).__init__(None, __file__, configfile)
- self.driver = FakePluginDriver(self.conf)
+++ /dev/null
-# Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
-# Copyright (C) 2011 Isaku Yamahata <yamahata at valinux co jp>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, version 3 of the License.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-NW_ID_EXTERNAL = '__NW_ID_EXTERNAL__'
-NW_ID_UNKNOWN = '__NW_ID_UNKNOWN__'
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright 2012 Isaku Yamahata <yamahata at private email ne jp>
-# 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.
-
-
-class OFPClient(object):
- def __init__(self, address):
- super(OFPClient, self).__init__()
- self.address = address
-
- def get_networks(self):
- pass
-
- def create_network(self, network_id):
- pass
-
- def update_network(self, network_id):
- pass
-
- def delete_network(self, network_id):
- pass
-
- def get_ports(self, network_id):
- pass
-
- def create_port(self, network_id, dpid, port):
- pass
-
- def update_port(self, network_id, dpid, port):
- pass
-
- def delete_port(self, network_id, dpid, port):
- pass
# License for the specific language governing permissions and limitations
# under the License.
-import os
-
-import mox
+import unittest2
from quantum.openstack.common import cfg
-from quantum.plugins.ryu.tests.unit.basetest import BaseRyuTest
-from quantum.plugins.ryu.tests.unit import fake_plugin
-from quantum.plugins.ryu.tests.unit import utils
-
-
-class PluginBaseTest(BaseRyuTest):
- """Class conisting of OVSQuantumPluginBase unit tests"""
- def setUp(self):
- super(PluginBaseTest, self).setUp()
- self.ini_file = utils.create_fake_ryu_ini()
-
- def tearDown(self):
- os.unlink(self.ini_file)
- super(PluginBaseTest, self).tearDown()
-
- def test_create_delete_network(self):
- # mox.StubOutClassWithMocks can't be used for class with metaclass
- # overrided
- driver_mock = self.mox.CreateMock(fake_plugin.FakePluginDriver)
- self.mox.StubOutWithMock(fake_plugin, 'FakePluginDriver',
- use_mock_anything=True)
-
- fake_plugin.FakePluginDriver(mox.IgnoreArg()).AndReturn(driver_mock)
- driver_mock.create_network(mox.IgnoreArg())
- driver_mock.delete_network(mox.IgnoreArg())
- self.mox.ReplayAll()
- plugin = fake_plugin.FakePlugin(configfile=self.ini_file)
-
- tenant_id = 'tenant_id'
- net_name = 'net_name'
- ret = plugin.create_network(tenant_id, net_name)
+from quantum.plugins.ryu.common import config
- plugin.delete_network(tenant_id, ret['net-id'])
- self.mox.VerifyAll()
+class ConfigurationTest(unittest2.TestCase):
+ """Configuration file Tests"""
def test_defaults(self):
self.assertEqual('br-int', cfg.CONF.OVS.integration_bridge)
self.assertEqual('sqlite://', cfg.CONF.DATABASE.sql_connection)
--- /dev/null
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2012 Isaku Yamahata <yamahata at private email ne jp>
+# 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 unittest2
+
+from quantum.db import api as db
+from quantum.db import models_v2
+from quantum.openstack.common import cfg
+from quantum.plugins.ryu.db import api_v2 as db_api_v2
+from quantum.plugins.ryu.db import models_v2 as ryu_models_v2
+from quantum.plugins.ryu import ofp_service_type
+
+
+class RyuDBTest(unittest2.TestCase):
+ def setUp(self):
+ options = {"sql_connection": cfg.CONF.DATABASE.sql_connection}
+ options.update({'base': models_v2.model_base.BASEV2})
+ reconnect_interval = cfg.CONF.DATABASE.reconnect_interval
+ options.update({"reconnect_interval": reconnect_interval})
+ db.configure_db(options)
+
+ self.hosts = [(cfg.CONF.OVS.openflow_controller,
+ ofp_service_type.CONTROLLER),
+ (cfg.CONF.OVS.openflow_rest_api,
+ ofp_service_type.REST_API)]
+ db_api_v2.set_ofp_servers(self.hosts)
+
+ def tearDown(self):
+ db.clear_db()
+ cfg.CONF.reset()
+
+ def test_ofp_server(self):
+ session = db.get_session()
+ servers = session.query(ryu_models_v2.OFPServer).all()
+ print servers
+ self.assertEqual(len(servers), 2)
+ for s in servers:
+ self.assertTrue((s.address, s.host_type) in self.hosts)
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright 2012 Isaku Yamahata <yamahata at private email ne jp>
-# 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 uuid
-
-import quantum.db.api as db
-from quantum.openstack.common import cfg
-from quantum.plugins.ryu.common import config
-from quantum.plugins.ryu.tests.unit.basetest import BaseRyuTest
-from quantum.plugins.ryu.tests.unit import utils
-from quantum.plugins.ryu.tests.unit.utils import patch_fake_ryu_client
-
-
-class RyuDriverTest(BaseRyuTest):
- """Class conisting of OFPRyuDriver unit tests"""
- def setUp(self):
- super(RyuDriverTest, self).setUp()
- self.conf = cfg.CONF
- # fake up ryu.app.client and ryu.app.rest_nw_id
- # With those, plugin can be tested without ryu installed
- self.module_patcher = patch_fake_ryu_client()
- self.module_patcher.start()
-
- def tearDown(self):
- self.module_patcher.stop()
- super(RyuDriverTest, self).tearDown()
-
- def test_ryu_driver(self):
- from ryu.app import client as client_mod
- from ryu.app import rest_nw_id as rest_nw_id_mod
-
- self.mox.StubOutClassWithMocks(client_mod, 'OFPClient')
- client_mock = client_mod.OFPClient(utils.FAKE_REST_ADDR)
-
- self.mox.StubOutWithMock(client_mock, 'update_network')
- self.mox.StubOutWithMock(client_mock, 'create_network')
- self.mox.StubOutWithMock(client_mock, 'delete_network')
- client_mock.update_network(rest_nw_id_mod.NW_ID_EXTERNAL)
- uuid0 = '01234567-89ab-cdef-0123-456789abcdef'
-
- def fake_uuid4():
- return uuid0
-
- self.stubs.Set(uuid, 'uuid4', fake_uuid4)
- uuid1 = '12345678-9abc-def0-1234-56789abcdef0'
- net1 = utils.Net(uuid1)
-
- client_mock.update_network(uuid0)
- client_mock.create_network(uuid1)
- client_mock.delete_network(uuid1)
- self.mox.ReplayAll()
-
- db.network_create('test', uuid0)
-
- from quantum.plugins.ryu import ryu_quantum_plugin
- ryu_driver = ryu_quantum_plugin.OFPRyuDriver(self.conf)
- ryu_driver.create_network(net1)
- ryu_driver.delete_network(net1)
- self.mox.VerifyAll()
-
- db.network_destroy(uuid0)
# License for the specific language governing permissions and limitations
# under the License.
-import ConfigParser
-import imp
-import os
-from StringIO import StringIO
-import tempfile
-
import mock
-from quantum.plugins.ryu.tests.unit import fake_rest_nw_id
-from quantum.plugins.ryu.tests.unit import fake_ryu_client
-
-
-FAKE_CONTROLLER_ADDR = '127.0.0.1:6633'
-FAKE_REST_ADDR = '127.0.0.1:8080'
-FAKE_RYU_INI_TEMPLATE = """
-[DATABASE]
-sql_connection = sqlite:///:memory:
-
-[OVS]
-integration-bridge = br-int
-openflow-controller = %s
-openflow-rest-api = %s
-""" % (FAKE_CONTROLLER_ADDR, FAKE_REST_ADDR)
-
-
-def create_fake_ryu_ini():
- fd, file_name = tempfile.mkstemp(suffix='.ini')
- tmp_file = os.fdopen(fd, 'w')
- tmp_file.write(FAKE_RYU_INI_TEMPLATE)
- tmp_file.close()
- return file_name
-
-
-def get_config():
- config = ConfigParser.ConfigParser()
- buf_file = StringIO(FAKE_RYU_INI_TEMPLATE)
- config.readfp(buf_file)
- buf_file.close()
- return config
-
def patch_fake_ryu_client():
- ryu_mod = imp.new_module('ryu')
- ryu_app_mod = imp.new_module('ryu.app')
- ryu_mod.app = ryu_app_mod
- ryu_app_mod.client = fake_ryu_client
- ryu_app_mod.rest_nw_id = fake_rest_nw_id
+ ryu_mod = mock.Mock()
+ ryu_app_mod = ryu_mod.app
+ ryu_app_client = ryu_app_mod.client
+ rest_nw_id = ryu_app_mod.rest_nw_id
+ rest_nw_id.NW_ID_EXTERNAL = '__NW_ID_EXTERNAL__'
+ rest_nw_id.NW_ID_UNKNOWN = '__NW_ID_UNKNOWN__'
return mock.patch.dict('sys.modules',
{'ryu': ryu_mod,
'ryu.app': ryu_app_mod,
- 'ryu.app.client': fake_ryu_client,
- 'ryu.app.rest_nw_id': fake_rest_nw_id})
-
-
-class Net(object):
- def __init__(self, uuid):
- self.uuid = uuid
+ 'ryu.app.client': ryu_app_client,
+ 'ryu.app.rest_nw_id': rest_nw_id})
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011, Nicira Networks, Inc.
-#
-# 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.
-# @author: Somik Behera, Nicira Networks, Inc.
-# @author: Salvatore Orlando, Citrix
-
-import logging
-
-from quantum.api.api_common import OperationalStatus
-from quantum.common import exceptions as exc
-from quantum.db import api as db
-
-
-LOG = logging.getLogger('quantum.plugins.sample.SamplePlugin')
-
-
-class QuantumEchoPlugin(object):
-
- """
- QuantumEchoPlugin is a demo plugin that doesn't
- do anything but demonstrated the concept of a
- concrete Quantum Plugin. Any call to this plugin
- will result in just a "print" to std. out with
- the name of the method that was called.
- """
-
- def get_all_networks(self, tenant_id):
- """
- Returns a dictionary containing all
- <network_uuid, network_name> for
- the specified tenant.
- """
- print("get_all_networks() called\n")
-
- def create_network(self, tenant_id, net_name, **kwargs):
- """
- Creates a new Virtual Network, and assigns it
- a symbolic name.
- """
- print("create_network() called\n")
-
- def delete_network(self, tenant_id, net_id):
- """
- Deletes the network with the specified network identifier
- belonging to the specified tenant.
- """
- print("delete_network() called\n")
-
- def get_network_details(self, tenant_id, net_id):
- """
- Deletes the Virtual Network belonging to a the
- spec
- """
- print("get_network_details() called\n")
-
- def update_network(self, tenant_id, net_id, **kwargs):
- print("update_network() called")
-
- def get_all_ports(self, tenant_id, net_id):
- """
- Retrieves all port identifiers belonging to the
- specified Virtual Network.
- """
- print("get_all_ports() called\n")
-
- def create_port(self, tenant_id, net_id, **kwargs):
- """
- Creates a port on the specified Virtual Network.
- """
- print("create_port() called\n")
-
- def delete_port(self, tenant_id, net_id, port_id):
- """
- Deletes a port on a specified Virtual Network,
- if the port contains a remote interface attachment,
- the remote interface is first un-plugged and then the port
- is deleted.
- """
- print("delete_port() called\n")
-
- def update_port(self, tenant_id, net_id, port_id, **kwargs):
- """
- Updates the attributes of a port on the specified Virtual Network.
- """
- print("update_port() called\n")
-
- def get_port_details(self, tenant_id, net_id, port_id):
- """
- This method allows the user to retrieve a remote interface
- that is attached to this particular port.
- """
- print("get_port_details() called\n")
-
- def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id):
- """
- Attaches a remote interface to the specified port on the
- specified Virtual Network.
- """
- print("plug_interface() called\n")
-
- def unplug_interface(self, tenant_id, net_id, port_id):
- """
- Detaches a remote interface from the specified port on the
- specified Virtual Network.
- """
- print("unplug_interface() called\n")
-
- supported_extension_aliases = ["FOXNSOX"]
-
- def method_to_support_foxnsox_extension(self):
- print("method_to_support_foxnsox_extension() called\n")
-
-
-class FakePlugin(object):
- """
- FakePlugin is a demo plugin that provides
- in-memory data structures to aid in quantum
- client/cli/api development
- """
-
- def __init__(self):
- db.configure_db({'sql_connection': 'sqlite:///:memory:'})
- FakePlugin._net_counter = 0
-
- def _get_network(self, tenant_id, network_id):
-
- db.validate_network_ownership(tenant_id, network_id)
- try:
- network = db.network_get(network_id)
- except:
- raise exc.NetworkNotFound(net_id=network_id)
- return network
-
- def _get_port(self, tenant_id, network_id, port_id):
-
- db.validate_port_ownership(tenant_id, network_id, port_id)
- net = self._get_network(tenant_id, network_id)
- try:
- port = db.port_get(port_id, network_id)
- except:
- raise exc.PortNotFound(net_id=network_id, port_id=port_id)
- # Port must exist and belong to the appropriate network.
- if port['network_id'] != net['uuid']:
- raise exc.PortNotFound(net_id=network_id, port_id=port_id)
- return port
-
- def _validate_port_state(self, port_state):
- if port_state.upper() not in ('ACTIVE', 'DOWN'):
- raise exc.StateInvalid(port_state=port_state)
- return True
-
- def _validate_attachment(self, tenant_id, network_id, port_id,
- remote_interface_id):
- for port in db.port_list(network_id):
- if port['interface_id'] == remote_interface_id:
- raise exc.AlreadyAttached(net_id=network_id,
- port_id=port_id,
- att_id=port['interface_id'],
- att_port_id=port['uuid'])
-
- def get_all_networks(self, tenant_id, **kwargs):
- """
- Returns a dictionary containing all
- <network_uuid, network_name> for
- the specified tenant.
- """
- LOG.debug("FakePlugin.get_all_networks() called")
- filter_opts = kwargs.get('filter_opts', None)
- if not filter_opts is None and len(filter_opts) > 0:
- LOG.debug("filtering options were passed to the plugin"
- "but the Fake plugin does not support them")
- nets = []
- for net in db.network_list(tenant_id):
- net_item = {'net-id': str(net.uuid),
- 'net-name': net.name,
- 'net-op-status': net.op_status}
- nets.append(net_item)
- return nets
-
- def get_network_details(self, tenant_id, net_id):
- """
- retrieved a list of all the remote vifs that
- are attached to the network
- """
- LOG.debug("FakePlugin.get_network_details() called")
- net = self._get_network(tenant_id, net_id)
- # Retrieves ports for network
- ports = self.get_all_ports(tenant_id, net_id)
- return {'net-id': str(net.uuid),
- 'net-name': net.name,
- 'net-op-status': net.op_status,
- 'net-ports': ports}
-
- def create_network(self, tenant_id, net_name, **kwargs):
- """
- Creates a new Virtual Network, and assigns it
- a symbolic name.
- """
- LOG.debug("FakePlugin.create_network() called")
- new_net = db.network_create(tenant_id, net_name)
- # Put operational status UP
- db.network_update(new_net.uuid, net_name,
- op_status=OperationalStatus.UP)
- # Return uuid for newly created network as net-id.
- return {'net-id': new_net.uuid}
-
- def delete_network(self, tenant_id, net_id):
- """
- Deletes the network with the specified network identifier
- belonging to the specified tenant.
- """
- LOG.debug("FakePlugin.delete_network() called")
- net = self._get_network(tenant_id, net_id)
- # Verify that no attachments are plugged into the network
- if net:
- for port in db.port_list(net_id):
- if port['interface_id']:
- raise exc.NetworkInUse(net_id=net_id)
- db.network_destroy(net_id)
- return net
- # Network not found
- raise exc.NetworkNotFound(net_id=net_id)
-
- def update_network(self, tenant_id, net_id, **kwargs):
- """
- Updates the attributes of a particular Virtual Network.
- """
- LOG.debug("FakePlugin.update_network() called")
- net = db.network_update(net_id, tenant_id, **kwargs)
- return net
-
- def get_all_ports(self, tenant_id, net_id, **kwargs):
- """
- Retrieves all port identifiers belonging to the
- specified Virtual Network.
- """
- LOG.debug("FakePlugin.get_all_ports() called")
- db.validate_network_ownership(tenant_id, net_id)
- filter_opts = kwargs.get('filter_opts')
- if filter_opts:
- LOG.debug("filtering options were passed to the plugin"
- "but the Fake plugin does not support them")
- port_ids = []
- ports = db.port_list(net_id)
- for x in ports:
- d = {'port-id': str(x.uuid)}
- port_ids.append(d)
- return port_ids
-
- def get_port_details(self, tenant_id, net_id, port_id):
- """
- This method allows the user to retrieve a remote interface
- that is attached to this particular port.
- """
- LOG.debug("FakePlugin.get_port_details() called")
- port = self._get_port(tenant_id, net_id, port_id)
- return {'port-id': str(port.uuid),
- 'attachment': port.interface_id,
- 'port-state': port.state,
- 'port-op-status': port.op_status}
-
- def create_port(self, tenant_id, net_id, port_state=None, **kwargs):
- """
- Creates a port on the specified Virtual Network.
- """
- LOG.debug("FakePlugin.create_port() called")
- # verify net_id
- self._get_network(tenant_id, net_id)
- port = db.port_create(net_id, port_state)
- # Put operational status UP
- db.port_update(port.uuid, net_id, op_status=OperationalStatus.UP)
- port_item = {'port-id': str(port.uuid)}
- return port_item
-
- def update_port(self, tenant_id, net_id, port_id, **kwargs):
- """
- Updates the attributes of a port on the specified Virtual Network.
- """
- LOG.debug("FakePlugin.update_port() called")
- #validate port and network ids
- self._get_network(tenant_id, net_id)
- self._get_port(tenant_id, net_id, port_id)
- port = db.port_update(port_id, net_id, **kwargs)
- port_item = {'port-id': port_id, 'port-state': port['state']}
- return port_item
-
- def delete_port(self, tenant_id, net_id, port_id):
- """
- Deletes a port on a specified Virtual Network,
- if the port contains a remote interface attachment,
- the remote interface is first un-plugged and then the port
- is deleted.
- """
- LOG.debug("FakePlugin.delete_port() called")
- net = self._get_network(tenant_id, net_id)
- port = self._get_port(tenant_id, net_id, port_id)
- if port['interface_id']:
- raise exc.PortInUse(net_id=net_id, port_id=port_id,
- att_id=port['interface_id'])
- try:
- port = db.port_destroy(port_id, net_id)
- except Exception, e:
- raise Exception("Failed to delete port: %s" % str(e))
- d = {}
- d["port-id"] = str(port.uuid)
- return d
-
- def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id):
- """
- Attaches a remote interface to the specified port on the
- specified Virtual Network.
- """
- LOG.debug("FakePlugin.plug_interface() called")
- port = self._get_port(tenant_id, net_id, port_id)
- # Validate attachment
- self._validate_attachment(tenant_id, net_id, port_id,
- remote_interface_id)
- if port['interface_id']:
- raise exc.PortInUse(net_id=net_id, port_id=port_id,
- att_id=port['interface_id'])
- db.port_set_attachment(port_id, net_id, remote_interface_id)
-
- def unplug_interface(self, tenant_id, net_id, port_id):
- """
- Detaches a remote interface from the specified port on the
- specified Virtual Network.
- """
- LOG.debug("FakePlugin.unplug_interface() called")
- self._get_port(tenant_id, net_id, port_id)
- # TODO(salvatore-orlando):
- # Should unplug on port without attachment raise an Error?
- db.port_unset_attachment(port_id, net_id)
+++ /dev/null
-# Copyright (c) 2012 OpenStack, LLC.
-#
-# 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 logging
-import uuid
-
-from quantum import quantum_plugin_base_v2
-
-
-LOG = logging.getLogger(__name__)
-
-
-class QuantumEchoPlugin(quantum_plugin_base_v2.QuantumPluginBaseV2):
-
- """
- QuantumEchoPlugin is a demo plugin that doesn't
- do anything but demonstrate the concept of a
- concrete Quantum Plugin. Any call to this plugin
- will result in just a log statement with the name
- method that was called and its arguments.
- """
-
- def _log(self, name, context, **kwargs):
- kwarg_msg = ' '.join([('%s: |%s|' % (str(key), kwargs[key]))
- for key in kwargs])
-
- # TODO(anyone) Add a nice __repr__ and __str__ to context
- #LOG.debug('%s context: %s %s' % (name, context, kwarg_msg))
- LOG.debug('%s %s' % (name, kwarg_msg))
-
- def create_subnet(self, context, subnet):
- self._log("create_subnet", context, subnet=subnet)
- res = {"id": str(uuid.uuid4())}
- res.update(subnet)
- return res
-
- def update_subnet(self, context, id, subnet):
- self._log("update_subnet", context, id=id, subnet=subnet)
- res = {"id": id}
- res.update(subnet)
- return res
-
- def get_subnet(self, context, id, show=None, verbose=None):
- self._log("get_subnet", context, id=id, show=show,
- verbose=verbose)
- return {"id": id}
-
- def delete_subnet(self, context, id):
- self._log("delete_subnet", context, id=id)
-
- def get_subnets(self, context, filters=None, show=None, verbose=None):
- self._log("get_subnets", context, filters=filters, show=show,
- verbose=verbose)
- return []
-
- def create_network(self, context, network):
- self._log("create_network", context, network=network)
- res = {"id": str(uuid.uuid4())}
- res.update(network)
- return res
-
- def update_network(self, context, id, network):
- self._log("update_network", context, id=id, network=network)
- res = {"id": id}
- res.update(network)
- return res
-
- def get_network(self, context, id, show=None, verbose=None):
- self._log("get_network", context, id=id, show=show,
- verbose=verbose)
- return {"id": id}
-
- def delete_network(self, context, id):
- self._log("delete_network", context, id=id)
-
- def get_networks(self, context, filters=None, show=None, verbose=None):
- self._log("get_networks", context, filters=filters, show=show,
- verbose=verbose)
- return []
-
- def create_port(self, context, port):
- self._log("create_port", context, port=port)
- res = {"id": str(uuid.uuid4())}
- res.update(port)
- return res
-
- def update_port(self, context, id, port):
- self._log("update_port", context, id=id, port=port)
- res = {"id": id}
- res.update(port)
- return res
-
- def get_port(self, context, id, show=None, verbose=None):
- self._log("get_port", context, id=id, show=show,
- verbose=verbose)
- return {"id": id}
-
- def delete_port(self, context, id):
- self._log("delete_port", context, id=id)
-
- def get_ports(self, context, filters=None, show=None, verbose=None):
- self._log("get_ports", context, filters=filters, show=show,
- verbose=verbose)
- return []
-
- supported_extension_aliases = ["FOXNSOX"]
-
- def method_to_support_foxnsox_extension(self, context):
- self._log("method_to_support_foxnsox_extension", context)
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright 2011 Nicira Networks, Inc.
-# 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.
-# @author: Somik Behera, Nicira Networks, Inc.
-
-"""
-Quantum Plug-in API specification.
-
-QuantumPluginBase provides the definition of minimum set of
-methods that needs to be implemented by a Quantum Plug-in.
-"""
-
-from abc import ABCMeta, abstractmethod
-import inspect
-
-
-class QuantumPluginBase(object):
-
- __metaclass__ = ABCMeta
-
- @abstractmethod
- def get_all_networks(self, tenant_id, **kwargs):
- """
- Returns a dictionary containing all
- <network_uuid, network_name> for
- the specified tenant.
- :param tenant_id: unique identifier for the tenant whose networks
- are being retrieved by this method
- :param **kwargs: options to be passed to the plugin. The following
- keywork based-options can be specified:
- filter_opts - options for filtering network list
- :returns: a list of mapping sequences with the following signature:
- [ {'net-id': uuid that uniquely identifies
- the particular quantum network,
- 'net-name': a human-readable name associated
- with network referenced by net-id
- },
- ....
- {'net-id': uuid that uniquely identifies the
- particular quantum network,
- 'net-name': a human-readable name associated
- with network referenced by net-id
- }
- ]
- :raises: None
- """
- pass
-
- @abstractmethod
- def create_network(self, tenant_id, net_name, **kwargs):
- """
- Creates a new Virtual Network, and assigns it
- a symbolic name.
-
- :returns: a sequence of mappings with the following signature:
- {'net-id': uuid that uniquely identifies the
- particular quantum network,
- 'net-name': a human-readable name associated
- with network referenced by net-id
- }
- :raises:
- """
- pass
-
- @abstractmethod
- def delete_network(self, tenant_id, net_id):
- """
- Deletes the network with the specified network identifier
- belonging to the specified tenant.
-
- :returns: a sequence of mappings with the following signature:
- {'net-id': uuid that uniquely identifies the
- particular quantum network
- }
- :raises: exception.NetworkInUse
- :raises: exception.NetworkNotFound
- """
- pass
-
- @abstractmethod
- def get_network_details(self, tenant_id, net_id):
- """
- Retrieves a list of all the remote vifs that
- are attached to the network.
-
- :returns: a sequence of mappings with the following signature:
- {'net-id': uuid that uniquely identifies the
- particular quantum network
- 'net-name': a human-readable name associated
- with network referenced by net-id
- 'net-ifaces': ['vif1_on_network_uuid',
- 'vif2_on_network_uuid',...,'vifn_uuid']
- }
- :raises: exception.NetworkNotFound
- """
- pass
-
- @abstractmethod
- def update_network(self, tenant_id, net_id, **kwargs):
- """
- Updates the attributes of a particular Virtual Network.
-
- :returns: a sequence of mappings representing the new network
- attributes, with the following signature:
- {'net-id': uuid that uniquely identifies the
- particular quantum network
- 'net-name': the new human-readable name
- associated with network referenced by net-id
- }
- :raises: exception.NetworkNotFound
- """
- pass
-
- @abstractmethod
- def get_all_ports(self, tenant_id, net_id, **kwargs):
- """
- Retrieves all port identifiers belonging to the
- specified Virtual Network.
- :param tenant_id: unique identifier for the tenant for which this
- method is going to retrieve ports
- :param net_id: unique identifiers for the network whose ports are
- about to be retrieved
- :param **kwargs: options to be passed to the plugin. The following
- keywork based-options can be specified:
- filter_opts - options for filtering network list
- :returns: a list of mapping sequences with the following signature:
- [ {'port-id': uuid representing a particular port
- on the specified quantum network
- },
- ....
- {'port-id': uuid representing a particular port
- on the specified quantum network
- }
- ]
- :raises: exception.NetworkNotFound
- """
- pass
-
- @abstractmethod
- def create_port(self, tenant_id, net_id, port_state=None, **kwargs):
- """
- Creates a port on the specified Virtual Network.
-
- :returns: a mapping sequence with the following signature:
- {'port-id': uuid representing the created port
- on specified quantum network
- }
- :raises: exception.NetworkNotFound
- :raises: exception.StateInvalid
- """
- pass
-
- @abstractmethod
- def update_port(self, tenant_id, net_id, port_id, **kwargs):
- """
- Updates the attributes of a specific port on the
- specified Virtual Network.
-
- :returns: a mapping sequence with the following signature:
- {'port-id': uuid representing the
- updated port on specified quantum network
- 'port-state': update port state( UP or DOWN)
- }
- :raises: exception.StateInvalid
- :raises: exception.PortNotFound
- """
- pass
-
- @abstractmethod
- def delete_port(self, tenant_id, net_id, port_id):
- """
- Deletes a port on a specified Virtual Network,
- if the port contains a remote interface attachment,
- the remote interface is first un-plugged and then the port
- is deleted.
-
- :returns: a mapping sequence with the following signature:
- {'port-id': uuid representing the deleted port
- on specified quantum network
- }
- :raises: exception.PortInUse
- :raises: exception.PortNotFound
- :raises: exception.NetworkNotFound
- """
- pass
-
- @abstractmethod
- def get_port_details(self, tenant_id, net_id, port_id):
- """
- This method allows the user to retrieve a remote interface
- that is attached to this particular port.
-
- :returns: a mapping sequence with the following signature:
- {'port-id': uuid representing the port on
- specified quantum network
- 'net-id': uuid representing the particular
- quantum network
- 'attachment': uuid of the virtual interface
- bound to the port, None otherwise
- }
- :raises: exception.PortNotFound
- :raises: exception.NetworkNotFound
- """
- pass
-
- @abstractmethod
- def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id):
- """
- Attaches a remote interface to the specified port on the
- specified Virtual Network.
-
- :returns: None
- :raises: exception.NetworkNotFound
- :raises: exception.PortNotFound
- :raises: exception.AlreadyAttached
- (? should the network automatically unplug/replug)
- """
- pass
-
- @abstractmethod
- def unplug_interface(self, tenant_id, net_id, port_id):
- """
- Detaches a remote interface from the specified port on the
- specified Virtual Network.
-
- :returns: None
- :raises: exception.NetworkNotFound
- :raises: exception.PortNotFound
- """
- pass
-
- @classmethod
- def __subclasshook__(cls, klass):
- """
- The __subclasshook__ method is a class method
- that will be called everytime a class is tested
- using issubclass(klass, Plugin).
- In that case, it will check that every method
- marked with the abstractmethod decorator is
- provided by the plugin class.
- """
- if cls is QuantumPluginBase:
- for method in cls.__abstractmethods__:
- method_ok = False
- for base in klass.__mro__:
- if method in base.__dict__:
- fn_obj = base.__dict__[method]
- if inspect.isfunction(fn_obj):
- abstract_fn_obj = cls.__dict__[method]
- arg_count = fn_obj.func_code.co_argcount
- expected_arg_count = (
- abstract_fn_obj.func_code.co_argcount)
- method_ok = arg_count == expected_arg_count
- if method_ok:
- continue
- return NotImplemented
- return True
- return NotImplemented
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010-2011 ????
-# 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.
-# @author: Brad Hall, Nicira Networks
-# @author: Salvatore Orlando, Citrix Systems
-
-import logging
-import unittest2 as unittest
-
-import mock
-import os
-
-from quantum.api.api_common import APIFaultWrapper
-from quantum.api.networks import Controller
-from quantum.common import config
-from quantum.common.test_lib import test_config
-from quantum.db import api as db
-from quantum.openstack.common import cfg
-from quantum.openstack.common import importutils
-import quantum.tests.unit.testlib_api as testlib
-from quantum.wsgi import XMLDeserializer, JSONDeserializer
-
-
-LOG = logging.getLogger('quantum.tests.test_api')
-
-
-ROOTDIR = os.path.dirname(os.path.dirname(__file__))
-ETCDIR = os.path.join(ROOTDIR, 'etc')
-
-
-def etcdir(*p):
- return os.path.join(ETCDIR, *p)
-
-
-NETS = "networks"
-PORTS = "ports"
-ATTS = "attachments"
-
-
-class AbstractAPITest(unittest.TestCase):
- """ Base class definiting some methods for API tests """
-
- def _deserialize_net_response(self, content_type, response):
- network_data = (self._net_deserializers[content_type].
- deserialize(response.body)['body'])
- # do not taint assertions with xml namespace
- if 'xmlns' in network_data['network']:
- del network_data['network']['xmlns']
- return network_data
-
- def _deserialize_port_response(self, content_type, response):
- port_data = (self._port_deserializers[content_type].
- deserialize(response.body)['body'])
- # do not taint assertions with xml namespace
- if 'xmlns' in port_data['port']:
- del port_data['port']['xmlns']
- return port_data
-
- def _create_network(self, fmt, name=None, custom_req_body=None,
- expected_res_status=None):
- LOG.debug("Creating network")
- content_type = "application/" + fmt
- if name:
- net_name = name
- else:
- net_name = self.network_name
- network_req = testlib.new_network_request(self.tenant_id,
- net_name, fmt,
- custom_req_body)
- network_res = network_req.get_response(self.api)
- expected_res_status = (expected_res_status or
- self._successful_create_code)
- self.assertEqual(network_res.status_int, expected_res_status)
- if expected_res_status in (200, 202):
- network_data = self._deserialize_net_response(content_type,
- network_res)
- return network_data['network']['id']
-
- def _create_port(self, network_id, port_state, fmt, custom_req_body=None,
- expected_res_status=None):
- LOG.debug("Creating port for network %s", network_id)
- content_type = "application/%s" % fmt
- port_req = testlib.new_port_request(self.tenant_id, network_id,
- port_state, fmt,
- custom_req_body)
- port_res = port_req.get_response(self.api)
- expected_res_status = (expected_res_status or
- self._successful_create_code)
- self.assertEqual(port_res.status_int, expected_res_status)
- if expected_res_status in (200, 202):
- port_data = self._deserialize_port_response(content_type,
- port_res)
- return port_data['port']['id']
-
- def _set_attachment(self, network_id, port_id, interface_id, fmt,
- expected_res_status=204):
- put_attachment_req = testlib.put_attachment_request(self.tenant_id,
- network_id,
- port_id,
- interface_id,
- fmt)
- put_attachment_res = put_attachment_req.get_response(self.api)
- self.assertEqual(put_attachment_res.status_int, expected_res_status)
-
- def setUp(self, api_router_klass, xml_metadata_dict):
- # Create the default configurations
- args = ['--config-file', etcdir('quantum.conf.test')]
- config.parse(args=args)
- # Update the plugin
- cfg.CONF.set_override('core_plugin', test_config['plugin_name'])
- api_router_cls = importutils.import_class(api_router_klass)
- self.api = api_router_cls()
- self.tenant_id = "test_tenant"
- self.network_name = "test_network"
-
- # Prepare XML & JSON deserializers
- net_xml_deserializer = XMLDeserializer(xml_metadata_dict[NETS])
- port_xml_deserializer = XMLDeserializer(xml_metadata_dict[PORTS])
- att_xml_deserializer = XMLDeserializer(xml_metadata_dict[ATTS])
-
- json_deserializer = JSONDeserializer()
-
- self._net_deserializers = {
- 'application/xml': net_xml_deserializer,
- 'application/json': json_deserializer,
- }
- self._port_deserializers = {
- 'application/xml': port_xml_deserializer,
- 'application/json': json_deserializer,
- }
- self._att_deserializers = {
- 'application/xml': att_xml_deserializer,
- 'application/json': json_deserializer,
- }
-
- def tearDown(self):
- """Clear the test environment"""
- # Remove database contents
- db.clear_db()
- cfg.CONF.reset()
-
-
-class BaseAPIOperationsTest(AbstractAPITest):
- """Abstract base class for Quantum API unit tests
- Defined according to operations defined for Quantum API v1.0
- """
-
- def _test_create_network(self, fmt):
- LOG.debug("_test_create_network - fmt:%s - START", fmt)
- content_type = "application/%s" % fmt
- network_id = self._create_network(fmt)
- show_network_req = testlib.show_network_request(self.tenant_id,
- network_id,
- fmt)
- show_network_res = show_network_req.get_response(self.api)
- self.assertEqual(show_network_res.status_int, 200)
- network_data = (self._net_deserializers[content_type].
- deserialize(show_network_res.body)['body'])
- self.assertEqual(network_id, network_data['network']['id'])
- LOG.debug("_test_create_network - fmt:%s - END", fmt)
-
- def _test_create_network_badrequest(self, fmt):
- LOG.debug("_test_create_network_badrequest - fmt:%s - START", fmt)
- bad_body = {'network': {'bad-attribute': 'very-bad'}}
- self._create_network(fmt, custom_req_body=bad_body,
- expected_res_status=400)
- LOG.debug("_test_create_network_badrequest - fmt:%s - END", fmt)
-
- def _test_list_networks(self, fmt):
- LOG.debug("_test_list_networks - fmt:%s - START", fmt)
- content_type = "application/%s" % fmt
- self._create_network(fmt, "net_1")
- self._create_network(fmt, "net_2")
- list_network_req = testlib.network_list_request(self.tenant_id,
- fmt)
- list_network_res = list_network_req.get_response(self.api)
- self.assertEqual(list_network_res.status_int, 200)
- network_data = (self._net_deserializers[content_type].
- deserialize(list_network_res.body)['body'])
- # Check network count: should return 2
- self.assertEqual(len(network_data['networks']), 2)
- LOG.debug("_test_list_networks - fmt:%s - END", fmt)
-
- def _test_list_networks_detail(self, fmt):
- LOG.debug("_test_list_networks_detail - fmt:%s - START", fmt)
- content_type = "application/%s" % fmt
- self._create_network(fmt, "net_1")
- self._create_network(fmt, "net_2")
- list_network_req = testlib.network_list_detail_request(self.tenant_id,
- fmt)
- list_network_res = list_network_req.get_response(self.api)
- self.assertEqual(list_network_res.status_int, 200)
- network_data = (self._net_deserializers[content_type].
- deserialize(list_network_res.body)['body'])
- # Check network count: should return 2
- self.assertEqual(len(network_data['networks']), 2)
- # Check contents - id & name for each network
- for network in network_data['networks']:
- self.assertTrue('id' in network and 'name' in network)
- self.assertTrue(network['id'] and network['name'])
- LOG.debug("_test_list_networks_detail - fmt:%s - END", fmt)
-
- def _test_show_network(self, fmt):
- LOG.debug("_test_show_network - fmt:%s - START", fmt)
- content_type = "application/%s" % fmt
- network_id = self._create_network(fmt)
- show_network_req = testlib.show_network_request(self.tenant_id,
- network_id,
- fmt)
- show_network_res = show_network_req.get_response(self.api)
- self.assertEqual(show_network_res.status_int, 200)
- network_data = self._deserialize_net_response(content_type,
- show_network_res)
- self.assert_network(id=network_id, name=self.network_name,
- network_data=network_data['network'])
- LOG.debug("_test_show_network - fmt:%s - END", fmt)
-
- def _test_show_network_detail(self, fmt):
- LOG.debug("_test_show_network_detail - fmt:%s - START", fmt)
- content_type = "application/%s" % fmt
- # Create a network and a port
- network_id = self._create_network(fmt)
- port_id = self._create_port(network_id, "ACTIVE", fmt)
- show_network_req = testlib.show_network_detail_request(self.tenant_id,
- network_id,
- fmt)
- show_network_res = show_network_req.get_response(self.api)
- self.assertEqual(show_network_res.status_int, 200)
- network_data = self._deserialize_net_response(content_type,
- show_network_res)
- self.assert_network_details(id=network_id, name=self.network_name,
- port_id=port_id, port_state='ACTIVE',
- network_data=network_data['network'])
- LOG.debug("_test_show_network_detail - fmt:%s - END", fmt)
-
- def _test_show_network_not_found(self, fmt):
- LOG.debug("_test_show_network_not_found - fmt:%s - START", fmt)
- show_network_req = testlib.show_network_request(self.tenant_id,
- "A_BAD_ID",
- fmt)
- show_network_res = show_network_req.get_response(self.api)
- self.assertEqual(show_network_res.status_int,
- self._network_not_found_code)
- LOG.debug("_test_show_network_not_found - fmt:%s - END", fmt)
-
- def _test_rename_network(self, fmt):
- LOG.debug("_test_rename_network - fmt:%s - START", fmt)
- content_type = "application/%s" % fmt
- new_name = 'new_network_name'
- network_id = self._create_network(fmt)
- update_network_req = testlib.update_network_request(self.tenant_id,
- network_id,
- new_name,
- fmt)
- update_network_res = update_network_req.get_response(self.api)
- self.assertEqual(update_network_res.status_int, 204)
- show_network_req = testlib.show_network_request(self.tenant_id,
- network_id,
- fmt)
- show_network_res = show_network_req.get_response(self.api)
- self.assertEqual(show_network_res.status_int, 200)
- network_data = self._deserialize_net_response(content_type,
- show_network_res)
- self.assert_network(id=network_id, name=new_name,
- network_data=network_data['network'])
- LOG.debug("_test_rename_network - fmt:%s - END", fmt)
-
- def _test_rename_network_badrequest(self, fmt):
- LOG.debug("_test_rename_network_badrequest - fmt:%s - START", fmt)
- network_id = self._create_network(fmt)
- bad_body = {'network': {'bad-attribute': 'very-bad'}}
- update_network_req = testlib.update_network_request(
- self.tenant_id,
- network_id, fmt,
- custom_req_body=bad_body)
- update_network_res = update_network_req.get_response(self.api)
- self.assertEqual(update_network_res.status_int, 400)
- LOG.debug("_test_rename_network_badrequest - fmt:%s - END", fmt)
-
- def _test_rename_network_not_found(self, fmt):
- LOG.debug("_test_rename_network_not_found - fmt:%s - START", fmt)
- new_name = 'new_network_name'
- update_network_req = testlib.update_network_request(self.tenant_id,
- "A BAD ID",
- new_name,
- fmt)
- update_network_res = update_network_req.get_response(self.api)
- self.assertEqual(update_network_res.status_int,
- self._network_not_found_code)
- LOG.debug("_test_rename_network_not_found - fmt:%s - END", fmt)
-
- def _test_delete_network(self, fmt):
- LOG.debug("_test_delete_network - fmt:%s - START", fmt)
- content_type = "application/%s" % fmt
- network_id = self._create_network(fmt)
- LOG.debug("Deleting network %s of tenant %s" %
- (network_id, self.tenant_id))
- delete_network_req = testlib.network_delete_request(self.tenant_id,
- network_id,
- fmt)
- delete_network_res = delete_network_req.get_response(self.api)
- self.assertEqual(delete_network_res.status_int, 204)
- list_network_req = testlib.network_list_request(self.tenant_id,
- fmt)
- list_network_res = list_network_req.get_response(self.api)
- network_list_data = (self._net_deserializers[content_type].
- deserialize(list_network_res.body)['body'])
- network_count = len(network_list_data['networks'])
- self.assertEqual(network_count, 0)
- LOG.debug("_test_delete_network - fmt:%s - END", fmt)
-
- def _test_delete_network_in_use(self, fmt):
- LOG.debug("_test_delete_network_in_use - fmt:%s - START", fmt)
- port_state = "ACTIVE"
- attachment_id = "test_attachment"
- network_id = self._create_network(fmt)
- LOG.debug("Deleting network %s of tenant %s" %
- (network_id, self.tenant_id))
- port_id = self._create_port(network_id, port_state, fmt)
- #plug an attachment into the port
- LOG.debug("Putting attachment into port %s", port_id)
- attachment_req = testlib.put_attachment_request(self.tenant_id,
- network_id,
- port_id,
- attachment_id)
- attachment_res = attachment_req.get_response(self.api)
- self.assertEquals(attachment_res.status_int, 204)
-
- LOG.debug("Deleting network %s of tenant %s" %
- (network_id, self.tenant_id))
- delete_network_req = testlib.network_delete_request(self.tenant_id,
- network_id,
- fmt)
- delete_network_res = delete_network_req.get_response(self.api)
- self.assertEqual(delete_network_res.status_int,
- self._network_in_use_code)
- LOG.debug("_test_delete_network_in_use - fmt:%s - END", fmt)
-
- def _test_delete_network_with_unattached_port(self, fmt):
- LOG.debug("_test_delete_network_with_unattached_port "
- "- fmt:%s - START", fmt)
- port_state = "ACTIVE"
- network_id = self._create_network(fmt)
- LOG.debug("Deleting network %s of tenant %s" %
- (network_id, self.tenant_id))
- self._create_port(network_id, port_state, fmt)
-
- LOG.debug("Deleting network %s of tenant %s" %
- (network_id, self.tenant_id))
- delete_network_req = testlib.network_delete_request(self.tenant_id,
- network_id,
- fmt)
- delete_network_res = delete_network_req.get_response(self.api)
- self.assertEqual(delete_network_res.status_int, 204)
- LOG.debug("_test_delete_network_with_unattached_port - fmt:%s - END",
- fmt)
-
- def _test_list_ports(self, fmt):
- LOG.debug("_test_list_ports - fmt:%s - START", fmt)
- content_type = "application/%s" % fmt
- port_state = "ACTIVE"
- network_id = self._create_network(fmt)
- self._create_port(network_id, port_state, fmt)
- self._create_port(network_id, port_state, fmt)
- list_port_req = testlib.port_list_request(self.tenant_id,
- network_id, fmt)
- list_port_res = list_port_req.get_response(self.api)
- self.assertEqual(list_port_res.status_int, 200)
- port_data = (self._port_deserializers[content_type].
- deserialize(list_port_res.body)['body'])
- # Check port count: should return 2
- self.assertEqual(len(port_data['ports']), 2)
- LOG.debug("_test_list_ports - fmt:%s - END", fmt)
-
- def _test_list_ports_networknotfound(self, fmt):
- LOG.debug("_test_list_ports_networknotfound"
- " - fmt:%s - START", fmt)
- list_port_req = testlib.port_list_request(self.tenant_id,
- "A_BAD_ID", fmt)
- list_port_res = list_port_req.get_response(self.api)
- self.assertEqual(list_port_res.status_int,
- self._network_not_found_code)
- LOG.debug("_test_list_ports_networknotfound - fmt:%s - END", fmt)
-
- def _test_list_ports_detail(self, fmt):
- LOG.debug("_test_list_ports_detail - fmt:%s - START", fmt)
- content_type = "application/%s" % fmt
- port_state = "ACTIVE"
- network_id = self._create_network(fmt)
- self._create_port(network_id, port_state, fmt)
- self._create_port(network_id, port_state, fmt)
- list_port_req = testlib.port_list_detail_request(self.tenant_id,
- network_id, fmt)
- list_port_res = list_port_req.get_response(self.api)
- self.assertEqual(list_port_res.status_int, 200)
- port_data = (self._port_deserializers[content_type].
- deserialize(list_port_res.body)['body'])
- # Check port count: should return 2
- self.assertEqual(len(port_data['ports']), 2)
- # Check contents - id & name for each network
- for port in port_data['ports']:
- self.assertTrue('id' in port and 'state' in port)
- self.assertTrue(port['id'] and port['state'])
- LOG.debug("_test_list_ports_detail - fmt:%s - END", fmt)
-
- def _test_show_port(self, fmt):
- LOG.debug("_test_show_port - fmt:%s - START", fmt)
- content_type = "application/%s" % fmt
- port_state = "ACTIVE"
- network_id = self._create_network(fmt)
- port_id = self._create_port(network_id, port_state, fmt)
- show_port_req = testlib.show_port_request(self.tenant_id,
- network_id, port_id,
- fmt)
- show_port_res = show_port_req.get_response(self.api)
- self.assertEqual(show_port_res.status_int, 200)
- port_data = self._deserialize_port_response(content_type,
- show_port_res)
- self.assert_port(id=port_id, state=port_state,
- port_data=port_data['port'])
- LOG.debug("_test_show_port - fmt:%s - END", fmt)
-
- def _test_show_port_detail(self, fmt):
- LOG.debug("_test_show_port - fmt:%s - START", fmt)
- content_type = "application/%s" % fmt
- port_state = "ACTIVE"
- network_id = self._create_network(fmt)
- port_id = self._create_port(network_id, port_state, fmt)
-
- # Part 1 - no attachment
- show_port_req = testlib.show_port_detail_request(
- self.tenant_id, network_id, port_id, fmt)
- show_port_res = show_port_req.get_response(self.api)
- self.assertEqual(show_port_res.status_int, 200)
- port_data = self._deserialize_port_response(content_type,
- show_port_res)
- self.assert_port(id=port_id, state=port_state,
- port_data=port_data['port'])
-
- # Part 2 - plug attachment into port
- interface_id = "test_interface"
- put_attachment_req = testlib.put_attachment_request(self.tenant_id,
- network_id,
- port_id,
- interface_id,
- fmt)
- put_attachment_res = put_attachment_req.get_response(self.api)
- self.assertEqual(put_attachment_res.status_int, 204)
- show_port_req = testlib.show_port_detail_request(
- self.tenant_id, network_id, port_id, fmt)
- show_port_res = show_port_req.get_response(self.api)
- self.assertEqual(show_port_res.status_int, 200)
- port_data = self._deserialize_port_response(content_type,
- show_port_res)
- self.assert_port_attachment(id=port_id, state=port_state,
- interface_id=interface_id,
- port_data=port_data['port'])
-
- LOG.debug("_test_show_port_detail - fmt:%s - END", fmt)
-
- def _test_show_port_networknotfound(self, fmt):
- LOG.debug("_test_show_port_networknotfound - fmt:%s - START", fmt)
- port_state = "ACTIVE"
- network_id = self._create_network(fmt)
- port_id = self._create_port(network_id, port_state, fmt)
- show_port_req = testlib.show_port_request(self.tenant_id,
- "A_BAD_ID", port_id,
- fmt)
- show_port_res = show_port_req.get_response(self.api)
- self.assertEqual(show_port_res.status_int,
- self._network_not_found_code)
- LOG.debug("_test_show_port_networknotfound - fmt:%s - END", fmt)
-
- def _test_show_port_portnotfound(self, fmt):
- LOG.debug("_test_show_port_portnotfound - fmt:%s - START", fmt)
- network_id = self._create_network(fmt)
- show_port_req = testlib.show_port_request(self.tenant_id,
- network_id,
- "A_BAD_ID",
- fmt)
- show_port_res = show_port_req.get_response(self.api)
- self.assertEqual(show_port_res.status_int,
- self._port_not_found_code)
- LOG.debug("_test_show_port_portnotfound - fmt:%s - END", fmt)
-
- def _test_create_port_noreqbody(self, fmt):
- LOG.debug("_test_create_port_noreqbody - fmt:%s - START", fmt)
- content_type = "application/%s" % fmt
- network_id = self._create_network(fmt)
- port_id = self._create_port(network_id, None, fmt,
- custom_req_body='')
- show_port_req = testlib.show_port_request(self.tenant_id,
- network_id, port_id, fmt)
- show_port_res = show_port_req.get_response(self.api)
- self.assertEqual(show_port_res.status_int, 200)
- port_data = (self._port_deserializers[content_type].
- deserialize(show_port_res.body)['body'])
- self.assertEqual(port_id, port_data['port']['id'])
- LOG.debug("_test_create_port_noreqbody - fmt:%s - END", fmt)
-
- def _test_create_port(self, fmt):
- LOG.debug("_test_create_port - fmt:%s - START", fmt)
- content_type = "application/%s" % fmt
- port_state = "ACTIVE"
- network_id = self._create_network(fmt)
- port_id = self._create_port(network_id, port_state, fmt)
- show_port_req = testlib.show_port_request(self.tenant_id,
- network_id, port_id, fmt)
- show_port_res = show_port_req.get_response(self.api)
- self.assertEqual(show_port_res.status_int, 200)
- port_data = (self._port_deserializers[content_type].
- deserialize(show_port_res.body)['body'])
- self.assertEqual(port_id, port_data['port']['id'])
- LOG.debug("_test_create_port - fmt:%s - END", fmt)
-
- def _test_create_port_networknotfound(self, fmt):
- LOG.debug("_test_create_port_networknotfound - fmt:%s - START", fmt)
- port_state = "ACTIVE"
- self._create_port("A_BAD_ID", port_state, fmt,
- expected_res_status=self._network_not_found_code)
- LOG.debug("_test_create_port_networknotfound - fmt:%s - END", fmt)
-
- def _test_create_port_badrequest(self, fmt):
- LOG.debug("_test_create_port_badrequest - fmt:%s - START", fmt)
- bad_body = {'bad-resource': {'bad-attribute': 'bad-value'}}
- network_id = self._create_network(fmt)
- port_state = "ACTIVE"
- self._create_port(network_id, port_state, fmt,
- custom_req_body=bad_body, expected_res_status=400)
- LOG.debug("_test_create_port_badrequest - fmt:%s - END", fmt)
-
- def _test_create_port_badportstate(self, fmt):
- LOG.debug("_test_create_port_badportstate - fmt:%s - START", fmt)
- network_id = self._create_network(fmt)
- port_state = "BADSTATE"
- self._create_port(network_id, port_state, fmt,
- expected_res_status=self._port_state_invalid_code)
- LOG.debug("_test_create_port_badportstate - fmt:%s - END", fmt)
-
- def _test_delete_port(self, fmt):
- LOG.debug("_test_delete_port - fmt:%s - START", fmt)
- content_type = "application/%s" % fmt
- port_state = "ACTIVE"
- network_id = self._create_network(fmt)
- port_id = self._create_port(network_id, port_state, fmt)
- LOG.debug("Deleting port %s for network %s of tenant %s" %
- (port_id, network_id, self.tenant_id))
- delete_port_req = testlib.port_delete_request(self.tenant_id,
- network_id, port_id,
- fmt)
- delete_port_res = delete_port_req.get_response(self.api)
- self.assertEqual(delete_port_res.status_int, 204)
- list_port_req = testlib.port_list_request(self.tenant_id, network_id,
- fmt)
- list_port_res = list_port_req.get_response(self.api)
- port_list_data = (self._port_deserializers[content_type].
- deserialize(list_port_res.body)['body'])
- port_count = len(port_list_data['ports'])
- self.assertEqual(port_count, 0)
- LOG.debug("_test_delete_port - fmt:%s - END", fmt)
-
- def _test_delete_port_in_use(self, fmt):
- LOG.debug("_test_delete_port_in_use - fmt:%s - START", fmt)
- port_state = "ACTIVE"
- attachment_id = "test_attachment"
- network_id = self._create_network(fmt)
- port_id = self._create_port(network_id, port_state, fmt)
- #plug an attachment into the port
- LOG.debug("Putting attachment into port %s", port_id)
- attachment_req = testlib.put_attachment_request(self.tenant_id,
- network_id,
- port_id,
- attachment_id)
- attachment_res = attachment_req.get_response(self.api)
- self.assertEquals(attachment_res.status_int, 204)
- LOG.debug("Deleting port %s for network %s of tenant %s" %
- (port_id, network_id, self.tenant_id))
- delete_port_req = testlib.port_delete_request(self.tenant_id,
- network_id, port_id,
- fmt)
- delete_port_res = delete_port_req.get_response(self.api)
- self.assertEqual(delete_port_res.status_int,
- self._port_in_use_code)
- LOG.debug("_test_delete_port_in_use - fmt:%s - END", fmt)
-
- def _test_delete_port_with_bad_id(self, fmt):
- LOG.debug("_test_delete_port_with_bad_id - fmt:%s - START", fmt)
- port_state = "ACTIVE"
- network_id = self._create_network(fmt)
- self._create_port(network_id, port_state, fmt)
- # Test for portnotfound
- delete_port_req = testlib.port_delete_request(self.tenant_id,
- network_id, "A_BAD_ID",
- fmt)
- delete_port_res = delete_port_req.get_response(self.api)
- self.assertEqual(delete_port_res.status_int,
- self._port_not_found_code)
- LOG.debug("_test_delete_port_with_bad_id - fmt:%s - END", fmt)
-
- def _test_delete_port_networknotfound(self, fmt):
- LOG.debug("_test_delete_port_networknotfound - fmt:%s - START", fmt)
- port_state = "ACTIVE"
- network_id = self._create_network(fmt)
- port_id = self._create_port(network_id, port_state, fmt)
- delete_port_req = testlib.port_delete_request(self.tenant_id,
- "A_BAD_ID", port_id,
- fmt)
- delete_port_res = delete_port_req.get_response(self.api)
- self.assertEqual(delete_port_res.status_int,
- self._network_not_found_code)
- LOG.debug("_test_delete_port_networknotfound - fmt:%s - END", fmt)
-
- def _test_set_port_state(self, fmt):
- LOG.debug("_test_set_port_state - fmt:%s - START", fmt)
- content_type = "application/%s" % fmt
- port_state = 'DOWN'
- new_port_state = 'ACTIVE'
- network_id = self._create_network(fmt)
- port_id = self._create_port(network_id, port_state, fmt)
- update_port_req = testlib.update_port_request(self.tenant_id,
- network_id, port_id,
- new_port_state,
- fmt)
- update_port_res = update_port_req.get_response(self.api)
- self.assertEqual(update_port_res.status_int, 204)
- show_port_req = testlib.show_port_request(self.tenant_id,
- network_id, port_id,
- fmt)
- show_port_res = show_port_req.get_response(self.api)
- self.assertEqual(show_port_res.status_int, 200)
- port_data = self._deserialize_port_response(content_type,
- show_port_res)
- self.assert_port(id=port_id, state=new_port_state,
- port_data=port_data['port'])
- # now set it back to the original value
- update_port_req = testlib.update_port_request(self.tenant_id,
- network_id, port_id,
- port_state,
- fmt)
- update_port_res = update_port_req.get_response(self.api)
- self.assertEqual(update_port_res.status_int, 204)
- show_port_req = testlib.show_port_request(self.tenant_id,
- network_id, port_id,
- fmt)
- show_port_res = show_port_req.get_response(self.api)
- self.assertEqual(show_port_res.status_int, 200)
- port_data = self._deserialize_port_response(content_type,
- show_port_res)
- self.assert_port(id=port_id, state=port_state,
- port_data=port_data['port'])
- LOG.debug("_test_set_port_state - fmt:%s - END", fmt)
-
- def _test_set_port_state_networknotfound(self, fmt):
- LOG.debug("_test_set_port_state_networknotfound - fmt:%s - START", fmt)
- port_state = 'DOWN'
- new_port_state = 'ACTIVE'
- network_id = self._create_network(fmt)
- port_id = self._create_port(network_id, port_state, fmt)
- update_port_req = testlib.update_port_request(self.tenant_id,
- "A_BAD_ID", port_id,
- new_port_state,
- fmt)
- update_port_res = update_port_req.get_response(self.api)
- self.assertEqual(update_port_res.status_int,
- self._network_not_found_code)
- LOG.debug("_test_set_port_state_networknotfound - fmt:%s - END", fmt)
-
- def _test_set_port_state_portnotfound(self, fmt):
- LOG.debug("_test_set_port_state_portnotfound - fmt:%s - START", fmt)
- port_state = 'DOWN'
- new_port_state = 'ACTIVE'
- network_id = self._create_network(fmt)
- self._create_port(network_id, port_state, fmt)
- update_port_req = testlib.update_port_request(self.tenant_id,
- network_id,
- "A_BAD_ID",
- new_port_state,
- fmt)
- update_port_res = update_port_req.get_response(self.api)
- self.assertEqual(update_port_res.status_int,
- self._port_not_found_code)
- LOG.debug("_test_set_port_state_portnotfound - fmt:%s - END", fmt)
-
- def _test_set_port_state_stateinvalid(self, fmt):
- LOG.debug("_test_set_port_state_stateinvalid - fmt:%s - START", fmt)
- port_state = 'DOWN'
- new_port_state = 'A_BAD_STATE'
- network_id = self._create_network(fmt)
- port_id = self._create_port(network_id, port_state, fmt)
- update_port_req = testlib.update_port_request(self.tenant_id,
- network_id, port_id,
- new_port_state,
- fmt)
- update_port_res = update_port_req.get_response(self.api)
- self.assertEqual(update_port_res.status_int,
- self._port_state_invalid_code)
- LOG.debug("_test_set_port_state_stateinvalid - fmt:%s - END", fmt)
-
- def _test_show_attachment(self, fmt):
- LOG.debug("_test_show_attachment - fmt:%s - START", fmt)
- content_type = "application/%s" % fmt
- port_state = "ACTIVE"
- network_id = self._create_network(fmt)
- interface_id = "test_interface"
- port_id = self._create_port(network_id, port_state, fmt)
- put_attachment_req = testlib.put_attachment_request(self.tenant_id,
- network_id,
- port_id,
- interface_id,
- fmt)
- put_attachment_res = put_attachment_req.get_response(self.api)
- self.assertEqual(put_attachment_res.status_int, 204)
- get_attachment_req = testlib.get_attachment_request(self.tenant_id,
- network_id,
- port_id,
- fmt)
- get_attachment_res = get_attachment_req.get_response(self.api)
- attachment_data = (self._att_deserializers[content_type].
- deserialize(get_attachment_res.body)['body'])
- self.assertEqual(attachment_data['attachment']['id'], interface_id)
- LOG.debug("_test_show_attachment - fmt:%s - END", fmt)
-
- def _test_show_attachment_none_set(self, fmt):
- LOG.debug("_test_show_attachment_none_set - fmt:%s - START", fmt)
- content_type = "application/%s" % fmt
- port_state = "ACTIVE"
- network_id = self._create_network(fmt)
- port_id = self._create_port(network_id, port_state, fmt)
- get_attachment_req = testlib.get_attachment_request(self.tenant_id,
- network_id,
- port_id,
- fmt)
- get_attachment_res = get_attachment_req.get_response(self.api)
- attachment_data = (self._att_deserializers[content_type].
- deserialize(get_attachment_res.body)['body'])
- self.assertTrue('id' not in attachment_data['attachment'])
- LOG.debug("_test_show_attachment_none_set - fmt:%s - END", fmt)
-
- def _test_show_attachment_networknotfound(self, fmt):
- LOG.debug("_test_show_attachment_networknotfound - fmt:%s - START",
- fmt)
- port_state = "ACTIVE"
- network_id = self._create_network(fmt)
- port_id = self._create_port(network_id, port_state, fmt)
- get_attachment_req = testlib.get_attachment_request(self.tenant_id,
- "A_BAD_ID",
- port_id,
- fmt)
- get_attachment_res = get_attachment_req.get_response(self.api)
- self.assertEqual(get_attachment_res.status_int,
- self._network_not_found_code)
- LOG.debug("_test_show_attachment_networknotfound - fmt:%s - END", fmt)
-
- def _test_show_attachment_portnotfound(self, fmt):
- LOG.debug("_test_show_attachment_portnotfound - fmt:%s - START", fmt)
- port_state = "ACTIVE"
- network_id = self._create_network(fmt)
- self._create_port(network_id, port_state, fmt)
- get_attachment_req = testlib.get_attachment_request(self.tenant_id,
- network_id,
- "A_BAD_ID",
- fmt)
- get_attachment_res = get_attachment_req.get_response(self.api)
- self.assertEqual(get_attachment_res.status_int,
- self._port_not_found_code)
- LOG.debug("_test_show_attachment_portnotfound - fmt:%s - END", fmt)
-
- def _test_put_attachment(self, fmt):
- LOG.debug("_test_put_attachment - fmt:%s - START", fmt)
- port_state = "ACTIVE"
- network_id = self._create_network(fmt)
- interface_id = "test_interface"
- port_id = self._create_port(network_id, port_state, fmt)
- put_attachment_req = testlib.put_attachment_request(self.tenant_id,
- network_id,
- port_id,
- interface_id,
- fmt)
- put_attachment_res = put_attachment_req.get_response(self.api)
- self.assertEqual(put_attachment_res.status_int, 204)
- LOG.debug("_test_put_attachment - fmt:%s - END", fmt)
-
- def _test_put_attachment_networknotfound(self, fmt):
- LOG.debug("_test_put_attachment_networknotfound - fmt:%s - START", fmt)
- port_state = 'DOWN'
- interface_id = "test_interface"
- network_id = self._create_network(fmt)
- port_id = self._create_port(network_id, port_state, fmt)
- put_attachment_req = testlib.put_attachment_request(self.tenant_id,
- "A_BAD_ID",
- port_id,
- interface_id,
- fmt)
- put_attachment_res = put_attachment_req.get_response(self.api)
- self.assertEqual(put_attachment_res.status_int,
- self._network_not_found_code)
- LOG.debug("_test_put_attachment_networknotfound - fmt:%s - END", fmt)
-
- def _test_put_attachment_portnotfound(self, fmt):
- LOG.debug("_test_put_attachment_portnotfound - fmt:%s - START", fmt)
- port_state = 'DOWN'
- interface_id = "test_interface"
- network_id = self._create_network(fmt)
- self._create_port(network_id, port_state, fmt)
- put_attachment_req = testlib.put_attachment_request(self.tenant_id,
- network_id,
- "A_BAD_ID",
- interface_id,
- fmt)
- put_attachment_res = put_attachment_req.get_response(self.api)
- self.assertEqual(put_attachment_res.status_int,
- self._port_not_found_code)
- LOG.debug("_test_put_attachment_portnotfound - fmt:%s - END", fmt)
-
- def _test_delete_attachment(self, fmt):
- LOG.debug("_test_delete_attachment - fmt:%s - START", fmt)
- port_state = "ACTIVE"
- network_id = self._create_network(fmt)
- interface_id = "test_interface"
- port_id = self._create_port(network_id, port_state, fmt)
- put_attachment_req = testlib.put_attachment_request(self.tenant_id,
- network_id,
- port_id,
- interface_id,
- fmt)
- put_attachment_res = put_attachment_req.get_response(self.api)
- self.assertEqual(put_attachment_res.status_int, 204)
- del_attachment_req = testlib.delete_attachment_request(self.tenant_id,
- network_id,
- port_id,
- fmt)
- del_attachment_res = del_attachment_req.get_response(self.api)
- self.assertEqual(del_attachment_res.status_int, 204)
- LOG.debug("_test_delete_attachment - fmt:%s - END", fmt)
-
- def _test_delete_attachment_networknotfound(self, fmt):
- LOG.debug("_test_delete_attachment_networknotfound - fmt:%s - START",
- fmt)
- port_state = "ACTIVE"
- network_id = self._create_network(fmt)
- port_id = self._create_port(network_id, port_state, fmt)
- del_attachment_req = testlib.delete_attachment_request(self.tenant_id,
- "A_BAD_ID",
- port_id,
- fmt)
- del_attachment_res = del_attachment_req.get_response(self.api)
- self.assertEqual(del_attachment_res.status_int,
- self._network_not_found_code)
- LOG.debug("_test_delete_attachment_networknotfound - fmt:%s - END",
- fmt)
-
- def _test_delete_attachment_portnotfound(self, fmt):
- LOG.debug("_test_delete_attachment_portnotfound - fmt:%s - START", fmt)
- port_state = "ACTIVE"
- network_id = self._create_network(fmt)
- self._create_port(network_id, port_state, fmt)
- del_attachment_req = testlib.delete_attachment_request(self.tenant_id,
- network_id,
- "A_BAD_ID",
- fmt)
- del_attachment_res = del_attachment_req.get_response(self.api)
- self.assertEqual(del_attachment_res.status_int,
- self._port_not_found_code)
- LOG.debug("_test_delete_attachment_portnotfound - fmt:%s - END", fmt)
-
- def _test_unparsable_data(self, fmt):
- LOG.debug("_test_unparsable_data - fmt:%s - START", fmt)
-
- data = "this is not json or xml"
- method = 'POST'
- content_type = "application/%s" % fmt
- tenant_id = self.tenant_id
- path = "/tenants/%(tenant_id)s/networks.%(fmt)s" % locals()
- network_req = testlib.create_request(path, data, content_type, method)
- network_res = network_req.get_response(self.api)
- self.assertEqual(network_res.status_int, 400)
-
- LOG.debug("_test_unparsable_data - fmt:%s - END", fmt)
-
- def _test_multitenancy(self, fmt):
- LOG.debug("_test_multitenancy - fmt:%s - START", fmt)
-
- # creates a network for tenant self.tenant_id
- net_id = self._create_network(fmt)
- port_id = self._create_port(net_id, "ACTIVE", fmt)
-
- invalid_tenant = self.tenant_id + "-invalid"
-
- def assert_net_not_found(base_path, method, fmt):
- content_type = "application/%s" % fmt
- full_path = "%s.%s" % (base_path, fmt)
- req = testlib.create_request(full_path, None, content_type)
- res = req.get_response(self.api)
- self.assertEqual(res.status_int, self._network_not_found_code)
-
- # new tenant should NOT see this network UUID
- net_path = "/tenants/%(invalid_tenant)s/networks/%(net_id)s" % locals()
- net_detail_path = net_path + "/detail"
-
- assert_net_not_found(net_path, 'GET', fmt)
- assert_net_not_found(net_path, 'PUT', fmt)
- assert_net_not_found(net_path, 'DELETE', fmt)
- assert_net_not_found(net_detail_path, 'GET', fmt)
-
- # new tenant should NOT see this network + port UUID
- port_all_path = net_path + "/ports"
- port_path = "%s/%s" % (port_all_path, port_id)
- port_detail_path = port_path + "/detail"
-
- # NOTE: we actually still check for a network not found
- # error here, as both the network and port in the URL are
- # invalid. This is consistent with the test
- # _test_show_port_networknotfound
- assert_net_not_found(port_all_path, 'POST', fmt)
- assert_net_not_found(port_all_path, 'GET', fmt)
- assert_net_not_found(port_path, 'GET', fmt)
- assert_net_not_found(port_path, 'PUT', fmt)
- assert_net_not_found(port_path, 'DELETE', fmt)
- assert_net_not_found(port_detail_path, 'GET', fmt)
-
- attach_path = port_path + "/attachment"
- assert_net_not_found(attach_path, 'GET', fmt)
- assert_net_not_found(attach_path, 'PUT', fmt)
- assert_net_not_found(attach_path, 'DELETE', fmt)
-
- LOG.debug("_test_multitenancy - fmt:%s - END", fmt)
-
- def test_list_networks_json(self):
- self._test_list_networks('json')
-
- def test_list_networks_xml(self):
- self._test_list_networks('xml')
-
- def test_list_networks_detail_json(self):
- self._test_list_networks_detail('json')
-
- def test_list_networks_detail_xml(self):
- self._test_list_networks_detail('xml')
-
- def test_create_network_json(self):
- self._test_create_network('json')
-
- def test_create_network_xml(self):
- self._test_create_network('xml')
-
- def test_create_network_badrequest_json(self):
- self._test_create_network_badrequest('json')
-
- def test_create_network_badrequest_xml(self):
- self._test_create_network_badrequest('xml')
-
- def test_show_network_not_found_json(self):
- self._test_show_network_not_found('json')
-
- def test_show_network_not_found_xml(self):
- self._test_show_network_not_found('xml')
-
- def test_show_network_json(self):
- self._test_show_network('json')
-
- def test_show_network_xml(self):
- self._test_show_network('xml')
-
- def test_show_network_detail_json(self):
- self._test_show_network_detail('json')
-
- def test_show_network_detail_xml(self):
- self._test_show_network_detail('xml')
-
- def test_delete_network_json(self):
- self._test_delete_network('json')
-
- def test_delete_network_xml(self):
- self._test_delete_network('xml')
-
- def test_rename_network_json(self):
- self._test_rename_network('json')
-
- def test_rename_network_xml(self):
- self._test_rename_network('xml')
-
- def test_rename_network_badrequest_json(self):
- self._test_rename_network_badrequest('json')
-
- def test_rename_network_badrequest_xml(self):
- self._test_rename_network_badrequest('xml')
-
- def test_rename_network_not_found_json(self):
- self._test_rename_network_not_found('json')
-
- def test_rename_network_not_found_xml(self):
- self._test_rename_network_not_found('xml')
-
- def test_delete_network_in_use_json(self):
- self._test_delete_network_in_use('json')
-
- def test_delete_network_in_use_xml(self):
- self._test_delete_network_in_use('xml')
-
- def test_delete_network_with_unattached_port_xml(self):
- self._test_delete_network_with_unattached_port('xml')
-
- def test_delete_network_with_unattached_port_json(self):
- self._test_delete_network_with_unattached_port('json')
-
- def test_list_ports_json(self):
- self._test_list_ports('json')
-
- def test_list_ports_xml(self):
- self._test_list_ports('xml')
-
- def test_list_ports_networknotfound_json(self):
- self._test_list_ports_networknotfound('json')
-
- def test_list_ports_networknotfound_xml(self):
- self._test_list_ports_networknotfound('xml')
-
- def test_list_ports_detail_json(self):
- self._test_list_ports_detail('json')
-
- def test_list_ports_detail_xml(self):
- self._test_list_ports_detail('xml')
-
- def test_show_port_json(self):
- self._test_show_port('json')
-
- def test_show_port_xml(self):
- self._test_show_port('xml')
-
- def test_show_port_detail_json(self):
- self._test_show_port_detail('json')
-
- def test_show_port_detail_xml(self):
- self._test_show_port_detail('xml')
-
- def test_show_port_networknotfound_json(self):
- self._test_show_port_networknotfound('json')
-
- def test_show_port_networknotfound_xml(self):
- self._test_show_port_networknotfound('xml')
-
- def test_show_port_portnotfound_json(self):
- self._test_show_port_portnotfound('json')
-
- def test_show_port_portnotfound_xml(self):
- self._test_show_port_portnotfound('xml')
-
- def test_create_port_json(self):
- self._test_create_port('json')
-
- def test_create_port_xml(self):
- self._test_create_port('xml')
-
- def test_create_port_noreqbody_json(self):
- self._test_create_port_noreqbody('json')
-
- def test_create_port_noreqbody_xml(self):
- self._test_create_port_noreqbody('xml')
-
- def test_create_port_networknotfound_json(self):
- self._test_create_port_networknotfound('json')
-
- def test_create_port_networknotfound_xml(self):
- self._test_create_port_networknotfound('xml')
-
- def test_create_port_badrequest_json(self):
- self._test_create_port_badrequest('json')
-
- def test_create_port_badrequest_xml(self):
- self._test_create_port_badrequest('xml')
-
- def test_create_port_badportstate_json(self):
- self._test_create_port_badportstate('json')
-
- def test_create_port_badportstate_xml(self):
- self._test_create_port_badportstate('xml')
-
- def test_delete_port_xml(self):
- self._test_delete_port('xml')
-
- def test_delete_port_json(self):
- self._test_delete_port('json')
-
- def test_delete_port_in_use_xml(self):
- self._test_delete_port_in_use('xml')
-
- def test_delete_port_in_use_json(self):
- self._test_delete_port_in_use('json')
-
- def test_delete_port_networknotfound_xml(self):
- self._test_delete_port_networknotfound('xml')
-
- def test_delete_port_networknotfound_json(self):
- self._test_delete_port_networknotfound('json')
-
- def test_delete_port_with_bad_id_xml(self):
- self._test_delete_port_with_bad_id('xml')
-
- def test_delete_port_with_bad_id_json(self):
- self._test_delete_port_with_bad_id('json')
-
- def test_set_port_state_xml(self):
- self._test_set_port_state('xml')
-
- def test_set_port_state_json(self):
- self._test_set_port_state('json')
-
- def test_set_port_state_networknotfound_xml(self):
- self._test_set_port_state_networknotfound('xml')
-
- def test_set_port_state_networknotfound_json(self):
- self._test_set_port_state_networknotfound('json')
-
- def test_set_port_state_portnotfound_xml(self):
- self._test_set_port_state_portnotfound('xml')
-
- def test_set_port_state_portnotfound_json(self):
- self._test_set_port_state_portnotfound('json')
-
- def test_set_port_state_stateinvalid_xml(self):
- self._test_set_port_state_stateinvalid('xml')
-
- def test_set_port_state_stateinvalid_json(self):
- self._test_set_port_state_stateinvalid('json')
-
- def test_show_attachment_xml(self):
- self._test_show_attachment('xml')
-
- def test_show_attachment_json(self):
- self._test_show_attachment('json')
-
- def test_show_attachment_none_set_xml(self):
- self._test_show_attachment_none_set('xml')
-
- def test_show_attachment_none_set_json(self):
- self._test_show_attachment_none_set('json')
-
- def test_show_attachment_networknotfound_xml(self):
- self._test_show_attachment_networknotfound('xml')
-
- def test_show_attachment_networknotfound_json(self):
- self._test_show_attachment_networknotfound('json')
-
- def test_show_attachment_portnotfound_xml(self):
- self._test_show_attachment_portnotfound('xml')
-
- def test_show_attachment_portnotfound_json(self):
- self._test_show_attachment_portnotfound('json')
-
- def test_put_attachment_xml(self):
- self._test_put_attachment('xml')
-
- def test_put_attachment_json(self):
- self._test_put_attachment('json')
-
- def test_put_attachment_networknotfound_xml(self):
- self._test_put_attachment_networknotfound('xml')
-
- def test_put_attachment_networknotfound_json(self):
- self._test_put_attachment_networknotfound('json')
-
- def test_put_attachment_portnotfound_xml(self):
- self._test_put_attachment_portnotfound('xml')
-
- def test_put_attachment_portnotfound_json(self):
- self._test_put_attachment_portnotfound('json')
-
- def test_delete_attachment_xml(self):
- self._test_delete_attachment('xml')
-
- def test_delete_attachment_json(self):
- self._test_delete_attachment('json')
-
- def test_delete_attachment_networknotfound_xml(self):
- self._test_delete_attachment_networknotfound('xml')
-
- def test_delete_attachment_networknotfound_json(self):
- self._test_delete_attachment_networknotfound('json')
-
- def test_delete_attachment_portnotfound_xml(self):
- self._test_delete_attachment_portnotfound('xml')
-
- def test_delete_attachment_portnotfound_json(self):
- self._test_delete_attachment_portnotfound('json')
-
- def test_unparsable_data_xml(self):
- self._test_unparsable_data('xml')
-
- def test_unparsable_data_json(self):
- self._test_unparsable_data('json')
-
- def test_multitenancy_xml(self):
- self._test_multitenancy('xml')
-
- def test_multitenancy_json(self):
- self._test_multitenancy('json')
-
- def test_internal_error(self):
- """Check that internal errors do not leak.
-
- Any internal, unexpected error should be turned into a 500 response
- without any traces of the original exception.
- """
- orig_exception_msg = "An exception with a traceback"
-
- @APIFaultWrapper()
- def raise_exception(self, *args, **kwargs):
- raise Exception(orig_exception_msg)
-
- list_network_req = testlib.network_list_request(self.tenant_id, "json")
- with mock.patch.object(Controller, 'index', new=raise_exception):
- list_network_res = list_network_req.get_response(self.api)
- self.assertEqual(list_network_res.status_int, 500)
- self.assertNotIn(orig_exception_msg, list_network_res.body)
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010-2012 ????
-# 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.
-# @author: Salvatore Orlando, Citrix Systems
-
-import unittest
-
-from lxml import etree
-from webob import exc
-
-import quantum.api.attachments as atts
-import quantum.api.networks as nets
-import quantum.api.ports as ports
-import quantum.api.versions as versions
-from quantum.common.test_lib import test_config
-from quantum.openstack.common import jsonutils
-import quantum.tests.unit._test_api as test_api
-import quantum.tests.unit.testlib_api as testlib
-
-
-class APITestV10(test_api.BaseAPIOperationsTest):
-
- def assert_network(self, **kwargs):
- self.assertEqual({'id': kwargs['id'],
- 'name': kwargs['name']},
- kwargs['network_data'])
-
- def assert_network_details(self, **kwargs):
- self.assertEqual({'id': kwargs['id'],
- 'name': kwargs['name'],
- 'ports': [{'id': kwargs['port_id'],
- 'state': 'ACTIVE'}]},
- kwargs['network_data'])
-
- def assert_port(self, **kwargs):
- self.assertEqual({'id': kwargs['id'],
- 'state': kwargs['state']},
- kwargs['port_data'])
-
- def assert_port_attachment(self, **kwargs):
- self.assertEqual({'id': kwargs['id'], 'state': kwargs['state'],
- 'attachment': {'id': kwargs['interface_id']}},
- kwargs['port_data'])
-
- def setUp(self):
- super(APITestV10, self).setUp(
- 'quantum.api.APIRouterV10',
- {
- test_api.NETS: nets.ControllerV10._serialization_metadata,
- test_api.PORTS: ports.ControllerV10._serialization_metadata,
- test_api.ATTS: atts.ControllerV10._serialization_metadata,
- }
- )
- self._successful_create_code = exc.HTTPOk.code
- self._network_not_found_code = 420
- self._network_in_use_code = 421
- self._port_not_found_code = 430
- self._port_state_invalid_code = 431
- self._port_in_use_code = 432
- self._already_attached_code = 440
-
-
-class APITestV11(test_api.BaseAPIOperationsTest):
-
- def assert_network(self, **kwargs):
- self.assertEqual({'id': kwargs['id'],
- 'name': kwargs['name'],
- 'op-status': self.net_op_status},
- kwargs['network_data'])
-
- def assert_network_details(self, **kwargs):
- self.assertEqual({'id': kwargs['id'],
- 'name': kwargs['name'],
- 'op-status': self.net_op_status,
- 'ports': [{'id': kwargs['port_id'],
- 'state': 'ACTIVE',
- 'op-status': self.port_op_status}]},
- kwargs['network_data'])
-
- def assert_port(self, **kwargs):
- self.assertEqual({'id': kwargs['id'],
- 'state': kwargs['state'],
- 'op-status': self.port_op_status},
- kwargs['port_data'])
-
- def assert_port_attachment(self, **kwargs):
- self.assertEqual({'id': kwargs['id'], 'state': kwargs['state'],
- 'op-status': self.port_op_status,
- 'attachment': {'id': kwargs['interface_id']}},
- kwargs['port_data'])
-
- def setUp(self):
- self.net_op_status = test_config.get('default_net_op_status',
- 'UNKNOWN')
- self.port_op_status = test_config.get('default_port_op_status',
- 'UNKNOWN')
- super(APITestV11, self).setUp(
- 'quantum.api.APIRouterV11',
- {
- test_api.NETS: nets.ControllerV11._serialization_metadata,
- test_api.PORTS: ports.ControllerV11._serialization_metadata,
- test_api.ATTS: atts.ControllerV11._serialization_metadata,
- }
- )
- self._successful_create_code = exc.HTTPAccepted.code
- self._network_not_found_code = exc.HTTPNotFound.code
- self._network_in_use_code = exc.HTTPConflict.code
- self._port_not_found_code = exc.HTTPNotFound.code
- self._port_state_invalid_code = exc.HTTPBadRequest.code
- self._port_in_use_code = exc.HTTPConflict.code
- self._already_attached_code = exc.HTTPConflict.code
-
-
-class APIFiltersTest(test_api.AbstractAPITest):
- """ Test case for API filters.
- Uses controller for API v1.1
- """
-
- def _do_filtered_network_list_request(self, flt):
- list_network_req = testlib.network_list_request(self.tenant_id,
- self.fmt,
- query_string=flt)
- list_network_res = list_network_req.get_response(self.api)
- self.assertEqual(list_network_res.status_int, 200)
- network_data = (self._net_deserializers[self.content_type].
- deserialize(list_network_res.body)['body'])
- return network_data
-
- def _do_filtered_port_list_request(self, flt, network_id):
- list_port_req = testlib.port_list_request(self.tenant_id,
- network_id,
- self.fmt,
- query_string=flt)
- list_port_res = list_port_req.get_response(self.api)
- self.assertEqual(list_port_res.status_int, 200)
- port_data = (self._port_deserializers[self.content_type].
- deserialize(list_port_res.body)['body'])
- return port_data
-
- def setUp(self):
- super(APIFiltersTest, self).setUp(
- 'quantum.api.APIRouterV11',
- {
- test_api.NETS: nets.ControllerV11._serialization_metadata,
- test_api.PORTS: ports.ControllerV11._serialization_metadata,
- test_api.ATTS: atts.ControllerV11._serialization_metadata,
- }
- )
- self._successful_create_code = exc.HTTPAccepted.code
- self.net_op_status = test_config.get('default_net_op_status',
- 'UNKNOWN')
- self.port_op_status = test_config.get('default_port_op_status',
- 'UNKNOWN')
- self.fmt = "xml"
- self.content_type = "application/%s" % self.fmt
- # create data for validating filters
- # Create network "test-1"
- self.net1_id = self._create_network(self.fmt, name="test-1")
- # Add 2 ports, 1 ACTIVE, 1 DOWN
- self.port11_id = self._create_port(self.net1_id, "ACTIVE", self.fmt)
- self.port12_id = self._create_port(self.net1_id, "DOWN", self.fmt)
- # Put attachment "test-1-att" in active port
- self._set_attachment(self.net1_id,
- self.port11_id,
- "test-1-att",
- self.fmt)
- # Create network "test-2"
- # Add 2 ports, 2 ACTIVE, 0 DOWN
- self.net2_id = self._create_network(self.fmt, name="test-2")
- self.port21_id = self._create_port(self.net2_id, "ACTIVE", self.fmt)
- self.port22_id = self._create_port(self.net2_id, "ACTIVE", self.fmt)
-
- def test_network_name_filter(self):
- flt = "name=test-1"
- network_data = self._do_filtered_network_list_request(flt)
- # Check network count: should return 1
- self.assertEqual(len(network_data['networks']), 1)
- self.assertEqual(network_data['networks'][0]['id'], self.net1_id)
-
- flt = "name=non-existent"
- network_data = self._do_filtered_network_list_request(flt)
- # Check network count: should return 0
- self.assertEqual(len(network_data['networks']), 0)
-
- def test_network_op_status_filter(self):
- # First filter for networks in default status
- flt = "op-status=%s" % self.net_op_status
- network_data = self._do_filtered_network_list_request(flt)
- # Check network count: should return 2
- self.assertEqual(len(network_data['networks']), 2)
-
- # And then for networks in 'DOWN' status
- flt = "op-status=DOWN"
- network_data = self._do_filtered_network_list_request(flt)
- # Check network count: should return 0
- self.assertEqual(len(network_data['networks']), 0)
-
- def test_network_port_op_status_filter(self):
- # First filter for networks with ports in default op status
- flt = "port-op-status=%s" % self.port_op_status
- network_data = self._do_filtered_network_list_request(flt)
- # Check network count: should return 2
- self.assertEqual(len(network_data['networks']), 2)
-
- def test_network_port_state_filter(self):
- # First filter for networks with ports 'ACTIVE'
- flt = "port-state=ACTIVE"
- network_data = self._do_filtered_network_list_request(flt)
- # Check network count: should return 2
- self.assertEqual(len(network_data['networks']), 2)
-
- # And then for networks with ports in 'DOWN' admin state
- flt = "port-state=DOWN"
- network_data = self._do_filtered_network_list_request(flt)
- # Check network count: should return 1
- self.assertEqual(len(network_data['networks']), 1)
-
- def test_network_has_attachment_filter(self):
- # First filter for networks with ports 'ACTIVE'
- flt = "has-attachment=True"
- network_data = self._do_filtered_network_list_request(flt)
- # Check network count: should return 1
- self.assertEqual(len(network_data['networks']), 1)
-
- # And then for networks with ports in 'DOWN' admin state
- flt = "has-attachment=False"
- network_data = self._do_filtered_network_list_request(flt)
- # Check network count: should return 1
- self.assertEqual(len(network_data['networks']), 1)
-
- def test_network_port_filter(self):
- flt = "port=%s" % self.port11_id
- network_data = self._do_filtered_network_list_request(flt)
- # Check network count: should return 1
- self.assertEqual(len(network_data['networks']), 1)
- self.assertEqual(network_data['networks'][0]['id'], self.net1_id)
-
- flt = "port=%s" % self.port21_id
- network_data = self._do_filtered_network_list_request(flt)
- # Check network count: should return 1
- self.assertEqual(len(network_data['networks']), 1)
- self.assertEqual(network_data['networks'][0]['id'], self.net2_id)
-
- def test_network_attachment_filter(self):
- flt = "attachment=test-1-att"
- network_data = self._do_filtered_network_list_request(flt)
- # Check network count: should return 1
- self.assertEqual(len(network_data['networks']), 1)
- self.assertEqual(network_data['networks'][0]['id'], self.net1_id)
-
- flt = "attachment=non-existent"
- network_data = self._do_filtered_network_list_request(flt)
- # Check network count: should return 0
- self.assertEqual(len(network_data['networks']), 0)
-
- def test_network_multiple_filters(self):
- # Add some data for having more fun
- another_net_id = self._create_network(self.fmt, name="test-1")
- # Add 1 ACTIVE port
- self._create_port(another_net_id, "ACTIVE", self.fmt)
- # Do the filtering
- flt = "name=test-1&port-state=ACTIVE&attachment=test-1-att"
- network_data = self._do_filtered_network_list_request(flt)
- # Check network count: should return 1
- self.assertEqual(len(network_data['networks']), 1)
- self.assertEqual(network_data['networks'][0]['id'], self.net1_id)
-
- def test_port_state_filter(self):
- # First filter for 'ACTIVE' ports in 1st network
- flt = "state=ACTIVE"
- port_data = self._do_filtered_port_list_request(flt, self.net1_id)
- # Check port count: should return 1
- self.assertEqual(len(port_data['ports']), 1)
-
- # And then in 2nd network
- port_data = self._do_filtered_port_list_request(flt, self.net2_id)
- # Check port count: should return 2
- self.assertEqual(len(port_data['ports']), 2)
-
- def test_port_op_status_filter(self):
- # First filter for 'UP' ports in 1st network
- flt = "op-status=%s" % self.port_op_status
- port_data = self._do_filtered_port_list_request(flt, self.net1_id)
- # Check port count: should return 2
- self.assertEqual(len(port_data['ports']), 2)
-
- def test_port_has_attachment_filter(self):
- # First search for ports with attachments in 1st network
- flt = "has-attachment=True"
- port_data = self._do_filtered_port_list_request(flt, self.net1_id)
- # Check port count: should return 1
- self.assertEqual(len(port_data['ports']), 1)
- self.assertEqual(port_data['ports'][0]['id'], self.port11_id)
-
- # And then for ports without attachment in 2nd network
- flt = "has-attachment=False"
- port_data = self._do_filtered_port_list_request(flt, self.net2_id)
- # Check port count: should return 2
- self.assertEqual(len(port_data['ports']), 2)
-
- def test_port_attachment_filter(self):
- # First search for ports with attachments in 1st network
- flt = "attachment=test-1-att"
- port_data = self._do_filtered_port_list_request(flt, self.net1_id)
- # Check port count: should return 1
- self.assertEqual(len(port_data['ports']), 1)
- self.assertEqual(port_data['ports'][0]['id'], self.port11_id)
-
- # And then for a non-existent attachment in 2nd network
- flt = "attachment=non-existent"
- port_data = self._do_filtered_port_list_request(flt, self.net2_id)
- # Check port count: should return 0
- self.assertEqual(len(port_data['ports']), 0)
-
- def test_port_multiple_filters(self):
- flt = "op-status=%s&state=DOWN" % self.port_op_status
- port_data = self._do_filtered_port_list_request(flt, self.net1_id)
- # Check port count: should return 1
- self.assertEqual(len(port_data['ports']), 1)
- self.assertEqual(port_data['ports'][0]['id'], self.port12_id)
-
- flt = "state=ACTIVE&attachment=test-1-att"
- port_data = self._do_filtered_port_list_request(flt, self.net1_id)
- # Check port count: should return 1
- self.assertEqual(len(port_data['ports']), 1)
- self.assertEqual(port_data['ports'][0]['id'], self.port11_id)
-
- flt = "state=ACTIVE&has-attachment=False"
- port_data = self._do_filtered_port_list_request(flt, self.net2_id)
- # Check port count: should return 2
- self.assertEqual(len(port_data['ports']), 2)
-
-
-class APIRootTest(unittest.TestCase):
- def setUp(self):
- self.app = versions.Versions()
-
- def _test_root_responds_with_versions(self, content_type):
- req = testlib.create_request('/', '', content_type)
- response = self.app(req)
- self.assertEquals(response.status_int, 200)
- return response.body
-
- def test_root_responds_with_versions_json(self):
- body = self._test_root_responds_with_versions('application/json')
- data = jsonutils.loads(body)
- self.assertEquals('versions', data.keys()[0])
-
- def test_root_responds_with_versions_xml(self):
- body = self._test_root_responds_with_versions('application/xml')
- root = etree.fromstring(body)
- self.assertEquals(root.tag, 'versions')
-
- def test_invalid_version(self):
- req = testlib.create_request('/v99.99/tenants/tenantX/networks',
- '',
- 'application/json')
- response = self.app(req)
- self.assertEquals(response.status_int, 404)
+++ /dev/null
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011, Cisco Systems, Inc.
-#
-# 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.
-# @author: Rohit Agarwalla, Cisco Systems, Inc.
-
-"""
-test_database.py is an independent test suite
-that tests the database api method calls
-"""
-
-import unittest
-
-from quantum.db import api as db
-from quantum.tests.unit import database_stubs as db_stubs
-
-
-class QuantumDBTest(unittest.TestCase):
- """Class consisting of Quantum DB unit tests"""
- def setUp(self):
- """Setup for tests"""
- db.configure_db({'sql_connection': 'sqlite:///:memory:'})
- self.dbtest = db_stubs.QuantumDB()
- self.tenant_id = "t1"
-
- def tearDown(self):
- """Tear Down"""
- db.clear_db()
-
- def testa_create_network(self):
- """test to create network"""
- net1 = self.dbtest.create_network(self.tenant_id, "plugin_test1")
- self.assertTrue(net1["name"] == "plugin_test1")
-
- def testb_get_networks(self):
- """test to get all networks"""
- net1 = self.dbtest.create_network(self.tenant_id, "plugin_test1")
- self.assertTrue(net1["name"] == "plugin_test1")
- net2 = self.dbtest.create_network(self.tenant_id, "plugin_test2")
- self.assertTrue(net2["name"] == "plugin_test2")
- nets = self.dbtest.get_all_networks(self.tenant_id)
- count = 0
- for net in nets:
- if "plugin_test" in net["name"]:
- count += 1
- self.assertTrue(count == 2)
-
- def testc_delete_network(self):
- """test to delete network"""
- net1 = self.dbtest.create_network(self.tenant_id, "plugin_test1")
- self.assertTrue(net1["name"] == "plugin_test1")
- self.dbtest.delete_network(net1["id"])
- nets = self.dbtest.get_all_networks(self.tenant_id)
- count = len(nets)
- self.assertTrue(count == 0)
-
- def testd_update_network(self):
- """test to rename network"""
- net1 = self.dbtest.create_network(self.tenant_id, "plugin_test1")
- self.assertTrue(net1["name"] == "plugin_test1")
- net = self.dbtest.update_network(self.tenant_id, net1["id"],
- {'name': "plugin_test1_renamed"})
- print net
- self.assertTrue(net["name"] == "plugin_test1_renamed")
-
- def teste_create_port(self):
- """test to create port"""
- net1 = self.dbtest.create_network(self.tenant_id, "plugin_test1")
- port = self.dbtest.create_port(net1["id"])
- self.assertTrue(port["net-id"] == net1["id"])
-
- def testf_get_ports(self):
- """test to get ports"""
- net1 = self.dbtest.create_network(self.tenant_id, "plugin_test1")
- port = self.dbtest.create_port(net1["id"])
- self.assertTrue(port["net-id"] == net1["id"])
- ports = self.dbtest.get_all_ports(net1["id"])
- count = len(ports)
- self.assertTrue(count == 1)
-
- def testf_update_port(self):
- """test to update port"""
- net1 = self.dbtest.create_network(self.tenant_id, "plugin_test1")
- port = self.dbtest.create_port(net1["id"])
- self.dbtest.update_port(port["net-id"],
- port['id'],
- state='ACTIVE',
- interface_id='interface_id1')
- self.assertTrue(port["net-id"] == net1["id"])
- ports = self.dbtest.get_all_ports(net1["id"])
- new_port = ports[0]
- self.assertEqual('ACTIVE', new_port['state'])
- self.assertEqual('interface_id1', new_port['attachment'])
-
- def testf_delete_port(self):
- """test to delete port"""
- net1 = self.dbtest.create_network(self.tenant_id, "plugin_test1")
- port = self.dbtest.create_port(net1["id"])
- self.assertTrue(port["net-id"] == net1["id"])
- ports = self.dbtest.get_all_ports(net1["id"])
- for por in ports:
- self.dbtest.delete_port(net1["id"], por["id"])
- ports = self.dbtest.get_all_ports(net1["id"])
- count = len(ports)
- self.assertTrue(count == 0)
-
- def testg_plug_unplug_interface(self):
- """test to plug/unplug interface"""
- net1 = self.dbtest.create_network(self.tenant_id, "plugin_test1")
- port1 = self.dbtest.create_port(net1["id"])
- self.dbtest.plug_interface(net1["id"], port1["id"], "vif1.1")
- port = self.dbtest.get_port(net1["id"], port1["id"])
- self.assertTrue(port[0]["attachment"] == "vif1.1")
- self.dbtest.unplug_interface(net1["id"], port1["id"])
- port = self.dbtest.get_port(net1["id"], port1["id"])
- self.assertTrue(port[0]["attachment"] is None)
import unittest
import routes
+import webob
from webtest import AppError
from webtest import TestApp
-from quantum.api import faults
from quantum.common import config
from quantum.common import exceptions
from quantum.extensions import extensions
PluginAwareExtensionManager,
)
from quantum.openstack.common import jsonutils
-from quantum.plugins.sample.SamplePlugin import QuantumEchoPlugin
+from quantum.db.db_base_plugin_v2 import QuantumDbPluginV2
from quantum.tests.unit import BaseTest
from quantum.tests.unit.extension_stubs import (
ExtensionExpectingPluginInterface,
super(ExtensionsTestApp, self).__init__(mapper)
+class FakePluginWithExtension(QuantumDbPluginV2):
+ """A fake plugin used only for extension testing in this file."""
+
+ supported_extension_aliases = ["FOXNSOX"]
+
+ def method_to_support_foxnsox_extension(self, context):
+ self._log("method_to_support_foxnsox_extension", context)
+
+
class ResourceExtensionTest(unittest.TestCase):
class ResourceExtensionController(wsgi.Controller):
return {'data': {'id': id}}
def notimplemented_function(self, request, id):
- return faults.Quantum10HTTPError(
- exceptions.NotImplementedError("notimplemented_function"))
+ return webob.exc.HTTPClientError(NotImplementedError())
def custom_member_action(self, request, id):
return {'member_action': 'value'}
def setup_extensions_middleware(extension_manager=None):
extension_manager = (extension_manager or
- PluginAwareExtensionManager(extensions_path,
- QuantumEchoPlugin()))
+ PluginAwareExtensionManager(
+ extensions_path,
+ FakePluginWithExtension()))
config_file = 'quantum.conf.test'
args = ['--config-file', etcdir(config_file)]
config.parse(args=args)
req.headers['Accept'] = content_type
req.body = body
return req
-
-
-def _network_list_request(tenant_id, format='xml', detail=False,
- query_string=None):
- method = 'GET'
- detail_str = detail and '/detail' or ''
- path = ("/tenants/%(tenant_id)s/networks"
- "%(detail_str)s.%(format)s") % locals()
- content_type = "application/%s" % format
- return create_request(path, None, content_type, method, query_string)
-
-
-def network_list_request(tenant_id, format='xml', query_string=None):
- return _network_list_request(tenant_id, format, query_string=query_string)
-
-
-def network_list_detail_request(tenant_id, format='xml'):
- return _network_list_request(tenant_id, format, detail=True)
-
-
-def _show_network_request(tenant_id, network_id, format='xml', detail=False):
- method = 'GET'
- detail_str = detail and '/detail' or ''
- path = ("/tenants/%(tenant_id)s/networks"
- "/%(network_id)s%(detail_str)s.%(format)s") % locals()
- content_type = "application/%s" % format
- return create_request(path, None, content_type, method)
-
-
-def show_network_request(tenant_id, network_id, format='xml'):
- return _show_network_request(tenant_id, network_id, format)
-
-
-def show_network_detail_request(tenant_id, network_id, format='xml'):
- return _show_network_request(tenant_id, network_id, format, detail=True)
-
-
-def new_network_request(tenant_id, network_name='new_name',
- format='xml', custom_req_body=None):
- method = 'POST'
- path = "/tenants/%(tenant_id)s/networks.%(format)s" % locals()
- data = custom_req_body or {'network': {'name': '%s' % network_name}}
- content_type = "application/%s" % format
- body = Serializer().serialize(data, content_type)
- return create_request(path, body, content_type, method)
-
-
-def update_network_request(tenant_id, network_id, network_name, format='xml',
- custom_req_body=None):
- method = 'PUT'
- path = ("/tenants/%(tenant_id)s/networks"
- "/%(network_id)s.%(format)s") % locals()
- data = custom_req_body or {'network': {'name': '%s' % network_name}}
- content_type = "application/%s" % format
- body = Serializer().serialize(data, content_type)
- return create_request(path, body, content_type, method)
-
-
-def network_delete_request(tenant_id, network_id, format='xml'):
- method = 'DELETE'
- path = ("/tenants/%(tenant_id)s/networks/"
- "%(network_id)s.%(format)s") % locals()
- content_type = "application/%s" % format
- return create_request(path, None, content_type, method)
-
-
-def _port_list_request(tenant_id, network_id, format='xml',
- detail=False, query_string=None):
- method = 'GET'
- detail_str = detail and '/detail' or ''
- path = ("/tenants/%(tenant_id)s/networks/"
- "%(network_id)s/ports%(detail_str)s.%(format)s") % locals()
- content_type = "application/%s" % format
- return create_request(path, None, content_type, method, query_string)
-
-
-def port_list_request(tenant_id, network_id, format='xml', query_string=None):
- return _port_list_request(tenant_id,
- network_id,
- format,
- query_string=query_string)
-
-
-def port_list_detail_request(tenant_id, network_id, format='xml'):
- return _port_list_request(tenant_id, network_id,
- format, detail=True)
-
-
-def _show_port_request(tenant_id, network_id, port_id,
- format='xml', detail=False):
- method = 'GET'
- detail_str = detail and '/detail' or ''
- path = ("/tenants/%(tenant_id)s/networks/%(network_id)s"
- "/ports/%(port_id)s%(detail_str)s.%(format)s") % locals()
- content_type = "application/%s" % format
- return create_request(path, None, content_type, method)
-
-
-def show_port_request(tenant_id, network_id, port_id, format='xml'):
- return _show_port_request(tenant_id, network_id, port_id, format)
-
-
-def show_port_detail_request(tenant_id, network_id, port_id, format='xml'):
- return _show_port_request(tenant_id, network_id, port_id,
- format, detail=True)
-
-
-def new_port_request(tenant_id, network_id, port_state,
- format='xml', custom_req_body=None):
- method = 'POST'
- path = ("/tenants/%(tenant_id)s/networks/"
- "%(network_id)s/ports.%(format)s") % locals()
- data = (custom_req_body or port_state and
- {'port': {'state': '%s' % port_state}})
- content_type = "application/%s" % format
- body = data and Serializer().serialize(data, content_type)
- return create_request(path, body, content_type, method)
-
-
-def port_delete_request(tenant_id, network_id, port_id, format='xml'):
- method = 'DELETE'
- path = ("/tenants/%(tenant_id)s/networks/"
- "%(network_id)s/ports/%(port_id)s.%(format)s") % locals()
- content_type = "application/%s" % format
- return create_request(path, None, content_type, method)
-
-
-def update_port_request(tenant_id, network_id, port_id, port_state,
- format='xml', custom_req_body=None):
- method = 'PUT'
- path = ("/tenants/%(tenant_id)s/networks"
- "/%(network_id)s/ports/%(port_id)s.%(format)s") % locals()
- data = custom_req_body or {'port': {'state': '%s' % port_state}}
- content_type = "application/%s" % format
- body = Serializer().serialize(data, content_type)
- return create_request(path, body, content_type, method)
-
-
-def get_attachment_request(tenant_id, network_id, port_id, format='xml'):
- method = 'GET'
- path = ("/tenants/%(tenant_id)s/networks/"
- "%(network_id)s/ports/%(port_id)s/"
- "attachment.%(format)s") % locals()
- content_type = "application/%s" % format
- return create_request(path, None, content_type, method)
-
-
-def put_attachment_request(tenant_id, network_id, port_id,
- attachment_id, format='xml'):
- method = 'PUT'
- path = ("/tenants/%(tenant_id)s/networks/"
- "%(network_id)s/ports/%(port_id)s/"
- "attachment.%(format)s") % locals()
- data = {'attachment': {'id': attachment_id}}
- content_type = "application/%s" % format
- body = Serializer().serialize(data, content_type)
- return create_request(path, body, content_type, method)
-
-
-def delete_attachment_request(tenant_id, network_id, port_id,
- attachment_id, format='xml'):
- method = 'DELETE'
- path = ("/tenants/%(tenant_id)s/networks/"
- "%(network_id)s/ports/%(port_id)s/"
- "attachment.%(format)s") % locals()
- content_type = "application/%s" % format
- return create_request(path, None, content_type, method)