Merging lp:quantum updates
This commit is contained in:
commit
60abf6ee8f
@ -52,6 +52,8 @@ class APIRouterV01(wsgi.Router):
|
||||
uri_prefix = '/tenants/{tenant_id}/'
|
||||
mapper.resource('network', 'networks',
|
||||
controller=networks.Controller(plugin),
|
||||
collection={'detail': 'GET'},
|
||||
member={'detail': 'GET'},
|
||||
path_prefix=uri_prefix)
|
||||
mapper.resource('port', 'ports',
|
||||
controller=ports.Controller(plugin),
|
||||
|
@ -57,8 +57,7 @@ class QuantumController(wsgi.Controller):
|
||||
pass
|
||||
if not param_value and param['required']:
|
||||
msg = ("Failed to parse request. " +
|
||||
"Parameter: %(param_name)s " +
|
||||
"not specified" % locals())
|
||||
"Parameter: " + param_name + " not specified")
|
||||
for line in msg.split('\n'):
|
||||
LOG.error(line)
|
||||
raise exc.HTTPBadRequest(msg)
|
||||
|
@ -52,7 +52,7 @@ class Fault(webob.exc.HTTPException):
|
||||
fault_name: {
|
||||
'code': code,
|
||||
'message': self.wrapped_exc.explanation,
|
||||
'detail': self.wrapped_exc.detail}}
|
||||
'detail': str(self.wrapped_exc.detail)}}
|
||||
# 'code' is an attribute on the fault tag itself
|
||||
metadata = {'application/xml': {'attributes': {fault_name: 'code'}}}
|
||||
default_xmlns = common.XML_NS_V10
|
||||
|
@ -36,7 +36,9 @@ class Controller(common.QuantumController):
|
||||
"application/xml": {
|
||||
"attributes": {
|
||||
"network": ["id", "name"],
|
||||
"port": ["id", "state"],
|
||||
},
|
||||
"plurals": {"networks": "network"}
|
||||
},
|
||||
}
|
||||
|
||||
@ -47,19 +49,46 @@ class Controller(common.QuantumController):
|
||||
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, is_detail=False)
|
||||
return self._items(request, tenant_id)
|
||||
|
||||
def _items(self, request, tenant_id, is_detail):
|
||||
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)
|
||||
builder = networks_view.get_view_builder(req)
|
||||
result = builder.build(network, net_details, port_details)['network']
|
||||
return dict(network=result)
|
||||
|
||||
def _items(self, req, tenant_id, net_details=False, port_details=False):
|
||||
""" Returns a list of networks. """
|
||||
networks = self._plugin.get_all_networks(tenant_id)
|
||||
builder = networks_view.get_view_builder(request)
|
||||
result = [builder.build(network, is_detail)['network']
|
||||
builder = networks_view.get_view_builder(req)
|
||||
result = [builder.build(network, net_details, port_details)['network']
|
||||
for network in networks]
|
||||
return dict(networks=result)
|
||||
|
||||
def show(self, request, tenant_id, id):
|
||||
""" Returns network details for the given network id """
|
||||
try:
|
||||
return self._item(request, tenant_id, id,
|
||||
net_details=True, port_details=False)
|
||||
except exception.NetworkNotFound as e:
|
||||
return faults.Fault(faults.NetworkNotFound(e))
|
||||
|
||||
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)
|
||||
|
@ -40,7 +40,10 @@ class Controller(common.QuantumController):
|
||||
_serialization_metadata = {
|
||||
"application/xml": {
|
||||
"attributes": {
|
||||
"port": ["id", "state"], }, }, }
|
||||
"port": ["id", "state"], },
|
||||
"plurals": {"ports": "port"}
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(self, plugin):
|
||||
self._resource_name = 'port'
|
||||
@ -68,8 +71,8 @@ class Controller(common.QuantumController):
|
||||
tenant_id, network_id, id)
|
||||
builder = ports_view.get_view_builder(request)
|
||||
#build response with details
|
||||
result = builder.build(port, True)
|
||||
return dict(ports=result)
|
||||
result = builder.build(port, True)['port']
|
||||
return dict(port=result)
|
||||
except exception.NetworkNotFound as e:
|
||||
return faults.Fault(faults.NetworkNotFound(e))
|
||||
except exception.PortNotFound as e:
|
||||
@ -105,7 +108,7 @@ class Controller(common.QuantumController):
|
||||
return faults.Fault(e)
|
||||
try:
|
||||
port = self._plugin.update_port(tenant_id, network_id, id,
|
||||
request_params['port-state'])
|
||||
request_params['port-state'])
|
||||
builder = ports_view.get_view_builder(request)
|
||||
result = builder.build(port, True)
|
||||
return dict(ports=result)
|
||||
@ -122,7 +125,7 @@ class Controller(common.QuantumController):
|
||||
try:
|
||||
self._plugin.delete_port(tenant_id, network_id, id)
|
||||
return exc.HTTPAccepted()
|
||||
#TODO(salvatore-orlando): Handle portInUse error
|
||||
# TODO(salvatore-orlando): Handle portInUse error
|
||||
except exception.NetworkNotFound as e:
|
||||
return faults.Fault(faults.NetworkNotFound(e))
|
||||
except exception.PortNotFound as e:
|
||||
|
@ -13,4 +13,3 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# @author: Somik Behera, Nicira Networks, Inc.
|
||||
|
@ -15,7 +15,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
from quantum.api.views import ports as ports_view
|
||||
|
||||
|
||||
def get_view_builder(req):
|
||||
@ -31,19 +31,34 @@ class ViewBuilder(object):
|
||||
"""
|
||||
self.base_url = base_url
|
||||
|
||||
def build(self, network_data, is_detail=False):
|
||||
def build(self, network_data, net_detail=False, port_detail=False):
|
||||
"""Generic method used to generate a network entity."""
|
||||
if is_detail:
|
||||
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
|
||||
return network
|
||||
|
||||
def _build_simple(self, network_data):
|
||||
"""Return a simple model of a server."""
|
||||
"""Return a simple model of a network."""
|
||||
return dict(network=dict(id=network_data['net-id']))
|
||||
|
||||
def _build_detail(self, network_data):
|
||||
"""Return a simple model of a server."""
|
||||
"""Return a detailed model of a network."""
|
||||
# net-ports might not be present in response from plugin
|
||||
ports = network_data.get('net-ports', None)
|
||||
portcount = ports and len(ports) or 0
|
||||
return dict(network=dict(id=network_data['net-id'],
|
||||
name=network_data['net-name']))
|
||||
name=network_data['net-name'],
|
||||
PortCount=portcount))
|
||||
|
||||
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']))
|
||||
|
@ -38,10 +38,10 @@ class ViewBuilder(object):
|
||||
return port
|
||||
|
||||
def _build_simple(self, port_data):
|
||||
"""Return a simple model of a server."""
|
||||
"""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 server."""
|
||||
"""Return a simple model of a port (with its state)."""
|
||||
return dict(port=dict(id=port_data['port-id'],
|
||||
state=port_data['port-state']))
|
||||
state=port_data['port-state']))
|
||||
|
@ -20,17 +20,13 @@
|
||||
Utility methods for working with WSGI servers
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
import datetime
|
||||
|
||||
from xml.dom import minidom
|
||||
|
||||
import eventlet
|
||||
import eventlet.wsgi
|
||||
eventlet.patcher.monkey_patch(all=False, socket=True)
|
||||
import routes
|
||||
import routes.middleware
|
||||
import webob.dec
|
||||
import webob.exc
|
||||
@ -135,7 +131,6 @@ class Request(webob.Request):
|
||||
|
||||
ctypes = ['application/json', 'application/xml']
|
||||
bm = self.accept.best_match(ctypes)
|
||||
LOG.debug("BM:%s", bm)
|
||||
return bm or 'application/json'
|
||||
|
||||
def get_content_type(self):
|
||||
@ -332,7 +327,6 @@ class Controller(object):
|
||||
"""
|
||||
Call the method specified in req.environ by RoutesMiddleware.
|
||||
"""
|
||||
LOG.debug("HERE - wsgi.Controller.__call__")
|
||||
arg_dict = req.environ['wsgiorg.routing_args'][1]
|
||||
action = arg_dict['action']
|
||||
method = getattr(self, action)
|
||||
@ -345,8 +339,6 @@ class Controller(object):
|
||||
|
||||
if type(result) is dict:
|
||||
content_type = req.best_match_content_type()
|
||||
LOG.debug("Content type:%s", content_type)
|
||||
LOG.debug("Result:%s", result)
|
||||
default_xmlns = self.get_default_xmlns(req)
|
||||
body = self._serialize(result, content_type, default_xmlns)
|
||||
|
||||
@ -460,7 +452,8 @@ class Serializer(object):
|
||||
if len(node.childNodes) == 1 and node.childNodes[0].nodeType == 3:
|
||||
return node.childNodes[0].nodeValue
|
||||
elif node.nodeName in listnames:
|
||||
return [self._from_xml_node(n, listnames) for n in node.childNodes]
|
||||
return [self._from_xml_node(n, listnames)
|
||||
for n in node.childNodes if n.nodeType != node.TEXT_NODE]
|
||||
else:
|
||||
result = dict()
|
||||
for attr in node.attributes.keys():
|
||||
@ -496,9 +489,7 @@ class Serializer(object):
|
||||
xmlns = metadata.get('xmlns', None)
|
||||
if xmlns:
|
||||
result.setAttribute('xmlns', xmlns)
|
||||
LOG.debug("DATA:%s", data)
|
||||
if type(data) is list:
|
||||
LOG.debug("TYPE IS LIST")
|
||||
collections = metadata.get('list_collections', {})
|
||||
if nodename in collections:
|
||||
metadata = collections[nodename]
|
||||
@ -517,7 +508,6 @@ class Serializer(object):
|
||||
node = self._to_xml_node(doc, metadata, singular, item)
|
||||
result.appendChild(node)
|
||||
elif type(data) is dict:
|
||||
LOG.debug("TYPE IS DICT")
|
||||
collections = metadata.get('dict_collections', {})
|
||||
if nodename in collections:
|
||||
metadata = collections[nodename]
|
||||
@ -536,8 +526,7 @@ class Serializer(object):
|
||||
node = self._to_xml_node(doc, metadata, k, v)
|
||||
result.appendChild(node)
|
||||
else:
|
||||
# Type is atom
|
||||
LOG.debug("TYPE IS ATOM:%s", data)
|
||||
# Type is atom.
|
||||
node = doc.createTextNode(str(data))
|
||||
result.appendChild(node)
|
||||
return result
|
||||
|
@ -21,7 +21,6 @@
|
||||
Quantum's Manager class is responsible for parsing a config file and
|
||||
instantiating the correct plugin that concretely implement quantum_plugin_base
|
||||
class.
|
||||
|
||||
The caller should make sure that QuantumManager is a singleton.
|
||||
"""
|
||||
import gettext
|
||||
|
@ -159,7 +159,6 @@ class DummyDataPlugin(object):
|
||||
retrieved a list of all the remote vifs that
|
||||
are attached to the network
|
||||
"""
|
||||
print("get_network_details() called\n")
|
||||
vifs_on_net = ["/tenant1/networks/net_id/portid/vif2.0"]
|
||||
return vifs_on_net
|
||||
|
||||
@ -187,12 +186,6 @@ class DummyDataPlugin(object):
|
||||
#return the port id
|
||||
return 201
|
||||
|
||||
def update_port(self, tenant_id, net_id, port_id, port_state):
|
||||
"""
|
||||
Updates the state of a port on the specified Virtual Network.
|
||||
"""
|
||||
print("update_port() called\n")
|
||||
|
||||
def delete_port(self, tenant_id, net_id, port_id):
|
||||
"""
|
||||
Deletes a port on a specified Virtual Network,
|
||||
@ -290,8 +283,11 @@ class FakePlugin(object):
|
||||
"""
|
||||
LOG.debug("FakePlugin.get_network_details() called")
|
||||
net = self._get_network(tenant_id, net_id)
|
||||
# Retrieves ports for network
|
||||
ports = self.get_all_ports(tenant_id, net_id)
|
||||
return {'net-id': str(net.uuid),
|
||||
'net-name': net.name}
|
||||
'net-name': net.name,
|
||||
'net-ports': ports}
|
||||
|
||||
def create_network(self, tenant_id, net_name):
|
||||
"""
|
||||
|
@ -84,10 +84,10 @@ $ python ovs_quantum_agent.py ovs_quantum_plugin.ini
|
||||
# -- Getting quantum up and running
|
||||
|
||||
- Start quantum [on the quantum service host]:
|
||||
~/src/quantum-framework$ PYTHONPATH=.:$PYTHONPATH python bin/quantum etc/quantum.conf
|
||||
~/src/quantum $ PYTHONPATH=.:$PYTHONPATH python bin/quantum etc/quantum.conf
|
||||
- Run ovs_quantum_plugin.py via the quantum plugin framework cli [on the
|
||||
quantum service host]
|
||||
~/src/quantum-framework$ PYTHONPATH=.:$PYTHONPATH python quantum/cli.py
|
||||
~/src/quantum$ PYTHONPATH=.:$PYTHONPATH python quantum/cli.py
|
||||
|
||||
This will show help all of the available commands.
|
||||
|
||||
|
@ -75,7 +75,7 @@ class APITest(unittest.TestCase):
|
||||
network_data = Serializer().deserialize(show_network_res.body,
|
||||
content_type)
|
||||
self.assertEqual(network_id,
|
||||
network_data['networks']['network']['id'])
|
||||
network_data['network']['id'])
|
||||
LOG.debug("_test_create_network - format:%s - END", format)
|
||||
|
||||
def _test_create_network_badrequest(self, format):
|
||||
@ -96,8 +96,8 @@ class APITest(unittest.TestCase):
|
||||
format)
|
||||
list_network_res = list_network_req.get_response(self.api)
|
||||
self.assertEqual(list_network_res.status_int, 200)
|
||||
network_data = Serializer().deserialize(list_network_res.body,
|
||||
content_type)
|
||||
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)
|
||||
LOG.debug("_test_list_networks - format:%s - END", format)
|
||||
@ -111,10 +111,12 @@ class APITest(unittest.TestCase):
|
||||
format)
|
||||
show_network_res = show_network_req.get_response(self.api)
|
||||
self.assertEqual(show_network_res.status_int, 200)
|
||||
network_data = Serializer().deserialize(show_network_res.body,
|
||||
content_type)
|
||||
self.assertEqual({'id': network_id, 'name': self.network_name},
|
||||
network_data['networks']['network'])
|
||||
network_data = self._net_serializer.deserialize(
|
||||
show_network_res.body, content_type)
|
||||
self.assertEqual({'id': network_id,
|
||||
'name': self.network_name,
|
||||
'PortCount': 0},
|
||||
network_data['network'])
|
||||
LOG.debug("_test_show_network - format:%s - END", format)
|
||||
|
||||
def _test_show_network_not_found(self, format):
|
||||
@ -142,10 +144,12 @@ class APITest(unittest.TestCase):
|
||||
format)
|
||||
show_network_res = show_network_req.get_response(self.api)
|
||||
self.assertEqual(show_network_res.status_int, 200)
|
||||
network_data = Serializer().deserialize(show_network_res.body,
|
||||
content_type)
|
||||
self.assertEqual({'id': network_id, 'name': new_name},
|
||||
network_data['networks']['network'])
|
||||
network_data = self._net_serializer.deserialize(
|
||||
show_network_res.body, content_type)
|
||||
self.assertEqual({'id': network_id,
|
||||
'name': new_name,
|
||||
'PortCount': 0},
|
||||
network_data['network'])
|
||||
LOG.debug("_test_rename_network - format:%s - END", format)
|
||||
|
||||
def _test_rename_network_badrequest(self, format):
|
||||
@ -189,8 +193,8 @@ class APITest(unittest.TestCase):
|
||||
list_network_req = testlib.network_list_request(self.tenant_id,
|
||||
format)
|
||||
list_network_res = list_network_req.get_response(self.api)
|
||||
network_list_data = Serializer().deserialize(list_network_res.body,
|
||||
content_type)
|
||||
network_list_data = self._net_serializer.deserialize(
|
||||
list_network_res.body, content_type)
|
||||
network_count = len(network_list_data['networks'])
|
||||
self.assertEqual(network_count, 0)
|
||||
LOG.debug("_test_delete_network - format:%s - END", format)
|
||||
@ -233,8 +237,8 @@ class APITest(unittest.TestCase):
|
||||
network_id, format)
|
||||
list_port_res = list_port_req.get_response(self.api)
|
||||
self.assertEqual(list_port_res.status_int, 200)
|
||||
port_data = Serializer().deserialize(list_port_res.body,
|
||||
content_type)
|
||||
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)
|
||||
LOG.debug("_test_list_ports - format:%s - END", format)
|
||||
@ -250,10 +254,10 @@ class APITest(unittest.TestCase):
|
||||
format)
|
||||
show_port_res = show_port_req.get_response(self.api)
|
||||
self.assertEqual(show_port_res.status_int, 200)
|
||||
port_data = Serializer().deserialize(show_port_res.body,
|
||||
content_type)
|
||||
port_data = self._port_serializer.deserialize(
|
||||
show_port_res.body, content_type)
|
||||
self.assertEqual({'id': port_id, 'state': port_state},
|
||||
port_data['ports']['port'])
|
||||
port_data['port'])
|
||||
LOG.debug("_test_show_port - format:%s - END", format)
|
||||
|
||||
def _test_show_port_networknotfound(self, format):
|
||||
@ -291,8 +295,9 @@ class APITest(unittest.TestCase):
|
||||
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 = Serializer().deserialize(show_port_res.body, content_type)
|
||||
self.assertEqual(port_id, port_data['ports']['port']['id'])
|
||||
port_data = self._port_serializer.deserialize(
|
||||
show_port_res.body, content_type)
|
||||
self.assertEqual(port_id, port_data['port']['id'])
|
||||
LOG.debug("_test_create_port - format:%s - END", format)
|
||||
|
||||
def _test_create_port_networknotfound(self, format):
|
||||
@ -329,8 +334,8 @@ class APITest(unittest.TestCase):
|
||||
list_port_req = testlib.port_list_request(self.tenant_id, network_id,
|
||||
format)
|
||||
list_port_res = list_port_req.get_response(self.api)
|
||||
port_list_data = Serializer().deserialize(list_port_res.body,
|
||||
content_type)
|
||||
port_list_data = self._port_serializer.deserialize(
|
||||
list_port_res.body, content_type)
|
||||
port_count = len(port_list_data['ports'])
|
||||
self.assertEqual(port_count, 0)
|
||||
LOG.debug("_test_delete_port - format:%s - END", format)
|
||||
@ -405,10 +410,10 @@ class APITest(unittest.TestCase):
|
||||
format)
|
||||
show_port_res = show_port_req.get_response(self.api)
|
||||
self.assertEqual(show_port_res.status_int, 200)
|
||||
network_data = Serializer().deserialize(show_port_res.body,
|
||||
content_type)
|
||||
port_data = self._port_serializer.deserialize(
|
||||
show_port_res.body, content_type)
|
||||
self.assertEqual({'id': port_id, 'state': new_port_state},
|
||||
network_data['ports']['port'])
|
||||
port_data['port'])
|
||||
LOG.debug("_test_set_port_state - format:%s - END", format)
|
||||
|
||||
def _test_set_port_state_networknotfound(self, format):
|
||||
@ -636,6 +641,10 @@ class APITest(unittest.TestCase):
|
||||
self.api = server.APIRouterV01(options)
|
||||
self.tenant_id = "test_tenant"
|
||||
self.network_name = "test_network"
|
||||
self._net_serializer = \
|
||||
Serializer(server.networks.Controller._serialization_metadata)
|
||||
self._port_serializer = \
|
||||
Serializer(server.ports.Controller._serialization_metadata)
|
||||
|
||||
def tearDown(self):
|
||||
"""Clear the test environment"""
|
||||
|
@ -84,7 +84,7 @@ def delete_all_nets(client, tenant_id):
|
||||
|
||||
|
||||
def create_net_with_attachments(net_name, iface_ids):
|
||||
data = {'network': {'network-name': '%s' % net_name}}
|
||||
data = {'network': {'net-name': '%s' % net_name}}
|
||||
body = Serializer().serialize(data, CONTENT_TYPE)
|
||||
res = client.do_request(tenant_id, 'POST',
|
||||
"/networks." + FORMAT, body=body)
|
||||
|
Loading…
Reference in New Issue
Block a user