merge Salvatore's api branch with fixes for tests. Tweaking branch to remove unwanted bin/quantum.py as part of merge

This commit is contained in:
Dan Wendlandt 2011-07-29 16:39:45 -07:00
commit 840d4f1417
13 changed files with 112 additions and 72 deletions

View File

@ -52,6 +52,8 @@ class APIRouterV01(wsgi.Router):
uri_prefix = '/tenants/{tenant_id}/' uri_prefix = '/tenants/{tenant_id}/'
mapper.resource('network', 'networks', mapper.resource('network', 'networks',
controller=networks.Controller(plugin), controller=networks.Controller(plugin),
collection={'detail': 'GET'},
member={'detail': 'GET'},
path_prefix=uri_prefix) path_prefix=uri_prefix)
mapper.resource('port', 'ports', mapper.resource('port', 'ports',
controller=ports.Controller(plugin), controller=ports.Controller(plugin),

View File

@ -57,8 +57,7 @@ class QuantumController(wsgi.Controller):
pass pass
if not param_value and param['required']: if not param_value and param['required']:
msg = ("Failed to parse request. " + msg = ("Failed to parse request. " +
"Parameter: %(param_name)s " + "Parameter: " + param_name + " not specified")
"not specified" % locals())
for line in msg.split('\n'): for line in msg.split('\n'):
LOG.error(line) LOG.error(line)
raise exc.HTTPBadRequest(msg) raise exc.HTTPBadRequest(msg)

View File

@ -52,7 +52,7 @@ class Fault(webob.exc.HTTPException):
fault_name: { fault_name: {
'code': code, 'code': code,
'message': self.wrapped_exc.explanation, '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 # 'code' is an attribute on the fault tag itself
metadata = {'application/xml': {'attributes': {fault_name: 'code'}}} metadata = {'application/xml': {'attributes': {fault_name: 'code'}}}
default_xmlns = common.XML_NS_V10 default_xmlns = common.XML_NS_V10

View File

@ -36,7 +36,9 @@ class Controller(common.QuantumController):
"application/xml": { "application/xml": {
"attributes": { "attributes": {
"network": ["id", "name"], "network": ["id", "name"],
"port": ["id", "state"],
}, },
"plurals": {"networks": "network"}
}, },
} }
@ -47,19 +49,46 @@ class Controller(common.QuantumController):
def index(self, request, tenant_id): def index(self, request, tenant_id):
""" Returns a list of network ids """ """ Returns a list of network ids """
#TODO: this should be for a given tenant!!! #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. """ """ Returns a list of networks. """
networks = self._plugin.get_all_networks(tenant_id) networks = self._plugin.get_all_networks(tenant_id)
builder = networks_view.get_view_builder(request) builder = networks_view.get_view_builder(req)
result = [builder.build(network, is_detail)['network'] result = [builder.build(network, net_details, port_details)['network']
for network in networks] for network in networks]
return dict(networks=result) return dict(networks=result)
def show(self, request, tenant_id, id): def show(self, request, tenant_id, id):
""" Returns network details for the given network id """ """ Returns network details for the given network id """
try: 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( network = self._plugin.get_network_details(
tenant_id, id) tenant_id, id)
builder = networks_view.get_view_builder(request) builder = networks_view.get_view_builder(request)

View File

@ -40,7 +40,10 @@ class Controller(common.QuantumController):
_serialization_metadata = { _serialization_metadata = {
"application/xml": { "application/xml": {
"attributes": { "attributes": {
"port": ["id", "state"], }, }, } "port": ["id", "state"], },
"plurals": {"ports": "port"}
},
}
def __init__(self, plugin): def __init__(self, plugin):
self._resource_name = 'port' self._resource_name = 'port'
@ -68,8 +71,8 @@ class Controller(common.QuantumController):
tenant_id, network_id, id) tenant_id, network_id, id)
builder = ports_view.get_view_builder(request) builder = ports_view.get_view_builder(request)
#build response with details #build response with details
result = builder.build(port, True) result = builder.build(port, True)['port']
return dict(ports=result) return dict(port=result)
except exception.NetworkNotFound as e: except exception.NetworkNotFound as e:
return faults.Fault(faults.NetworkNotFound(e)) return faults.Fault(faults.NetworkNotFound(e))
except exception.PortNotFound as e: except exception.PortNotFound as e:
@ -105,7 +108,7 @@ class Controller(common.QuantumController):
return faults.Fault(e) return faults.Fault(e)
try: try:
port = self._plugin.update_port(tenant_id, network_id, id, 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) builder = ports_view.get_view_builder(request)
result = builder.build(port, True) result = builder.build(port, True)
return dict(ports=result) return dict(ports=result)
@ -122,7 +125,7 @@ class Controller(common.QuantumController):
try: try:
self._plugin.delete_port(tenant_id, network_id, id) self._plugin.delete_port(tenant_id, network_id, id)
return exc.HTTPAccepted() return exc.HTTPAccepted()
#TODO(salvatore-orlando): Handle portInUse error # TODO(salvatore-orlando): Handle portInUse error
except exception.NetworkNotFound as e: except exception.NetworkNotFound as e:
return faults.Fault(faults.NetworkNotFound(e)) return faults.Fault(faults.NetworkNotFound(e))
except exception.PortNotFound as e: except exception.PortNotFound as e:

View File

@ -13,4 +13,3 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# @author: Somik Behera, Nicira Networks, Inc.

View File

@ -15,7 +15,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import os from quantum.api.views import ports as ports_view
def get_view_builder(req): def get_view_builder(req):
@ -31,19 +31,34 @@ class ViewBuilder(object):
""" """
self.base_url = base_url 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.""" """Generic method used to generate a network entity."""
if is_detail: if net_detail:
network = self._build_detail(network_data) network = self._build_detail(network_data)
else: else:
network = self._build_simple(network_data) 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 return network
def _build_simple(self, network_data): 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'])) return dict(network=dict(id=network_data['net-id']))
def _build_detail(self, network_data): 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'], 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']))

View File

@ -38,10 +38,10 @@ class ViewBuilder(object):
return port return port
def _build_simple(self, port_data): 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'])) return dict(port=dict(id=port_data['port-id']))
def _build_detail(self, port_data): 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'], return dict(port=dict(id=port_data['port-id'],
state=port_data['port-state'])) state=port_data['port-state']))

View File

@ -20,17 +20,13 @@
Utility methods for working with WSGI servers Utility methods for working with WSGI servers
""" """
import json
import logging import logging
import sys import sys
import datetime
from xml.dom import minidom from xml.dom import minidom
import eventlet
import eventlet.wsgi import eventlet.wsgi
eventlet.patcher.monkey_patch(all=False, socket=True) eventlet.patcher.monkey_patch(all=False, socket=True)
import routes
import routes.middleware import routes.middleware
import webob.dec import webob.dec
import webob.exc import webob.exc
@ -135,7 +131,6 @@ class Request(webob.Request):
ctypes = ['application/json', 'application/xml'] ctypes = ['application/json', 'application/xml']
bm = self.accept.best_match(ctypes) bm = self.accept.best_match(ctypes)
LOG.debug("BM:%s", bm)
return bm or 'application/json' return bm or 'application/json'
def get_content_type(self): def get_content_type(self):
@ -332,7 +327,6 @@ class Controller(object):
""" """
Call the method specified in req.environ by RoutesMiddleware. Call the method specified in req.environ by RoutesMiddleware.
""" """
LOG.debug("HERE - wsgi.Controller.__call__")
arg_dict = req.environ['wsgiorg.routing_args'][1] arg_dict = req.environ['wsgiorg.routing_args'][1]
action = arg_dict['action'] action = arg_dict['action']
method = getattr(self, action) method = getattr(self, action)
@ -345,8 +339,6 @@ class Controller(object):
if type(result) is dict: if type(result) is dict:
content_type = req.best_match_content_type() 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) default_xmlns = self.get_default_xmlns(req)
body = self._serialize(result, content_type, default_xmlns) 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: if len(node.childNodes) == 1 and node.childNodes[0].nodeType == 3:
return node.childNodes[0].nodeValue return node.childNodes[0].nodeValue
elif node.nodeName in listnames: 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: else:
result = dict() result = dict()
for attr in node.attributes.keys(): for attr in node.attributes.keys():
@ -496,9 +489,7 @@ class Serializer(object):
xmlns = metadata.get('xmlns', None) xmlns = metadata.get('xmlns', None)
if xmlns: if xmlns:
result.setAttribute('xmlns', xmlns) result.setAttribute('xmlns', xmlns)
LOG.debug("DATA:%s", data)
if type(data) is list: if type(data) is list:
LOG.debug("TYPE IS LIST")
collections = metadata.get('list_collections', {}) collections = metadata.get('list_collections', {})
if nodename in collections: if nodename in collections:
metadata = collections[nodename] metadata = collections[nodename]
@ -517,7 +508,6 @@ class Serializer(object):
node = self._to_xml_node(doc, metadata, singular, item) node = self._to_xml_node(doc, metadata, singular, item)
result.appendChild(node) result.appendChild(node)
elif type(data) is dict: elif type(data) is dict:
LOG.debug("TYPE IS DICT")
collections = metadata.get('dict_collections', {}) collections = metadata.get('dict_collections', {})
if nodename in collections: if nodename in collections:
metadata = collections[nodename] metadata = collections[nodename]
@ -536,8 +526,7 @@ class Serializer(object):
node = self._to_xml_node(doc, metadata, k, v) node = self._to_xml_node(doc, metadata, k, v)
result.appendChild(node) result.appendChild(node)
else: else:
# Type is atom # Type is atom.
LOG.debug("TYPE IS ATOM:%s", data)
node = doc.createTextNode(str(data)) node = doc.createTextNode(str(data))
result.appendChild(node) result.appendChild(node)
return result return result

View File

@ -21,7 +21,6 @@
Quantum's Manager class is responsible for parsing a config file and Quantum's Manager class is responsible for parsing a config file and
instantiating the correct plugin that concretely implement quantum_plugin_base instantiating the correct plugin that concretely implement quantum_plugin_base
class. class.
The caller should make sure that QuantumManager is a singleton. The caller should make sure that QuantumManager is a singleton.
""" """
import gettext import gettext

View File

@ -159,7 +159,6 @@ class DummyDataPlugin(object):
retrieved a list of all the remote vifs that retrieved a list of all the remote vifs that
are attached to the network are attached to the network
""" """
print("get_network_details() called\n")
vifs_on_net = ["/tenant1/networks/net_id/portid/vif2.0"] vifs_on_net = ["/tenant1/networks/net_id/portid/vif2.0"]
return vifs_on_net return vifs_on_net
@ -187,12 +186,6 @@ class DummyDataPlugin(object):
#return the port id #return the port id
return 201 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): def delete_port(self, tenant_id, net_id, port_id):
""" """
Deletes a port on a specified Virtual Network, Deletes a port on a specified Virtual Network,
@ -290,8 +283,11 @@ class FakePlugin(object):
""" """
LOG.debug("FakePlugin.get_network_details() called") LOG.debug("FakePlugin.get_network_details() called")
net = self._get_network(tenant_id, net_id) 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), 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): def create_network(self, tenant_id, net_name):
""" """

View File

@ -84,10 +84,10 @@ $ python ovs_quantum_agent.py ovs_quantum_plugin.ini
# -- Getting quantum up and running # -- Getting quantum up and running
- Start quantum [on the quantum service host]: - 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 - Run ovs_quantum_plugin.py via the quantum plugin framework cli [on the
quantum service host] 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. This will show help all of the available commands.

View File

@ -75,7 +75,7 @@ class APITest(unittest.TestCase):
network_data = Serializer().deserialize(show_network_res.body, network_data = Serializer().deserialize(show_network_res.body,
content_type) content_type)
self.assertEqual(network_id, self.assertEqual(network_id,
network_data['networks']['network']['id']) network_data['network']['id'])
LOG.debug("_test_create_network - format:%s - END", format) LOG.debug("_test_create_network - format:%s - END", format)
def _test_create_network_badrequest(self, format): def _test_create_network_badrequest(self, format):
@ -96,8 +96,8 @@ class APITest(unittest.TestCase):
format) format)
list_network_res = list_network_req.get_response(self.api) list_network_res = list_network_req.get_response(self.api)
self.assertEqual(list_network_res.status_int, 200) self.assertEqual(list_network_res.status_int, 200)
network_data = Serializer().deserialize(list_network_res.body, network_data = self._net_serializer.deserialize(
content_type) list_network_res.body, content_type)
# Check network count: should return 2 # Check network count: should return 2
self.assertEqual(len(network_data['networks']), 2) self.assertEqual(len(network_data['networks']), 2)
LOG.debug("_test_list_networks - format:%s - END", format) LOG.debug("_test_list_networks - format:%s - END", format)
@ -111,10 +111,12 @@ class APITest(unittest.TestCase):
format) format)
show_network_res = show_network_req.get_response(self.api) show_network_res = show_network_req.get_response(self.api)
self.assertEqual(show_network_res.status_int, 200) self.assertEqual(show_network_res.status_int, 200)
network_data = Serializer().deserialize(show_network_res.body, network_data = self._net_serializer.deserialize(
content_type) show_network_res.body, content_type)
self.assertEqual({'id': network_id, 'name': self.network_name}, self.assertEqual({'id': network_id,
network_data['networks']['network']) 'name': self.network_name,
'PortCount': 0},
network_data['network'])
LOG.debug("_test_show_network - format:%s - END", format) LOG.debug("_test_show_network - format:%s - END", format)
def _test_show_network_not_found(self, format): def _test_show_network_not_found(self, format):
@ -142,10 +144,12 @@ class APITest(unittest.TestCase):
format) format)
show_network_res = show_network_req.get_response(self.api) show_network_res = show_network_req.get_response(self.api)
self.assertEqual(show_network_res.status_int, 200) self.assertEqual(show_network_res.status_int, 200)
network_data = Serializer().deserialize(show_network_res.body, network_data = self._net_serializer.deserialize(
content_type) show_network_res.body, content_type)
self.assertEqual({'id': network_id, 'name': new_name}, self.assertEqual({'id': network_id,
network_data['networks']['network']) 'name': new_name,
'PortCount': 0},
network_data['network'])
LOG.debug("_test_rename_network - format:%s - END", format) LOG.debug("_test_rename_network - format:%s - END", format)
def _test_rename_network_badrequest(self, 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, list_network_req = testlib.network_list_request(self.tenant_id,
format) format)
list_network_res = list_network_req.get_response(self.api) list_network_res = list_network_req.get_response(self.api)
network_list_data = Serializer().deserialize(list_network_res.body, network_list_data = self._net_serializer.deserialize(
content_type) list_network_res.body, content_type)
network_count = len(network_list_data['networks']) network_count = len(network_list_data['networks'])
self.assertEqual(network_count, 0) self.assertEqual(network_count, 0)
LOG.debug("_test_delete_network - format:%s - END", format) LOG.debug("_test_delete_network - format:%s - END", format)
@ -233,8 +237,8 @@ class APITest(unittest.TestCase):
network_id, format) network_id, format)
list_port_res = list_port_req.get_response(self.api) list_port_res = list_port_req.get_response(self.api)
self.assertEqual(list_port_res.status_int, 200) self.assertEqual(list_port_res.status_int, 200)
port_data = Serializer().deserialize(list_port_res.body, port_data = self._port_serializer.deserialize(
content_type) list_port_res.body, content_type)
# Check port count: should return 2 # Check port count: should return 2
self.assertEqual(len(port_data['ports']), 2) self.assertEqual(len(port_data['ports']), 2)
LOG.debug("_test_list_ports - format:%s - END", format) LOG.debug("_test_list_ports - format:%s - END", format)
@ -250,10 +254,10 @@ class APITest(unittest.TestCase):
format) format)
show_port_res = show_port_req.get_response(self.api) show_port_res = show_port_req.get_response(self.api)
self.assertEqual(show_port_res.status_int, 200) self.assertEqual(show_port_res.status_int, 200)
port_data = Serializer().deserialize(show_port_res.body, port_data = self._port_serializer.deserialize(
content_type) show_port_res.body, content_type)
self.assertEqual({'id': port_id, 'state': port_state}, self.assertEqual({'id': port_id, 'state': port_state},
port_data['ports']['port']) port_data['port'])
LOG.debug("_test_show_port - format:%s - END", format) LOG.debug("_test_show_port - format:%s - END", format)
def _test_show_port_networknotfound(self, format): def _test_show_port_networknotfound(self, format):
@ -291,8 +295,9 @@ class APITest(unittest.TestCase):
network_id, port_id, format) network_id, port_id, format)
show_port_res = show_port_req.get_response(self.api) show_port_res = show_port_req.get_response(self.api)
self.assertEqual(show_port_res.status_int, 200) self.assertEqual(show_port_res.status_int, 200)
port_data = Serializer().deserialize(show_port_res.body, content_type) port_data = self._port_serializer.deserialize(
self.assertEqual(port_id, port_data['ports']['port']['id']) show_port_res.body, content_type)
self.assertEqual(port_id, port_data['port']['id'])
LOG.debug("_test_create_port - format:%s - END", format) LOG.debug("_test_create_port - format:%s - END", format)
def _test_create_port_networknotfound(self, 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, list_port_req = testlib.port_list_request(self.tenant_id, network_id,
format) format)
list_port_res = list_port_req.get_response(self.api) list_port_res = list_port_req.get_response(self.api)
port_list_data = Serializer().deserialize(list_port_res.body, port_list_data = self._port_serializer.deserialize(
content_type) list_port_res.body, content_type)
port_count = len(port_list_data['ports']) port_count = len(port_list_data['ports'])
self.assertEqual(port_count, 0) self.assertEqual(port_count, 0)
LOG.debug("_test_delete_port - format:%s - END", format) LOG.debug("_test_delete_port - format:%s - END", format)
@ -405,10 +410,10 @@ class APITest(unittest.TestCase):
format) format)
show_port_res = show_port_req.get_response(self.api) show_port_res = show_port_req.get_response(self.api)
self.assertEqual(show_port_res.status_int, 200) self.assertEqual(show_port_res.status_int, 200)
network_data = Serializer().deserialize(show_port_res.body, port_data = self._port_serializer.deserialize(
content_type) show_port_res.body, content_type)
self.assertEqual({'id': port_id, 'state': new_port_state}, 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) LOG.debug("_test_set_port_state - format:%s - END", format)
def _test_set_port_state_networknotfound(self, format): def _test_set_port_state_networknotfound(self, format):
@ -636,6 +641,10 @@ class APITest(unittest.TestCase):
self.api = server.APIRouterV01(options) self.api = server.APIRouterV01(options)
self.tenant_id = "test_tenant" self.tenant_id = "test_tenant"
self.network_name = "test_network" 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): def tearDown(self):
"""Clear the test environment""" """Clear the test environment"""