Merging lp:~salvatore-orlando/quantum/quantum-api-alignment
Bug #813433: Align API implementation with specifcation (Critical) Bug #821628: Getting network details is failing (Undecided) Bug #823841: Remove constraint on network names (Medium) Blueprint: Quantum API v1.0 Implementation (Essential)
This commit is contained in:
commit
d5086c8b79
@ -17,7 +17,7 @@ api_extensions_path = extensions
|
||||
[composite:quantum]
|
||||
use = egg:Paste#urlmap
|
||||
/: quantumversions
|
||||
/v0.1: quantumapi
|
||||
/v1.0: quantumapi
|
||||
|
||||
[pipeline:quantumapi]
|
||||
pipeline = extensions quantumapiapp
|
||||
|
@ -26,6 +26,7 @@ import webob.exc
|
||||
|
||||
from quantum import manager
|
||||
from quantum.api import faults
|
||||
from quantum.api import attachments
|
||||
from quantum.api import networks
|
||||
from quantum.api import ports
|
||||
from quantum.common import flags
|
||||
@ -58,24 +59,29 @@ class APIRouterV01(wsgi.Router):
|
||||
path_prefix=uri_prefix)
|
||||
mapper.resource('port', 'ports',
|
||||
controller=ports.Controller(plugin),
|
||||
collection={'detail': 'GET'},
|
||||
member={'detail': 'GET'},
|
||||
parent_resource=dict(member_name='network',
|
||||
collection_name=uri_prefix +\
|
||||
'networks'))
|
||||
|
||||
attachments_ctrl = attachments.Controller(plugin)
|
||||
|
||||
mapper.connect("get_resource",
|
||||
uri_prefix + 'networks/{network_id}/' \
|
||||
'ports/{id}/attachment{.format}',
|
||||
controller=ports.Controller(plugin),
|
||||
controller=attachments_ctrl,
|
||||
action="get_resource",
|
||||
conditions=dict(method=['GET']))
|
||||
mapper.connect("attach_resource",
|
||||
uri_prefix + 'networks/{network_id}/' \
|
||||
'ports/{id}/attachment{.format}',
|
||||
controller=ports.Controller(plugin),
|
||||
controller=attachments_ctrl,
|
||||
action="attach_resource",
|
||||
conditions=dict(method=['PUT']))
|
||||
mapper.connect("detach_resource",
|
||||
uri_prefix + 'networks/{network_id}/' \
|
||||
'ports/{id}/attachment{.format}',
|
||||
controller=ports.Controller(plugin),
|
||||
controller=attachments_ctrl,
|
||||
action="detach_resource",
|
||||
conditions=dict(method=['DELETE']))
|
||||
|
@ -38,7 +38,7 @@ class QuantumController(wsgi.Controller):
|
||||
for param in params:
|
||||
param_name = param['param-name']
|
||||
param_value = None
|
||||
# 1- parse request body
|
||||
# Parameters are expected to be in request body only
|
||||
if req.body:
|
||||
des_body = self._deserialize(req.body,
|
||||
req.best_match_content_type())
|
||||
@ -50,22 +50,13 @@ class QuantumController(wsgi.Controller):
|
||||
LOG.error(line)
|
||||
raise exc.HTTPBadRequest(msg)
|
||||
param_value = data.get(param_name, None)
|
||||
if not param_value:
|
||||
# 2- parse request headers
|
||||
# prepend param name with a 'x-' prefix
|
||||
param_value = req.headers.get("x-" + param_name, None)
|
||||
# 3- parse request query parameters
|
||||
if not param_value:
|
||||
try:
|
||||
param_value = req.str_GET[param_name]
|
||||
except KeyError:
|
||||
#param not found
|
||||
pass
|
||||
if not param_value and param['required']:
|
||||
msg = ("Failed to parse request. " +
|
||||
"Parameter: " + param_name + " not specified")
|
||||
for line in msg.split('\n'):
|
||||
LOG.error(line)
|
||||
raise exc.HTTPBadRequest(msg)
|
||||
|
||||
# If the parameter wasn't found and it was required, return 400
|
||||
if not param_value and param['required']:
|
||||
msg = ("Failed to parse request. " +
|
||||
"Parameter: " + param_name + " not specified")
|
||||
for line in msg.split('\n'):
|
||||
LOG.error(line)
|
||||
raise exc.HTTPBadRequest(msg)
|
||||
results[param_name] = param_value or param.get('default-value')
|
||||
return results
|
||||
|
86
quantum/api/attachments.py
Normal file
86
quantum/api/attachments.py
Normal file
@ -0,0 +1,86 @@
|
||||
# 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 webob import exc
|
||||
|
||||
from quantum.api import api_common as common
|
||||
from quantum.api import faults
|
||||
from quantum.api.views import attachments as attachments_view
|
||||
from quantum.common import exceptions as exception
|
||||
|
||||
LOG = logging.getLogger('quantum.api.ports')
|
||||
|
||||
|
||||
class Controller(common.QuantumController):
|
||||
""" Port API controller for Quantum API """
|
||||
|
||||
_attachment_ops_param_list = [{
|
||||
'param-name': 'id',
|
||||
'required': True}, ]
|
||||
|
||||
_serialization_metadata = {
|
||||
"application/xml": {
|
||||
"attributes": {
|
||||
"attachment": ["id"], }
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(self, plugin):
|
||||
self._resource_name = 'attachment'
|
||||
super(Controller, self).__init__(plugin)
|
||||
|
||||
def get_resource(self, request, tenant_id, network_id, id):
|
||||
try:
|
||||
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)
|
||||
except exception.NetworkNotFound as e:
|
||||
return faults.Fault(faults.NetworkNotFound(e))
|
||||
except exception.PortNotFound as e:
|
||||
return faults.Fault(faults.PortNotFound(e))
|
||||
|
||||
def attach_resource(self, request, tenant_id, network_id, id):
|
||||
try:
|
||||
request_params = \
|
||||
self._parse_request_params(request,
|
||||
self._attachment_ops_param_list)
|
||||
except exc.HTTPError as e:
|
||||
return faults.Fault(e)
|
||||
try:
|
||||
self._plugin.plug_interface(tenant_id, network_id, id,
|
||||
request_params['id'])
|
||||
return exc.HTTPNoContent()
|
||||
except exception.NetworkNotFound as e:
|
||||
return faults.Fault(faults.NetworkNotFound(e))
|
||||
except exception.PortNotFound as e:
|
||||
return faults.Fault(faults.PortNotFound(e))
|
||||
except exception.PortInUse as e:
|
||||
return faults.Fault(faults.PortInUse(e))
|
||||
except exception.AlreadyAttached as e:
|
||||
return faults.Fault(faults.AlreadyAttached(e))
|
||||
|
||||
def detach_resource(self, request, tenant_id, network_id, id):
|
||||
try:
|
||||
self._plugin.unplug_interface(tenant_id,
|
||||
network_id, id)
|
||||
return exc.HTTPNoContent()
|
||||
except exception.NetworkNotFound as e:
|
||||
return faults.Fault(faults.NetworkNotFound(e))
|
||||
except exception.PortNotFound as e:
|
||||
return faults.Fault(faults.PortNotFound(e))
|
@ -31,7 +31,6 @@ class Fault(webob.exc.HTTPException):
|
||||
401: "unauthorized",
|
||||
420: "networkNotFound",
|
||||
421: "networkInUse",
|
||||
422: "networkNameExists",
|
||||
430: "portNotFound",
|
||||
431: "requestedStateInvalid",
|
||||
432: "portInUse",
|
||||
@ -92,22 +91,6 @@ class NetworkInUse(webob.exc.HTTPClientError):
|
||||
explanation = ('Unable to remove the network: attachments still plugged.')
|
||||
|
||||
|
||||
class NetworkNameExists(webob.exc.HTTPClientError):
|
||||
"""
|
||||
subclass of :class:`~HTTPClientError`
|
||||
|
||||
This indicates that the server could not set the network name to the
|
||||
specified value because another network for the same tenant already has
|
||||
that name.
|
||||
|
||||
code: 422, title: Network Name Exists
|
||||
"""
|
||||
code = 422
|
||||
title = 'Network Name Exists'
|
||||
explanation = ('Unable to set network name: tenant already has network' \
|
||||
' with same name.')
|
||||
|
||||
|
||||
class PortNotFound(webob.exc.HTTPClientError):
|
||||
"""
|
||||
subclass of :class:`~HTTPClientError`
|
||||
|
@ -29,7 +29,7 @@ class Controller(common.QuantumController):
|
||||
""" Network API controller for Quantum API """
|
||||
|
||||
_network_ops_param_list = [{
|
||||
'param-name': 'net-name',
|
||||
'param-name': 'name',
|
||||
'required': True}, ]
|
||||
|
||||
_serialization_metadata = {
|
||||
@ -37,38 +37,43 @@ class Controller(common.QuantumController):
|
||||
"attributes": {
|
||||
"network": ["id", "name"],
|
||||
"port": ["id", "state"],
|
||||
},
|
||||
"plurals": {"networks": "network"}
|
||||
},
|
||||
"attachment": ["id"]},
|
||||
"plurals": {"networks": "network",
|
||||
"ports": "port"}},
|
||||
}
|
||||
|
||||
def __init__(self, plugin):
|
||||
self._resource_name = 'network'
|
||||
super(Controller, self).__init__(plugin)
|
||||
|
||||
def index(self, request, tenant_id):
|
||||
""" Returns a list of network ids """
|
||||
#TODO: this should be for a given tenant!!!
|
||||
return self._items(request, tenant_id)
|
||||
|
||||
def _item(self, req, 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)
|
||||
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(req)
|
||||
result = builder.build(network, net_details, port_details)['network']
|
||||
result = builder.build(network, net_details,
|
||||
ports_data, port_details)['network']
|
||||
return dict(network=result)
|
||||
|
||||
def _items(self, req, tenant_id, net_details=False, port_details=False):
|
||||
def _items(self, req, tenant_id, net_details=False):
|
||||
""" Returns a list of networks. """
|
||||
networks = self._plugin.get_all_networks(tenant_id)
|
||||
builder = networks_view.get_view_builder(req)
|
||||
result = [builder.build(network, net_details, port_details)['network']
|
||||
result = [builder.build(network, net_details)['network']
|
||||
for network in networks]
|
||||
return dict(networks=result)
|
||||
|
||||
def index(self, request, tenant_id):
|
||||
""" Returns a list of network ids """
|
||||
return self._items(request, tenant_id)
|
||||
|
||||
def show(self, request, tenant_id, id):
|
||||
""" Returns network details for the given network id """
|
||||
try:
|
||||
@ -80,23 +85,13 @@ class Controller(common.QuantumController):
|
||||
def detail(self, request, **kwargs):
|
||||
tenant_id = kwargs.get('tenant_id')
|
||||
network_id = kwargs.get('id')
|
||||
try:
|
||||
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, port_details=False)
|
||||
network = self._plugin.get_network_details(
|
||||
tenant_id, id)
|
||||
builder = networks_view.get_view_builder(request)
|
||||
#build response with details
|
||||
result = builder.build(network, True)
|
||||
return dict(networks=result)
|
||||
except exception.NetworkNotFound as e:
|
||||
return faults.Fault(faults.NetworkNotFound(e))
|
||||
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)
|
||||
|
||||
def create(self, request, tenant_id):
|
||||
""" Creates a new network for a given tenant """
|
||||
@ -107,15 +102,13 @@ class Controller(common.QuantumController):
|
||||
self._network_ops_param_list)
|
||||
except exc.HTTPError as e:
|
||||
return faults.Fault(e)
|
||||
try:
|
||||
network = self._plugin.\
|
||||
create_network(tenant_id,
|
||||
request_params['net-name'])
|
||||
builder = networks_view.get_view_builder(request)
|
||||
result = builder.build(network)
|
||||
return dict(networks=result)
|
||||
except exception.NetworkNameExists as e:
|
||||
return faults.Fault(faults.NetworkNameExists(e))
|
||||
network = self._plugin.\
|
||||
create_network(tenant_id,
|
||||
request_params['name'])
|
||||
builder = networks_view.get_view_builder(request)
|
||||
result = builder.build(network)['network']
|
||||
#MUST RETURN 202???
|
||||
return dict(network=result)
|
||||
|
||||
def update(self, request, tenant_id, id):
|
||||
""" Updates the name for the network with the given id """
|
||||
@ -127,18 +120,16 @@ class Controller(common.QuantumController):
|
||||
return faults.Fault(e)
|
||||
try:
|
||||
self._plugin.rename_network(tenant_id, id,
|
||||
request_params['net-name'])
|
||||
return exc.HTTPAccepted()
|
||||
request_params['name'])
|
||||
return exc.HTTPNoContent()
|
||||
except exception.NetworkNotFound as e:
|
||||
return faults.Fault(faults.NetworkNotFound(e))
|
||||
except exception.NetworkNameExists as e:
|
||||
return faults.Fault(faults.NetworkNameExists(e))
|
||||
|
||||
def delete(self, request, tenant_id, id):
|
||||
""" Destroys the network with the given id """
|
||||
try:
|
||||
self._plugin.delete_network(tenant_id, id)
|
||||
return exc.HTTPAccepted()
|
||||
return exc.HTTPNoContent()
|
||||
except exception.NetworkNotFound as e:
|
||||
return faults.Fault(faults.NetworkNotFound(e))
|
||||
except exception.NetworkInUse as e:
|
||||
|
@ -29,55 +29,79 @@ class Controller(common.QuantumController):
|
||||
""" Port API controller for Quantum API """
|
||||
|
||||
_port_ops_param_list = [{
|
||||
'param-name': 'port-state',
|
||||
'param-name': 'state',
|
||||
'default-value': 'DOWN',
|
||||
'required': False}, ]
|
||||
|
||||
_attachment_ops_param_list = [{
|
||||
'param-name': 'attachment-id',
|
||||
'required': True}, ]
|
||||
|
||||
_serialization_metadata = {
|
||||
"application/xml": {
|
||||
"attributes": {
|
||||
"port": ["id", "state"], },
|
||||
"plurals": {"ports": "port"}
|
||||
},
|
||||
"port": ["id", "state"],
|
||||
"attachment": ["id"]},
|
||||
"plurals": {"ports": "port"}},
|
||||
}
|
||||
|
||||
def __init__(self, plugin):
|
||||
self._resource_name = 'port'
|
||||
super(Controller, self).__init__(plugin)
|
||||
|
||||
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, is_detail=False)
|
||||
|
||||
def _items(self, request, tenant_id, network_id, is_detail):
|
||||
""" Returns a list of networks. """
|
||||
def _items(self, request, tenant_id, network_id,
|
||||
port_details=False):
|
||||
""" Returns a list of ports. """
|
||||
try:
|
||||
ports = self._plugin.get_all_ports(tenant_id, network_id)
|
||||
port_list = self._plugin.get_all_ports(tenant_id, network_id)
|
||||
builder = ports_view.get_view_builder(request)
|
||||
result = [builder.build(port, is_detail)['port']
|
||||
for port in ports]
|
||||
|
||||
# Load extra data for ports if required.
|
||||
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
|
||||
|
||||
result = [builder.build(port, port_details)['port']
|
||||
for port in port_list]
|
||||
return dict(ports=result)
|
||||
except exception.NetworkNotFound as e:
|
||||
return faults.Fault(faults.NetworkNotFound(e))
|
||||
|
||||
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)
|
||||
result = builder.build(port, port_details=True,
|
||||
att_details=att_details)['port']
|
||||
return dict(port=result)
|
||||
|
||||
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)
|
||||
|
||||
def show(self, request, tenant_id, network_id, id):
|
||||
""" Returns port details for given port and network """
|
||||
try:
|
||||
port = self._plugin.get_port_details(
|
||||
tenant_id, network_id, id)
|
||||
builder = ports_view.get_view_builder(request)
|
||||
#build response with details
|
||||
result = builder.build(port, True)['port']
|
||||
return dict(port=result)
|
||||
return self._item(request, tenant_id, network_id, id)
|
||||
except exception.NetworkNotFound as e:
|
||||
return faults.Fault(faults.NetworkNotFound(e))
|
||||
except exception.PortNotFound as e:
|
||||
return faults.Fault(faults.PortNotFound(e))
|
||||
|
||||
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)
|
||||
|
||||
def create(self, request, tenant_id, network_id):
|
||||
""" Creates a new port for a given network """
|
||||
#look for port state in request
|
||||
@ -89,10 +113,10 @@ class Controller(common.QuantumController):
|
||||
try:
|
||||
port = self._plugin.create_port(tenant_id,
|
||||
network_id,
|
||||
request_params['port-state'])
|
||||
request_params['state'])
|
||||
builder = ports_view.get_view_builder(request)
|
||||
result = builder.build(port)
|
||||
return dict(ports=result)
|
||||
result = builder.build(port)['port']
|
||||
return dict(port=result)
|
||||
except exception.NetworkNotFound as e:
|
||||
return faults.Fault(faults.NetworkNotFound(e))
|
||||
except exception.StateInvalid as e:
|
||||
@ -107,11 +131,9 @@ class Controller(common.QuantumController):
|
||||
except exc.HTTPError as e:
|
||||
return faults.Fault(e)
|
||||
try:
|
||||
port = self._plugin.update_port(tenant_id, network_id, id,
|
||||
request_params['port-state'])
|
||||
builder = ports_view.get_view_builder(request)
|
||||
result = builder.build(port, True)
|
||||
return dict(ports=result)
|
||||
self._plugin.update_port(tenant_id, network_id, id,
|
||||
request_params['state'])
|
||||
return exc.HTTPNoContent()
|
||||
except exception.NetworkNotFound as e:
|
||||
return faults.Fault(faults.NetworkNotFound(e))
|
||||
except exception.PortNotFound as e:
|
||||
@ -124,53 +146,10 @@ class Controller(common.QuantumController):
|
||||
#look for port state in request
|
||||
try:
|
||||
self._plugin.delete_port(tenant_id, network_id, id)
|
||||
return exc.HTTPAccepted()
|
||||
# TODO(salvatore-orlando): Handle portInUse error
|
||||
return exc.HTTPNoContent()
|
||||
except exception.NetworkNotFound as e:
|
||||
return faults.Fault(faults.NetworkNotFound(e))
|
||||
except exception.PortNotFound as e:
|
||||
return faults.Fault(faults.PortNotFound(e))
|
||||
except exception.PortInUse as e:
|
||||
return faults.Fault(faults.PortInUse(e))
|
||||
|
||||
def get_resource(self, request, tenant_id, network_id, id):
|
||||
try:
|
||||
result = self._plugin.get_port_details(
|
||||
tenant_id, network_id, id).get('attachment-id',
|
||||
None)
|
||||
return dict(attachment=result)
|
||||
except exception.NetworkNotFound as e:
|
||||
return faults.Fault(faults.NetworkNotFound(e))
|
||||
except exception.PortNotFound as e:
|
||||
return faults.Fault(faults.PortNotFound(e))
|
||||
|
||||
def attach_resource(self, request, tenant_id, network_id, id):
|
||||
try:
|
||||
request_params = \
|
||||
self._parse_request_params(request,
|
||||
self._attachment_ops_param_list)
|
||||
except exc.HTTPError as e:
|
||||
return faults.Fault(e)
|
||||
try:
|
||||
self._plugin.plug_interface(tenant_id,
|
||||
network_id, id,
|
||||
request_params['attachment-id'])
|
||||
return exc.HTTPAccepted()
|
||||
except exception.NetworkNotFound as e:
|
||||
return faults.Fault(faults.NetworkNotFound(e))
|
||||
except exception.PortNotFound as e:
|
||||
return faults.Fault(faults.PortNotFound(e))
|
||||
except exception.PortInUse as e:
|
||||
return faults.Fault(faults.PortInUse(e))
|
||||
except exception.AlreadyAttached as e:
|
||||
return faults.Fault(faults.AlreadyAttached(e))
|
||||
|
||||
def detach_resource(self, request, tenant_id, network_id, id):
|
||||
try:
|
||||
self._plugin.unplug_interface(tenant_id,
|
||||
network_id, id)
|
||||
return exc.HTTPAccepted()
|
||||
except exception.NetworkNotFound as e:
|
||||
return faults.Fault(faults.NetworkNotFound(e))
|
||||
except exception.PortNotFound as e:
|
||||
return faults.Fault(faults.PortNotFound(e))
|
||||
|
@ -31,11 +31,11 @@ class Versions(wsgi.Application):
|
||||
"""Respond to a request for all Quantum API versions."""
|
||||
version_objs = [
|
||||
{
|
||||
"id": "v0.1",
|
||||
"id": "v1.0",
|
||||
"status": "CURRENT",
|
||||
},
|
||||
{
|
||||
"id": "v1.0",
|
||||
"id": "v1.1",
|
||||
"status": "FUTURE",
|
||||
},
|
||||
]
|
||||
|
37
quantum/api/views/attachments.py
Normal file
37
quantum/api/views/attachments.py
Normal file
@ -0,0 +1,37 @@
|
||||
# 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={})
|
@ -15,8 +15,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from quantum.api.views import ports as ports_view
|
||||
|
||||
|
||||
def get_view_builder(req):
|
||||
base_url = req.application_url
|
||||
@ -31,17 +29,16 @@ class ViewBuilder(object):
|
||||
"""
|
||||
self.base_url = base_url
|
||||
|
||||
def build(self, network_data, net_detail=False, port_detail=False):
|
||||
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:
|
||||
builder = ports_view.ViewBuilder(self.base_url)
|
||||
ports = [builder.build(port_data, port_detail)['port']
|
||||
for port_data in network_data['net-ports'].values()]
|
||||
network['ports'] = ports
|
||||
ports = [self._build_port(port_data) for port_data in ports_data]
|
||||
network['network']['ports'] = ports
|
||||
return network
|
||||
|
||||
def _build_simple(self, network_data):
|
||||
@ -55,6 +52,8 @@ class ViewBuilder(object):
|
||||
|
||||
def _build_port(self, port_data):
|
||||
"""Return details about a specific logical port."""
|
||||
return dict(port=dict(id=port_data['port-id'],
|
||||
state=port_data['port-state'],
|
||||
attachment=port_data['attachment']))
|
||||
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
|
||||
|
@ -29,19 +29,11 @@ class ViewBuilder(object):
|
||||
"""
|
||||
self.base_url = base_url
|
||||
|
||||
def build(self, port_data, is_detail=False):
|
||||
def build(self, port_data, port_details=False, att_details=False):
|
||||
"""Generic method used to generate a port entity."""
|
||||
if is_detail:
|
||||
port = self._build_detail(port_data)
|
||||
else:
|
||||
port = self._build_simple(port_data)
|
||||
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
|
||||
|
||||
def _build_simple(self, port_data):
|
||||
"""Return a simple model of a port."""
|
||||
return dict(port=dict(id=port_data['port-id']))
|
||||
|
||||
def _build_detail(self, port_data):
|
||||
"""Return a simple model of a port (with its state)."""
|
||||
return dict(port=dict(id=port_data['port-id'],
|
||||
state=port_data['port-state']))
|
||||
|
@ -69,7 +69,7 @@ def api_create_net(client, *args):
|
||||
LOG.debug(res)
|
||||
nid = None
|
||||
try:
|
||||
nid = res["networks"]["network"]["id"]
|
||||
nid = res["network"]["id"]
|
||||
except Exception, e:
|
||||
print "Failed to create network"
|
||||
# TODO(bgh): grab error details from ws request result
|
||||
@ -104,7 +104,7 @@ def detail_net(manager, *args):
|
||||
def api_detail_net(client, *args):
|
||||
tid, nid = args
|
||||
try:
|
||||
res = client.show_network_details(nid)["networks"]["network"]
|
||||
res = client.show_network_details(nid)["network"]
|
||||
except Exception, e:
|
||||
LOG.error("Failed to get network details: %s" % e)
|
||||
return
|
||||
@ -121,7 +121,7 @@ def api_detail_net(client, *args):
|
||||
pid = port["id"]
|
||||
res = client.show_port_attachment(nid, pid)
|
||||
LOG.debug(res)
|
||||
remote_iface = res["attachment"]
|
||||
remote_iface = res["attachment"]["id"]
|
||||
print "\tRemote interface:%s" % remote_iface
|
||||
|
||||
|
||||
@ -133,7 +133,7 @@ def rename_net(manager, *args):
|
||||
|
||||
def api_rename_net(client, *args):
|
||||
tid, nid, name = args
|
||||
data = {'network': {'net-name': '%s' % name}}
|
||||
data = {'network': {'name': '%s' % name}}
|
||||
try:
|
||||
res = client.update_network(nid, data)
|
||||
except Exception, e:
|
||||
@ -179,7 +179,7 @@ def api_create_port(client, *args):
|
||||
except Exception, e:
|
||||
LOG.error("Failed to create port: %s" % e)
|
||||
return
|
||||
new_port = res["ports"]["port"]["id"]
|
||||
new_port = res["port"]["id"]
|
||||
print "Created Virtual Port:%s " \
|
||||
"on Virtual Network:%s" % (new_port, nid)
|
||||
|
||||
@ -214,16 +214,17 @@ def detail_port(manager, *args):
|
||||
def api_detail_port(client, *args):
|
||||
tid, nid, pid = args
|
||||
try:
|
||||
port = client.show_port_details(nid, pid)["ports"]["port"]
|
||||
port = client.show_port_details(nid, pid)["port"]
|
||||
att = client.show_port_attachment(nid, pid)
|
||||
except Exception, e:
|
||||
LOG.error("Failed to get port details: %s" % e)
|
||||
return
|
||||
|
||||
id = port["id"]
|
||||
attachment = port["attachment"]
|
||||
id = port['id']
|
||||
interface_id = att['id']
|
||||
LOG.debug(port)
|
||||
print "Virtual Port:%s on Virtual Network:%s " \
|
||||
"contains remote interface:%s" % (pid, nid, attachment)
|
||||
"contains remote interface:%s" % (pid, nid, interface_id)
|
||||
|
||||
|
||||
def plug_iface(manager, *args):
|
||||
@ -236,7 +237,7 @@ def plug_iface(manager, *args):
|
||||
def api_plug_iface(client, *args):
|
||||
tid, nid, pid, vid = args
|
||||
try:
|
||||
data = {'port': {'attachment-id': '%s' % vid}}
|
||||
data = {'attachment': {'id': '%s' % vid}}
|
||||
res = client.attach_resource(nid, pid, data)
|
||||
except Exception, e:
|
||||
LOG.error("Failed to plug iface \"%s\" to port \"%s\": %s" % (vid,
|
||||
|
@ -27,13 +27,10 @@ EXCEPTIONS = {
|
||||
401: exceptions.NotAuthorized,
|
||||
420: exceptions.NetworkNotFound,
|
||||
421: exceptions.NetworkInUse,
|
||||
422: exceptions.NetworkNameExists,
|
||||
430: exceptions.PortNotFound,
|
||||
431: exceptions.StateInvalid,
|
||||
432: exceptions.PortInUse,
|
||||
440: exceptions.AlreadyAttached,
|
||||
441: exceptions.AttachmentNotReady,
|
||||
}
|
||||
440: exceptions.AlreadyAttached}
|
||||
|
||||
|
||||
class ApiCall(object):
|
||||
@ -72,7 +69,7 @@ class Client(object):
|
||||
|
||||
def __init__(self, host="127.0.0.1", port=9696, use_ssl=False, tenant=None,
|
||||
format="xml", testingStub=None, key_file=None, cert_file=None,
|
||||
logger=None, action_prefix="/v0.1/tenants/{tenant_id}"):
|
||||
logger=None, action_prefix="/v1.0/tenants/{tenant_id}"):
|
||||
"""
|
||||
Creates a new client to some service.
|
||||
|
||||
|
@ -111,16 +111,6 @@ class AlreadyAttached(QuantumException):
|
||||
"already plugged into port %(att_port_id)s")
|
||||
|
||||
|
||||
class AttachmentNotReady(QuantumException):
|
||||
message = _("The attachment %(att_id)s is not ready")
|
||||
|
||||
|
||||
class NetworkNameExists(QuantumException):
|
||||
message = _("Unable to set network name to %(net_name). " \
|
||||
"Network with id %(net_id) already has this name for " \
|
||||
"tenant %(tenant_id)")
|
||||
|
||||
|
||||
class Duplicate(Error):
|
||||
pass
|
||||
|
||||
|
@ -122,6 +122,7 @@ class Request(webob.Request):
|
||||
Based on the query extension then the Accept header.
|
||||
|
||||
"""
|
||||
# First lookup http request
|
||||
parts = self.path.rsplit('.', 1)
|
||||
LOG.debug("Request parts:%s", parts)
|
||||
if len(parts) > 1:
|
||||
@ -129,21 +130,26 @@ class Request(webob.Request):
|
||||
if format in ['json', 'xml']:
|
||||
return 'application/{0}'.format(parts[1])
|
||||
|
||||
#Then look up content header
|
||||
type_from_header = self.get_content_type()
|
||||
if type_from_header:
|
||||
return type_from_header
|
||||
ctypes = ['application/json', 'application/xml']
|
||||
|
||||
#Finally search in Accept-* headers
|
||||
bm = self.accept.best_match(ctypes)
|
||||
return bm or 'application/json'
|
||||
|
||||
def get_content_type(self):
|
||||
allowed_types = ("application/xml", "application/json")
|
||||
if not "Content-Type" in self.headers:
|
||||
msg = _("Missing Content-Type")
|
||||
LOG.debug(msg)
|
||||
raise webob.exc.HTTPBadRequest(msg)
|
||||
LOG.debug(_("Missing Content-Type"))
|
||||
return None
|
||||
type = self.content_type
|
||||
if type in allowed_types:
|
||||
return type
|
||||
LOG.debug(_("Wrong Content-Type: %s") % type)
|
||||
raise webob.exc.HTTPBadRequest("Invalid content type")
|
||||
return None
|
||||
|
||||
|
||||
class Application(object):
|
||||
|
@ -17,6 +17,8 @@
|
||||
# @author: Brad Hall, Nicira Networks, Inc.
|
||||
# @author: Dan Wendlandt, Nicira Networks, Inc.
|
||||
|
||||
import logging
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker, exc
|
||||
|
||||
@ -27,6 +29,7 @@ from quantum.db import models
|
||||
_ENGINE = None
|
||||
_MAKER = None
|
||||
BASE = models.BASE
|
||||
LOG = logging.getLogger('quantum.db.api')
|
||||
|
||||
|
||||
def configure_db(options):
|
||||
@ -78,6 +81,11 @@ def unregister_models():
|
||||
|
||||
|
||||
def _check_duplicate_net_name(tenant_id, net_name):
|
||||
"""Checks whether a network with the same name
|
||||
already exists for the tenant.
|
||||
"""
|
||||
|
||||
#TODO(salvatore-orlando): Not used anymore - candidate for removal
|
||||
session = get_session()
|
||||
try:
|
||||
net = session.query(models.Network).\
|
||||
@ -94,7 +102,6 @@ def _check_duplicate_net_name(tenant_id, net_name):
|
||||
def network_create(tenant_id, name):
|
||||
session = get_session()
|
||||
|
||||
_check_duplicate_net_name(tenant_id, name)
|
||||
with session.begin():
|
||||
net = models.Network(tenant_id, name)
|
||||
session.add(net)
|
||||
|
@ -70,13 +70,14 @@ class Port(BASE, QuantumBase):
|
||||
uuid = Column(String(255), primary_key=True)
|
||||
network_id = Column(String(255), ForeignKey("networks.uuid"),
|
||||
nullable=False)
|
||||
interface_id = Column(String(255))
|
||||
interface_id = Column(String(255), nullable=True)
|
||||
# Port state - Hardcoding string value at the moment
|
||||
state = Column(String(8))
|
||||
|
||||
def __init__(self, network_id):
|
||||
self.uuid = str(uuid.uuid4())
|
||||
self.network_id = network_id
|
||||
self.interface_id = None
|
||||
self.state = "DOWN"
|
||||
|
||||
def __repr__(self):
|
||||
|
@ -352,7 +352,7 @@ class FakePlugin(object):
|
||||
LOG.debug("FakePlugin.get_port_details() called")
|
||||
port = self._get_port(tenant_id, net_id, port_id)
|
||||
return {'port-id': str(port.uuid),
|
||||
'attachment-id': port.interface_id,
|
||||
'attachment': port.interface_id,
|
||||
'port-state': port.state}
|
||||
|
||||
def create_port(self, tenant_id, net_id, port_state=None):
|
||||
@ -407,10 +407,10 @@ class FakePlugin(object):
|
||||
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)
|
||||
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'])
|
||||
|
@ -48,7 +48,7 @@ class APITest(unittest.TestCase):
|
||||
if expected_res_status == 200:
|
||||
network_data = Serializer().deserialize(network_res.body,
|
||||
content_type)
|
||||
return network_data['networks']['network']['id']
|
||||
return network_data['network']['id']
|
||||
|
||||
def _create_port(self, network_id, port_state, format,
|
||||
custom_req_body=None, expected_res_status=200):
|
||||
@ -61,7 +61,7 @@ class APITest(unittest.TestCase):
|
||||
self.assertEqual(port_res.status_int, expected_res_status)
|
||||
if expected_res_status == 200:
|
||||
port_data = Serializer().deserialize(port_res.body, content_type)
|
||||
return port_data['ports']['port']['id']
|
||||
return port_data['port']['id']
|
||||
|
||||
def _test_create_network(self, format):
|
||||
LOG.debug("_test_create_network - format:%s - START", format)
|
||||
@ -74,8 +74,7 @@ class APITest(unittest.TestCase):
|
||||
self.assertEqual(show_network_res.status_int, 200)
|
||||
network_data = Serializer().deserialize(show_network_res.body,
|
||||
content_type)
|
||||
self.assertEqual(network_id,
|
||||
network_data['network']['id'])
|
||||
self.assertEqual(network_id, network_data['network']['id'])
|
||||
LOG.debug("_test_create_network - format:%s - END", format)
|
||||
|
||||
def _test_create_network_badrequest(self, format):
|
||||
@ -102,6 +101,25 @@ class APITest(unittest.TestCase):
|
||||
self.assertEqual(len(network_data['networks']), 2)
|
||||
LOG.debug("_test_list_networks - format:%s - END", format)
|
||||
|
||||
def _test_list_networks_detail(self, format):
|
||||
LOG.debug("_test_list_networks_detail - format:%s - START", format)
|
||||
content_type = "application/%s" % format
|
||||
self._create_network(format, "net_1")
|
||||
self._create_network(format, "net_2")
|
||||
list_network_req = testlib.network_list_detail_request(self.tenant_id,
|
||||
format)
|
||||
list_network_res = list_network_req.get_response(self.api)
|
||||
self.assertEqual(list_network_res.status_int, 200)
|
||||
network_data = self._net_serializer.deserialize(
|
||||
list_network_res.body, content_type)
|
||||
# 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 - format:%s - END", format)
|
||||
|
||||
def _test_show_network(self, format):
|
||||
LOG.debug("_test_show_network - format:%s - START", format)
|
||||
content_type = "application/%s" % format
|
||||
@ -118,6 +136,25 @@ class APITest(unittest.TestCase):
|
||||
network_data['network'])
|
||||
LOG.debug("_test_show_network - format:%s - END", format)
|
||||
|
||||
def _test_show_network_detail(self, format):
|
||||
LOG.debug("_test_show_network_detail - format:%s - START", format)
|
||||
content_type = "application/%s" % format
|
||||
# Create a network and a port
|
||||
network_id = self._create_network(format)
|
||||
port_id = self._create_port(network_id, "ACTIVE", format)
|
||||
show_network_req = testlib.show_network_detail_request(
|
||||
self.tenant_id, network_id, format)
|
||||
show_network_res = show_network_req.get_response(self.api)
|
||||
self.assertEqual(show_network_res.status_int, 200)
|
||||
network_data = self._net_serializer.deserialize(
|
||||
show_network_res.body, content_type)
|
||||
self.assertEqual({'id': network_id,
|
||||
'name': self.network_name,
|
||||
'ports': [{'id': port_id,
|
||||
'state': 'ACTIVE'}]},
|
||||
network_data['network'])
|
||||
LOG.debug("_test_show_network_detail - format:%s - END", format)
|
||||
|
||||
def _test_show_network_not_found(self, format):
|
||||
LOG.debug("_test_show_network_not_found - format:%s - START", format)
|
||||
show_network_req = testlib.show_network_request(self.tenant_id,
|
||||
@ -137,7 +174,7 @@ class APITest(unittest.TestCase):
|
||||
new_name,
|
||||
format)
|
||||
update_network_res = update_network_req.get_response(self.api)
|
||||
self.assertEqual(update_network_res.status_int, 202)
|
||||
self.assertEqual(update_network_res.status_int, 204)
|
||||
show_network_req = testlib.show_network_request(self.tenant_id,
|
||||
network_id,
|
||||
format)
|
||||
@ -187,7 +224,7 @@ class APITest(unittest.TestCase):
|
||||
network_id,
|
||||
format)
|
||||
delete_network_res = delete_network_req.get_response(self.api)
|
||||
self.assertEqual(delete_network_res.status_int, 202)
|
||||
self.assertEqual(delete_network_res.status_int, 204)
|
||||
list_network_req = testlib.network_list_request(self.tenant_id,
|
||||
format)
|
||||
list_network_res = list_network_req.get_response(self.api)
|
||||
@ -213,7 +250,7 @@ class APITest(unittest.TestCase):
|
||||
port_id,
|
||||
attachment_id)
|
||||
attachment_res = attachment_req.get_response(self.api)
|
||||
self.assertEquals(attachment_res.status_int, 202)
|
||||
self.assertEquals(attachment_res.status_int, 204)
|
||||
|
||||
LOG.debug("Deleting network %(network_id)s"\
|
||||
" of tenant %(tenant_id)s", locals())
|
||||
@ -241,6 +278,27 @@ class APITest(unittest.TestCase):
|
||||
self.assertEqual(len(port_data['ports']), 2)
|
||||
LOG.debug("_test_list_ports - format:%s - END", format)
|
||||
|
||||
def _test_list_ports_detail(self, format):
|
||||
LOG.debug("_test_list_ports_detail - format:%s - START", format)
|
||||
content_type = "application/%s" % format
|
||||
port_state = "ACTIVE"
|
||||
network_id = self._create_network(format)
|
||||
self._create_port(network_id, port_state, format)
|
||||
self._create_port(network_id, port_state, format)
|
||||
list_port_req = testlib.port_list_detail_request(self.tenant_id,
|
||||
network_id, format)
|
||||
list_port_res = list_port_req.get_response(self.api)
|
||||
self.assertEqual(list_port_res.status_int, 200)
|
||||
port_data = self._port_serializer.deserialize(
|
||||
list_port_res.body, content_type)
|
||||
# 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 - format:%s - END", format)
|
||||
|
||||
def _test_show_port(self, format):
|
||||
LOG.debug("_test_show_port - format:%s - START", format)
|
||||
content_type = "application/%s" % format
|
||||
@ -258,6 +316,44 @@ class APITest(unittest.TestCase):
|
||||
port_data['port'])
|
||||
LOG.debug("_test_show_port - format:%s - END", format)
|
||||
|
||||
def _test_show_port_detail(self, format):
|
||||
LOG.debug("_test_show_port - format:%s - START", format)
|
||||
content_type = "application/%s" % format
|
||||
port_state = "ACTIVE"
|
||||
network_id = self._create_network(format)
|
||||
port_id = self._create_port(network_id, port_state, format)
|
||||
|
||||
# Part 1 - no attachment
|
||||
show_port_req = testlib.show_port_detail_request(self.tenant_id,
|
||||
network_id, port_id, format)
|
||||
show_port_res = show_port_req.get_response(self.api)
|
||||
self.assertEqual(show_port_res.status_int, 200)
|
||||
port_data = self._port_serializer.deserialize(
|
||||
show_port_res.body, content_type)
|
||||
self.assertEqual({'id': port_id, 'state': port_state},
|
||||
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,
|
||||
format)
|
||||
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, format)
|
||||
show_port_res = show_port_req.get_response(self.api)
|
||||
self.assertEqual(show_port_res.status_int, 200)
|
||||
port_data = self._port_serializer.deserialize(
|
||||
show_port_res.body, content_type)
|
||||
self.assertEqual({'id': port_id, 'state': port_state,
|
||||
'attachment': {'id': interface_id}},
|
||||
port_data['port'])
|
||||
|
||||
LOG.debug("_test_show_port_detail - format:%s - END", format)
|
||||
|
||||
def _test_show_port_networknotfound(self, format):
|
||||
LOG.debug("_test_show_port_networknotfound - format:%s - START",
|
||||
format)
|
||||
@ -343,7 +439,7 @@ class APITest(unittest.TestCase):
|
||||
network_id, port_id,
|
||||
format)
|
||||
delete_port_res = delete_port_req.get_response(self.api)
|
||||
self.assertEqual(delete_port_res.status_int, 202)
|
||||
self.assertEqual(delete_port_res.status_int, 204)
|
||||
list_port_req = testlib.port_list_request(self.tenant_id, network_id,
|
||||
format)
|
||||
list_port_res = list_port_req.get_response(self.api)
|
||||
@ -367,7 +463,7 @@ class APITest(unittest.TestCase):
|
||||
port_id,
|
||||
attachment_id)
|
||||
attachment_res = attachment_req.get_response(self.api)
|
||||
self.assertEquals(attachment_res.status_int, 202)
|
||||
self.assertEquals(attachment_res.status_int, 204)
|
||||
LOG.debug("Deleting port %(port_id)s for network %(network_id)s"\
|
||||
" of tenant %(tenant_id)s", locals())
|
||||
delete_port_req = testlib.port_delete_request(self.tenant_id,
|
||||
@ -417,7 +513,7 @@ class APITest(unittest.TestCase):
|
||||
new_port_state,
|
||||
format)
|
||||
update_port_res = update_port_req.get_response(self.api)
|
||||
self.assertEqual(update_port_res.status_int, 200)
|
||||
self.assertEqual(update_port_res.status_int, 204)
|
||||
show_port_req = testlib.show_port_request(self.tenant_id,
|
||||
network_id, port_id,
|
||||
format)
|
||||
@ -427,6 +523,22 @@ class APITest(unittest.TestCase):
|
||||
show_port_res.body, content_type)
|
||||
self.assertEqual({'id': port_id, 'state': new_port_state},
|
||||
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,
|
||||
format)
|
||||
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,
|
||||
format)
|
||||
show_port_res = show_port_req.get_response(self.api)
|
||||
self.assertEqual(show_port_res.status_int, 200)
|
||||
port_data = self._port_serializer.deserialize(
|
||||
show_port_res.body, content_type)
|
||||
self.assertEqual({'id': port_id, 'state': port_state},
|
||||
port_data['port'])
|
||||
LOG.debug("_test_set_port_state - format:%s - END", format)
|
||||
|
||||
def _test_set_port_state_networknotfound(self, format):
|
||||
@ -491,7 +603,7 @@ class APITest(unittest.TestCase):
|
||||
interface_id,
|
||||
format)
|
||||
put_attachment_res = put_attachment_req.get_response(self.api)
|
||||
self.assertEqual(put_attachment_res.status_int, 202)
|
||||
self.assertEqual(put_attachment_res.status_int, 204)
|
||||
get_attachment_req = testlib.get_attachment_request(self.tenant_id,
|
||||
network_id,
|
||||
port_id,
|
||||
@ -499,7 +611,7 @@ class APITest(unittest.TestCase):
|
||||
get_attachment_res = get_attachment_req.get_response(self.api)
|
||||
attachment_data = Serializer().deserialize(get_attachment_res.body,
|
||||
content_type)
|
||||
self.assertEqual(attachment_data['attachment'], interface_id)
|
||||
self.assertEqual(attachment_data['attachment']['id'], interface_id)
|
||||
LOG.debug("_test_show_attachment - format:%s - END", format)
|
||||
|
||||
def _test_show_attachment_networknotfound(self, format):
|
||||
@ -544,7 +656,7 @@ class APITest(unittest.TestCase):
|
||||
interface_id,
|
||||
format)
|
||||
put_attachment_res = put_attachment_req.get_response(self.api)
|
||||
self.assertEqual(put_attachment_res.status_int, 202)
|
||||
self.assertEqual(put_attachment_res.status_int, 204)
|
||||
LOG.debug("_test_put_attachment - format:%s - END", format)
|
||||
|
||||
def _test_put_attachment_networknotfound(self, format):
|
||||
@ -593,13 +705,13 @@ class APITest(unittest.TestCase):
|
||||
interface_id,
|
||||
format)
|
||||
put_attachment_res = put_attachment_req.get_response(self.api)
|
||||
self.assertEqual(put_attachment_res.status_int, 202)
|
||||
self.assertEqual(put_attachment_res.status_int, 204)
|
||||
del_attachment_req = testlib.delete_attachment_request(self.tenant_id,
|
||||
network_id,
|
||||
port_id,
|
||||
format)
|
||||
del_attachment_res = del_attachment_req.get_response(self.api)
|
||||
self.assertEqual(del_attachment_res.status_int, 202)
|
||||
self.assertEqual(del_attachment_res.status_int, 204)
|
||||
LOG.debug("_test_delete_attachment - format:%s - END", format)
|
||||
|
||||
def _test_delete_attachment_networknotfound(self, format):
|
||||
@ -670,6 +782,12 @@ class APITest(unittest.TestCase):
|
||||
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')
|
||||
|
||||
@ -694,6 +812,12 @@ class APITest(unittest.TestCase):
|
||||
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')
|
||||
|
||||
@ -730,12 +854,24 @@ class APITest(unittest.TestCase):
|
||||
def test_list_ports_xml(self):
|
||||
self._test_list_ports('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')
|
||||
|
||||
|
@ -43,7 +43,7 @@ class ServerStub():
|
||||
return self.content
|
||||
|
||||
def status(self):
|
||||
return status
|
||||
return self.status
|
||||
|
||||
# To test error codes, set the host to 10.0.0.1, and the port to the code
|
||||
def __init__(self, host, port=9696, key_file="", cert_file=""):
|
||||
|
@ -12,26 +12,45 @@ def create_request(path, body, content_type, method='GET'):
|
||||
return req
|
||||
|
||||
|
||||
def network_list_request(tenant_id, format='xml'):
|
||||
def _network_list_request(tenant_id, format='xml', detail=False):
|
||||
method = 'GET'
|
||||
path = "/tenants/%(tenant_id)s/networks.%(format)s" % locals()
|
||||
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)
|
||||
|
||||
|
||||
def network_list_request(tenant_id, format='xml'):
|
||||
return _network_list_request(tenant_id, format)
|
||||
|
||||
|
||||
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'):
|
||||
method = 'GET'
|
||||
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)
|
||||
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': {'net-name': '%s' % network_name}}
|
||||
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)
|
||||
@ -42,7 +61,7 @@ def update_network_request(tenant_id, network_id, network_name, format='xml',
|
||||
method = 'PUT'
|
||||
path = "/tenants/%(tenant_id)s/networks" \
|
||||
"/%(network_id)s.%(format)s" % locals()
|
||||
data = custom_req_body or {'network': {'net-name': '%s' % network_name}}
|
||||
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)
|
||||
@ -56,20 +75,41 @@ def network_delete_request(tenant_id, network_id, format='xml'):
|
||||
return create_request(path, None, content_type, method)
|
||||
|
||||
|
||||
def port_list_request(tenant_id, network_id, format='xml'):
|
||||
def _port_list_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/ports.%(format)s" % locals()
|
||||
"%(network_id)s/ports%(detail_str)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'):
|
||||
return _port_list_request(tenant_id, network_id, format)
|
||||
|
||||
|
||||
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'):
|
||||
method = 'GET'
|
||||
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)
|
||||
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,
|
||||
@ -78,7 +118,7 @@ def new_port_request(tenant_id, network_id, port_state,
|
||||
path = "/tenants/%(tenant_id)s/networks/" \
|
||||
"%(network_id)s/ports.%(format)s" % locals()
|
||||
data = custom_req_body or port_state and \
|
||||
{'port': {'port-state': '%s' % port_state}}
|
||||
{'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)
|
||||
@ -97,7 +137,7 @@ def update_port_request(tenant_id, network_id, port_id, port_state,
|
||||
method = 'PUT'
|
||||
path = "/tenants/%(tenant_id)s/networks" \
|
||||
"/%(network_id)s/ports/%(port_id)s.%(format)s" % locals()
|
||||
data = custom_req_body or {'port': {'port-state': '%s' % port_state}}
|
||||
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)
|
||||
@ -116,7 +156,7 @@ def put_attachment_request(tenant_id, network_id, port_id,
|
||||
method = 'PUT'
|
||||
path = "/tenants/%(tenant_id)s/networks/" \
|
||||
"%(network_id)s/ports/%(port_id)s/attachment.%(format)s" % locals()
|
||||
data = {'port': {'attachment-id': attachment_id}}
|
||||
data = {'attachment': {'id': attachment_id}}
|
||||
content_type = "application/%s" % format
|
||||
body = Serializer().serialize(data, content_type)
|
||||
return create_request(path, body, content_type, method)
|
||||
|
Loading…
x
Reference in New Issue
Block a user