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: Id34dc7229bb7b399b5cfd4602dbc8d5ee4e8de61changes/98/10998/6
parent
2a2d7f2e3a
commit
77573d7338
|
@ -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
|
||||
|
|
|
@ -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'
|
|
@ -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
|
||||
|
|
|
@ -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"
|
|
@ -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)
|
|
@ -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"
|
|
@ -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"
|
|
@ -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={})
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
|
@ -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):
|
||||