From 77573d733837c6b890d92bc4d46bf5298e5322dd Mon Sep 17 00:00:00 2001 From: Dan Wendlandt Date: Fri, 10 Aug 2012 10:37:26 -0700 Subject: [PATCH] Remove v1 code from quantum-server bp remove-v1-related-code Removes API, DB, and test code that is used only for Quantum v1 API, which is no longer supported. Includes removal of v1 code for sample, ovs, linuxbridge and ryu plugin. Nicira and Cisco plugins will be handled outside of this patchset. Change-Id: Id34dc7229bb7b399b5cfd4602dbc8d5ee4e8de61 --- etc/api-paste.ini | 18 - quantum/api/__init__.py | 108 -- quantum/api/api_common.py | 137 -- quantum/api/attachments.py | 89 -- quantum/api/faults.py | 187 --- quantum/api/networks.py | 188 --- quantum/api/ports.py | 185 --- quantum/api/views/attachments.py | 37 - quantum/api/views/filters.py | 160 --- quantum/api/views/networks.py | 91 -- quantum/api/views/ports.py | 60 - quantum/db/api.py | 198 +-- quantum/db/models.py | 77 -- quantum/extensions/_portstats_view.py | 49 - quantum/extensions/portstats.py | 96 -- .../plugins/linuxbridge/LinuxBridgePlugin.py | 258 ---- quantum/plugins/linuxbridge/common/utils.py | 53 - .../plugins/linuxbridge/db/l2network_db.py | 8 +- .../linuxbridge/db/l2network_models.py | 50 - quantum/plugins/linuxbridge/run_tests.py | 4 - .../linuxbridge/tests/unit/test_database.py | 289 ---- quantum/plugins/openvswitch/ovs_db.py | 56 - quantum/plugins/openvswitch/ovs_models.py | 50 - .../plugins/openvswitch/ovs_quantum_plugin.py | 211 --- quantum/plugins/openvswitch/run_tests.py | 4 - .../openvswitch/tests/unit/test_vlan_map.py | 67 - .../plugins/ryu/agent/ryu_quantum_agent.py | 16 +- quantum/plugins/ryu/common/config.py | 1 - quantum/plugins/ryu/db/api.py | 27 - quantum/plugins/ryu/db/models.py | 37 - .../plugins/ryu/ovs_quantum_plugin_base.py | 173 --- quantum/plugins/ryu/run_tests.py | 4 - quantum/plugins/ryu/ryu_quantum_plugin.py | 39 - quantum/plugins/ryu/tests/unit/basetest.py | 42 - quantum/plugins/ryu/tests/unit/fake_plugin.py | 37 - .../plugins/ryu/tests/unit/fake_rest_nw_id.py | 17 - .../plugins/ryu/tests/unit/fake_ryu_client.py | 46 - .../{test_plugin_base.py => test_defaults.py} | 40 +- quantum/plugins/ryu/tests/unit/test_ryu_db.py | 52 + .../plugins/ryu/tests/unit/test_ryu_driver.py | 75 - quantum/plugins/ryu/tests/unit/utils.py | 58 +- quantum/plugins/sample/SamplePlugin.py | 344 ----- quantum/plugins/sample/SamplePluginV2.py | 121 -- quantum/plugins/sample/__init__.py | 0 quantum/quantum_plugin_base.py | 270 ---- quantum/tests/unit/_test_api.py | 1227 ----------------- quantum/tests/unit/test_api.py | 372 ----- quantum/tests/unit/test_database.py | 127 -- quantum/tests/unit/test_extensions.py | 21 +- quantum/tests/unit/testlib_api.py | 167 --- 50 files changed, 87 insertions(+), 5956 deletions(-) delete mode 100644 quantum/api/attachments.py delete mode 100644 quantum/api/faults.py delete mode 100644 quantum/api/networks.py delete mode 100644 quantum/api/ports.py delete mode 100644 quantum/api/views/attachments.py delete mode 100644 quantum/api/views/filters.py delete mode 100644 quantum/api/views/networks.py delete mode 100644 quantum/api/views/ports.py delete mode 100644 quantum/db/models.py delete mode 100644 quantum/extensions/_portstats_view.py delete mode 100644 quantum/extensions/portstats.py delete mode 100644 quantum/plugins/linuxbridge/LinuxBridgePlugin.py delete mode 100644 quantum/plugins/linuxbridge/common/utils.py delete mode 100644 quantum/plugins/linuxbridge/db/l2network_models.py delete mode 100644 quantum/plugins/linuxbridge/tests/unit/test_database.py delete mode 100644 quantum/plugins/openvswitch/ovs_db.py delete mode 100644 quantum/plugins/openvswitch/ovs_models.py delete mode 100644 quantum/plugins/openvswitch/tests/unit/test_vlan_map.py delete mode 100644 quantum/plugins/ryu/db/api.py delete mode 100644 quantum/plugins/ryu/db/models.py delete mode 100644 quantum/plugins/ryu/ovs_quantum_plugin_base.py delete mode 100644 quantum/plugins/ryu/tests/unit/basetest.py delete mode 100644 quantum/plugins/ryu/tests/unit/fake_plugin.py delete mode 100644 quantum/plugins/ryu/tests/unit/fake_rest_nw_id.py delete mode 100644 quantum/plugins/ryu/tests/unit/fake_ryu_client.py rename quantum/plugins/ryu/tests/unit/{test_plugin_base.py => test_defaults.py} (50%) create mode 100644 quantum/plugins/ryu/tests/unit/test_ryu_db.py delete mode 100644 quantum/plugins/ryu/tests/unit/test_ryu_driver.py delete mode 100644 quantum/plugins/sample/SamplePlugin.py delete mode 100644 quantum/plugins/sample/SamplePluginV2.py delete mode 100644 quantum/plugins/sample/__init__.py delete mode 100644 quantum/quantum_plugin_base.py delete mode 100644 quantum/tests/unit/_test_api.py delete mode 100644 quantum/tests/unit/test_api.py delete mode 100644 quantum/tests/unit/test_database.py diff --git a/etc/api-paste.ini b/etc/api-paste.ini index 2a42529e0..a028d5bf8 100644 --- a/etc/api-paste.ini +++ b/etc/api-paste.ini @@ -1,20 +1,8 @@ [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 @@ -38,11 +26,5 @@ paste.filter_factory = quantum.extensions.extensions:plugin_aware_extension_midd [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 diff --git a/quantum/api/__init__.py b/quantum/api/__init__.py index 2cec49a81..e69de29bb 100644 --- a/quantum/api/__init__.py +++ b/quantum/api/__init__.py @@ -1,108 +0,0 @@ -# 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' diff --git a/quantum/api/api_common.py b/quantum/api/api_common.py index 4e0880232..8debe36f4 100644 --- a/quantum/api/api_common.py +++ b/quantum/api/api_common.py @@ -26,143 +26,6 @@ from quantum import wsgi 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 diff --git a/quantum/api/attachments.py b/quantum/api/attachments.py deleted file mode 100644 index b9cb2ec45..000000000 --- a/quantum/api/attachments.py +++ /dev/null @@ -1,89 +0,0 @@ -# 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" diff --git a/quantum/api/faults.py b/quantum/api/faults.py deleted file mode 100644 index 3497540c4..000000000 --- a/quantum/api/faults.py +++ /dev/null @@ -1,187 +0,0 @@ -# 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) diff --git a/quantum/api/networks.py b/quantum/api/networks.py deleted file mode 100644 index 74ef3dd61..000000000 --- a/quantum/api/networks.py +++ /dev/null @@ -1,188 +0,0 @@ -# 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" diff --git a/quantum/api/ports.py b/quantum/api/ports.py deleted file mode 100644 index 3f423a0d0..000000000 --- a/quantum/api/ports.py +++ /dev/null @@ -1,185 +0,0 @@ -# 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" diff --git a/quantum/api/views/attachments.py b/quantum/api/views/attachments.py deleted file mode 100644 index 31351a1e0..000000000 --- a/quantum/api/views/attachments.py +++ /dev/null @@ -1,37 +0,0 @@ -# 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={}) diff --git a/quantum/api/views/filters.py b/quantum/api/views/filters.py deleted file mode 100644 index 349088cc1..000000000 --- a/quantum/api/views/filters.py +++ /dev/null @@ -1,160 +0,0 @@ -# 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) diff --git a/quantum/api/views/networks.py b/quantum/api/views/networks.py deleted file mode 100644 index fecf467f8..000000000 --- a/quantum/api/views/networks.py +++ /dev/null @@ -1,91 +0,0 @@ -# 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 diff --git a/quantum/api/views/ports.py b/quantum/api/views/ports.py deleted file mode 100644 index 0b210778f..000000000 --- a/quantum/api/views/ports.py +++ /dev/null @@ -1,60 +0,0 @@ -# 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 diff --git a/quantum/db/api.py b/quantum/db/api.py index 3967fc1bf..747916960 100644 --- a/quantum/db/api.py +++ b/quantum/db/api.py @@ -25,10 +25,8 @@ from sqlalchemy import create_engine 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__) @@ -138,197 +136,3 @@ def unregister_models(base=BASE): 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) diff --git a/quantum/db/models.py b/quantum/db/models.py deleted file mode 100644 index 177cba3cf..000000000 --- a/quantum/db/models.py +++ /dev/null @@ -1,77 +0,0 @@ -# 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 "" % (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 "" % (self.uuid, self.name, - self.op_status, self.tenant_id) diff --git a/quantum/extensions/_portstats_view.py b/quantum/extensions/_portstats_view.py deleted file mode 100644 index d67b9147f..000000000 --- a/quantum/extensions/_portstats_view.py +++ /dev/null @@ -1,49 +0,0 @@ -# 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 diff --git a/quantum/extensions/portstats.py b/quantum/extensions/portstats.py deleted file mode 100644 index ff87b2953..000000000 --- a/quantum/extensions/portstats.py +++ /dev/null @@ -1,96 +0,0 @@ -# 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) diff --git a/quantum/plugins/linuxbridge/LinuxBridgePlugin.py b/quantum/plugins/linuxbridge/LinuxBridgePlugin.py deleted file mode 100644 index 0dbaa7237..000000000 --- a/quantum/plugins/linuxbridge/LinuxBridgePlugin.py +++ /dev/null @@ -1,258 +0,0 @@ -# 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 - 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) diff --git a/quantum/plugins/linuxbridge/common/utils.py b/quantum/plugins/linuxbridge/common/utils.py deleted file mode 100644 index f14e8ea7b..000000000 --- a/quantum/plugins/linuxbridge/common/utils.py +++ /dev/null @@ -1,53 +0,0 @@ -# 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], - } diff --git a/quantum/plugins/linuxbridge/db/l2network_db.py b/quantum/plugins/linuxbridge/db/l2network_db.py index a0ca30f75..25c3aa02f 100644 --- a/quantum/plugins/linuxbridge/db/l2network_db.py +++ b/quantum/plugins/linuxbridge/db/l2network_db.py @@ -27,13 +27,12 @@ from quantum.db import models_v2 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): @@ -44,7 +43,6 @@ 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() @@ -182,7 +180,7 @@ def reserve_specific_vlanid(vlan_id): 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"]: @@ -191,7 +189,7 @@ def reserve_specific_vlanid(vlan_id): 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) diff --git a/quantum/plugins/linuxbridge/db/l2network_models.py b/quantum/plugins/linuxbridge/db/l2network_models.py deleted file mode 100644 index 540c93fb4..000000000 --- a/quantum/plugins/linuxbridge/db/l2network_models.py +++ /dev/null @@ -1,50 +0,0 @@ -# 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 "" % (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 "" % (self.vlan_id, self.network_id) diff --git a/quantum/plugins/linuxbridge/run_tests.py b/quantum/plugins/linuxbridge/run_tests.py index 721104521..44f571e8d 100644 --- a/quantum/plugins/linuxbridge/run_tests.py +++ b/quantum/plugins/linuxbridge/run_tests.py @@ -35,7 +35,6 @@ 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 @@ -47,10 +46,7 @@ if __name__ == '__main__': # 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, diff --git a/quantum/plugins/linuxbridge/tests/unit/test_database.py b/quantum/plugins/linuxbridge/tests/unit/test_database.py deleted file mode 100644 index af574bd4b..000000000 --- a/quantum/plugins/linuxbridge/tests/unit/test_database.py +++ /dev/null @@ -1,289 +0,0 @@ -# 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) diff --git a/quantum/plugins/openvswitch/ovs_db.py b/quantum/plugins/openvswitch/ovs_db.py deleted file mode 100644 index 49adade44..000000000 --- a/quantum/plugins/openvswitch/ovs_db.py +++ /dev/null @@ -1,56 +0,0 @@ -# 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() diff --git a/quantum/plugins/openvswitch/ovs_models.py b/quantum/plugins/openvswitch/ovs_models.py deleted file mode 100644 index 52555e175..000000000 --- a/quantum/plugins/openvswitch/ovs_models.py +++ /dev/null @@ -1,50 +0,0 @@ -# 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 "" % (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 "" % (self.ip_address) diff --git a/quantum/plugins/openvswitch/ovs_quantum_plugin.py b/quantum/plugins/openvswitch/ovs_quantum_plugin.py index a0156c81b..aa24cbdca 100644 --- a/quantum/plugins/openvswitch/ovs_quantum_plugin.py +++ b/quantum/plugins/openvswitch/ovs_quantum_plugin.py @@ -23,7 +23,6 @@ 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 @@ -32,223 +31,13 @@ from quantum.db import db_base_plugin_v2 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. diff --git a/quantum/plugins/openvswitch/run_tests.py b/quantum/plugins/openvswitch/run_tests.py index 84c99e937..8496c4a25 100755 --- a/quantum/plugins/openvswitch/run_tests.py +++ b/quantum/plugins/openvswitch/run_tests.py @@ -34,7 +34,6 @@ from nose import core 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 @@ -46,10 +45,7 @@ if __name__ == '__main__': # 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, diff --git a/quantum/plugins/openvswitch/tests/unit/test_vlan_map.py b/quantum/plugins/openvswitch/tests/unit/test_vlan_map.py deleted file mode 100644 index baa5e6321..000000000 --- a/quantum/plugins/openvswitch/tests/unit/test_vlan_map.py +++ /dev/null @@ -1,67 +0,0 @@ -# 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 diff --git a/quantum/plugins/ryu/agent/ryu_quantum_agent.py b/quantum/plugins/ryu/agent/ryu_quantum_agent.py index 65e1c757c..dc1ad4580 100755 --- a/quantum/plugins/ryu/agent/ryu_quantum_agent.py +++ b/quantum/plugins/ryu/agent/ryu_quantum_agent.py @@ -130,13 +130,12 @@ def check_ofp_mode(db): 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): @@ -151,16 +150,10 @@ class OVSQuantumOFPRyuAgent: 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 @@ -232,13 +225,12 @@ def main(): 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) diff --git a/quantum/plugins/ryu/common/config.py b/quantum/plugins/ryu/common/config.py index 66f2656f1..280560d67 100644 --- a/quantum/plugins/ryu/common/config.py +++ b/quantum/plugins/ryu/common/config.py @@ -30,7 +30,6 @@ ovs_opts = [ ] agent_opts = [ - cfg.BoolOpt('target_v2_api', default=True), cfg.IntOpt('polling_interval', default=2), cfg.StrOpt('root_helper', default='sudo'), ] diff --git a/quantum/plugins/ryu/db/api.py b/quantum/plugins/ryu/db/api.py deleted file mode 100644 index caa8b5738..000000000 --- a/quantum/plugins/ryu/db/api.py +++ /dev/null @@ -1,27 +0,0 @@ -# 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. - -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() diff --git a/quantum/plugins/ryu/db/models.py b/quantum/plugins/ryu/db/models.py deleted file mode 100644 index e40f9cac5..000000000 --- a/quantum/plugins/ryu/db/models.py +++ /dev/null @@ -1,37 +0,0 @@ -# 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. - -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_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 "" % (self.id, self.address, - self.host_type) diff --git a/quantum/plugins/ryu/ovs_quantum_plugin_base.py b/quantum/plugins/ryu/ovs_quantum_plugin_base.py deleted file mode 100644 index da941799d..000000000 --- a/quantum/plugins/ryu/ovs_quantum_plugin_base.py +++ /dev/null @@ -1,173 +0,0 @@ -# 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 diff --git a/quantum/plugins/ryu/run_tests.py b/quantum/plugins/ryu/run_tests.py index b0ffe758b..c3628e540 100644 --- a/quantum/plugins/ryu/run_tests.py +++ b/quantum/plugins/ryu/run_tests.py @@ -34,7 +34,6 @@ from nose import core 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 @@ -47,10 +46,7 @@ if __name__ == '__main__': # 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 diff --git a/quantum/plugins/ryu/ryu_quantum_plugin.py b/quantum/plugins/ryu/ryu_quantum_plugin.py index 2a8ad3068..07dd6107b 100644 --- a/quantum/plugins/ryu/ryu_quantum_plugin.py +++ b/quantum/plugins/ryu/ryu_quantum_plugin.py @@ -26,52 +26,13 @@ from quantum.db import api as db 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} diff --git a/quantum/plugins/ryu/tests/unit/basetest.py b/quantum/plugins/ryu/tests/unit/basetest.py deleted file mode 100644 index 5dbd39a1c..000000000 --- a/quantum/plugins/ryu/tests/unit/basetest.py +++ /dev/null @@ -1,42 +0,0 @@ -# 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. - -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() diff --git a/quantum/plugins/ryu/tests/unit/fake_plugin.py b/quantum/plugins/ryu/tests/unit/fake_plugin.py deleted file mode 100644 index 3d521b4f7..000000000 --- a/quantum/plugins/ryu/tests/unit/fake_plugin.py +++ /dev/null @@ -1,37 +0,0 @@ -# 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. - -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) diff --git a/quantum/plugins/ryu/tests/unit/fake_rest_nw_id.py b/quantum/plugins/ryu/tests/unit/fake_rest_nw_id.py deleted file mode 100644 index 5a682cc29..000000000 --- a/quantum/plugins/ryu/tests/unit/fake_rest_nw_id.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (C) 2011 Nippon Telegraph and Telephone Corporation. -# Copyright (C) 2011 Isaku Yamahata -# -# 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 . - -NW_ID_EXTERNAL = '__NW_ID_EXTERNAL__' -NW_ID_UNKNOWN = '__NW_ID_UNKNOWN__' diff --git a/quantum/plugins/ryu/tests/unit/fake_ryu_client.py b/quantum/plugins/ryu/tests/unit/fake_ryu_client.py deleted file mode 100644 index 763b86cf4..000000000 --- a/quantum/plugins/ryu/tests/unit/fake_ryu_client.py +++ /dev/null @@ -1,46 +0,0 @@ -# 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. - - -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 diff --git a/quantum/plugins/ryu/tests/unit/test_plugin_base.py b/quantum/plugins/ryu/tests/unit/test_defaults.py similarity index 50% rename from quantum/plugins/ryu/tests/unit/test_plugin_base.py rename to quantum/plugins/ryu/tests/unit/test_defaults.py index c9391877a..dae4cc422 100644 --- a/quantum/plugins/ryu/tests/unit/test_plugin_base.py +++ b/quantum/plugins/ryu/tests/unit/test_defaults.py @@ -15,46 +15,14 @@ # 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 +from quantum.plugins.ryu.common import config -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) - - 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) diff --git a/quantum/plugins/ryu/tests/unit/test_ryu_db.py b/quantum/plugins/ryu/tests/unit/test_ryu_db.py new file mode 100644 index 000000000..c12849c04 --- /dev/null +++ b/quantum/plugins/ryu/tests/unit/test_ryu_db.py @@ -0,0 +1,52 @@ +# 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. + +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) diff --git a/quantum/plugins/ryu/tests/unit/test_ryu_driver.py b/quantum/plugins/ryu/tests/unit/test_ryu_driver.py deleted file mode 100644 index dde741d65..000000000 --- a/quantum/plugins/ryu/tests/unit/test_ryu_driver.py +++ /dev/null @@ -1,75 +0,0 @@ -# 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. - -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) diff --git a/quantum/plugins/ryu/tests/unit/utils.py b/quantum/plugins/ryu/tests/unit/utils.py index de7ec20f4..eaa5541eb 100644 --- a/quantum/plugins/ryu/tests/unit/utils.py +++ b/quantum/plugins/ryu/tests/unit/utils.py @@ -15,60 +15,18 @@ # 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}) diff --git a/quantum/plugins/sample/SamplePlugin.py b/quantum/plugins/sample/SamplePlugin.py deleted file mode 100644 index 07d59cff0..000000000 --- a/quantum/plugins/sample/SamplePlugin.py +++ /dev/null @@ -1,344 +0,0 @@ -# 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 - 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 - 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) diff --git a/quantum/plugins/sample/SamplePluginV2.py b/quantum/plugins/sample/SamplePluginV2.py deleted file mode 100644 index 5a6f9b94f..000000000 --- a/quantum/plugins/sample/SamplePluginV2.py +++ /dev/null @@ -1,121 +0,0 @@ -# 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) diff --git a/quantum/plugins/sample/__init__.py b/quantum/plugins/sample/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/quantum/quantum_plugin_base.py b/quantum/quantum_plugin_base.py deleted file mode 100644 index 69f91dc5a..000000000 --- a/quantum/quantum_plugin_base.py +++ /dev/null @@ -1,270 +0,0 @@ -# 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 - 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 diff --git a/quantum/tests/unit/_test_api.py b/quantum/tests/unit/_test_api.py deleted file mode 100644 index 26ac1fade..000000000 --- a/quantum/tests/unit/_test_api.py +++ /dev/null @@ -1,1227 +0,0 @@ -# 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) diff --git a/quantum/tests/unit/test_api.py b/quantum/tests/unit/test_api.py deleted file mode 100644 index 82aef8f85..000000000 --- a/quantum/tests/unit/test_api.py +++ /dev/null @@ -1,372 +0,0 @@ -# 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) diff --git a/quantum/tests/unit/test_database.py b/quantum/tests/unit/test_database.py deleted file mode 100644 index 1e883a6a7..000000000 --- a/quantum/tests/unit/test_database.py +++ /dev/null @@ -1,127 +0,0 @@ -# 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) diff --git a/quantum/tests/unit/test_extensions.py b/quantum/tests/unit/test_extensions.py index ed7efdf92..777c745f4 100644 --- a/quantum/tests/unit/test_extensions.py +++ b/quantum/tests/unit/test_extensions.py @@ -19,10 +19,10 @@ import os 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 @@ -32,7 +32,7 @@ from quantum.extensions.extensions import ( 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, @@ -65,6 +65,15 @@ class ExtensionsTestApp(wsgi.Router): 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): @@ -76,8 +85,7 @@ class ResourceExtensionTest(unittest.TestCase): 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'} @@ -473,8 +481,9 @@ def setup_base_app(): 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) diff --git a/quantum/tests/unit/testlib_api.py b/quantum/tests/unit/testlib_api.py index 341a9acb8..2023bf49e 100644 --- a/quantum/tests/unit/testlib_api.py +++ b/quantum/tests/unit/testlib_api.py @@ -28,170 +28,3 @@ def create_request(path, body, content_type, method='GET', query_string=None): 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)