Fixing detail action for port collection

Adding PortIsDown exception
Adding unit tests for detail actions and PortIsDown
PEP8 FIXES
This commit is contained in:
Salvatore Orlando 2011-08-08 13:02:09 +01:00
parent 1b3d8c76e5
commit 100f47e9e6
10 changed files with 247 additions and 25 deletions

View File

@ -72,6 +72,8 @@ class Controller(common.QuantumController):
return faults.Fault(faults.PortNotFound(e))
except exception.PortInUse as e:
return faults.Fault(faults.PortInUse(e))
except exception.PortIsDown as e:
return faults.Fault(faults.PortIsDown(e))
except exception.AlreadyAttached as e:
return faults.Fault(faults.AlreadyAttached(e))

View File

@ -34,6 +34,7 @@ class Fault(webob.exc.HTTPException):
430: "portNotFound",
431: "requestedStateInvalid",
432: "portInUse",
433: "portIsDown",
440: "alreadyAttached",
470: "serviceUnavailable",
471: "pluginFault"}
@ -133,6 +134,19 @@ class PortInUse(webob.exc.HTTPClientError):
explanation = ('A resource is currently attached to the logical port')
class PortIsDown(webob.exc.HTTPClientError):
"""
subclass of :class:`~HTTPClientError`
This indicates that the server could not plug an attachment into a port
as the port is administratively down
code: 433, title: PortIsDown
"""
code = 433
title = 'Port is Down'
explanation = ('The specified logical port is administratively down')
class AlreadyAttached(webob.exc.HTTPClientError):
"""
subclass of :class:`~HTTPClientError`

View File

@ -39,7 +39,8 @@ class Controller(common.QuantumController):
"port": ["id", "state"],
"attachment": ["id"]
},
"plurals": {"networks": "network"}
"plurals": {"networks": "network",
"ports": "port"}
},
}

View File

@ -51,14 +51,23 @@ class Controller(common.QuantumController):
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)
# 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 ports]
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. """
@ -88,11 +97,11 @@ class Controller(common.QuantumController):
port_id = kwargs.get('id')
if port_id:
# show details for a given network
return self._item(request, tenant_id,
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,
return self._items(request, tenant_id,
network_id, port_details=True)
def create(self, request, tenant_id, network_id):

View File

@ -32,8 +32,8 @@ class ViewBuilder(object):
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:
if port_details:
port['port']['state'] = port_data['port-state']
if att_details and port_data['attachment-id']:
port['attachment'] = dict(id=port_data['attachment-id'])
port['port']['attachment'] = dict(id=port_data['attachment-id'])
return port

View File

@ -102,6 +102,12 @@ class PortInUse(QuantumException):
"is plugged into the logical port.")
class PortIsDown(QuantumException):
message = _("Unable to perform operation on port %(port_id)s " \
"for network %(net_id)s. The port is currently " \
"administratively down.")
class AlreadyAttached(QuantumException):
message = _("Unable to plug the attachment %(att_id)s into port " \
"%(port_id)s for network %(net_id)s. The attachment is " \

View File

@ -129,13 +129,13 @@ class Request(webob.Request):
format = parts[1]
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'

View File

@ -405,10 +405,13 @@ class FakePlugin(object):
specified Virtual Network.
"""
LOG.debug("FakePlugin.plug_interface() called")
port = self._get_port(tenant_id, net_id, port_id)
# Verify port state
if port['state'] == 'DOWN':
raise exc.PortIsDown(net_id=net_id, port_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'])

View File

@ -101,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
@ -117,6 +136,29 @@ 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,
@ -240,6 +282,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
@ -257,6 +320,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)
@ -580,6 +681,22 @@ class APITest(unittest.TestCase):
LOG.debug("_test_put_attachment_portnotfound - format:%s - END",
format)
def _test_put_attachment_portisdown(self, format):
LOG.debug("_test_put_attachment_portisdown - format:%s - START",
format)
port_state = "DOWN"
network_id = self._create_network(format)
interface_id = "test_interface"
port_id = self._create_port(network_id, port_state, format)
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, 433)
LOG.debug("_test_put_attachment_portisdown - format:%s - END", format)
def _test_delete_attachment(self, format):
LOG.debug("_test_delete_attachment - format:%s - START", format)
port_state = "ACTIVE"
@ -669,6 +786,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')
@ -693,6 +816,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')
@ -729,12 +858,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')
@ -855,6 +996,12 @@ class APITest(unittest.TestCase):
def test_put_attachment_portnotfound_json(self):
self._test_put_attachment_portnotfound('json')
def test_put_attachment_portisdown_xml(self):
self._test_put_attachment_portisdown('xml')
def test_put_attachment_portisdown_json(self):
self._test_put_attachment_portisdown('json')
def test_delete_attachment_xml(self):
self._test_delete_attachment('xml')

View File

@ -12,19 +12,38 @@ 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',
@ -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,