neutron/quantum/tests/unit/nicira/test_networkgw.py

524 lines
24 KiB
Python

#
# Copyright 2012 Nicira Networks, Inc. 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 contextlib
import mock
import testtools
from webob import exc
import webtest
from quantum.api import extensions
from quantum.api.extensions import PluginAwareExtensionManager
from quantum.common import config
from quantum.common.test_lib import test_config
from quantum import context
from quantum.db import api as db_api
from quantum.db import db_base_plugin_v2
from quantum import manager
from quantum.openstack.common import cfg
from quantum.plugins.nicira.nicira_nvp_plugin.extensions import (nvp_networkgw
as networkgw)
from quantum.plugins.nicira.nicira_nvp_plugin import nicira_networkgw_db
from quantum.tests.unit import test_api_v2
from quantum.tests.unit import test_db_plugin
from quantum.tests.unit import test_extensions
_uuid = test_api_v2._uuid
_get_path = test_api_v2._get_path
class TestExtensionManager(object):
def get_resources(self):
return networkgw.Nvp_networkgw.get_resources()
def get_actions(self):
return []
def get_request_extensions(self):
return []
class NetworkGatewayExtensionTestCase(testtools.TestCase):
def setUp(self):
super(NetworkGatewayExtensionTestCase, self).setUp()
plugin = '%s.%s' % (networkgw.__name__,
networkgw.NetworkGatewayPluginBase.__name__)
self._resource = networkgw.RESOURCE_NAME.replace('-', '_')
# Ensure 'stale' patched copies of the plugin are never returned
manager.QuantumManager._instance = None
# Ensure existing ExtensionManager is not used
extensions.PluginAwareExtensionManager._instance = None
# Create the default configurations
args = ['--config-file', test_api_v2.etcdir('quantum.conf.test')]
config.parse(args=args)
# Update the plugin and extensions path
cfg.CONF.set_override('core_plugin', plugin)
self.addCleanup(cfg.CONF.reset)
_plugin_patcher = mock.patch(plugin, autospec=True)
self.plugin = _plugin_patcher.start()
self.addCleanup(_plugin_patcher.stop)
# Instantiate mock plugin and enable extensions
manager.QuantumManager.get_plugin().supported_extension_aliases = (
[networkgw.EXT_ALIAS])
ext_mgr = TestExtensionManager()
PluginAwareExtensionManager._instance = ext_mgr
self.ext_mdw = test_extensions.setup_extensions_middleware(ext_mgr)
self.api = webtest.TestApp(self.ext_mdw)
def test_network_gateway_create(self):
nw_gw_id = _uuid()
data = {self._resource: {'name': 'nw-gw',
'tenant_id': _uuid(),
'devices': [{'id': _uuid(),
'interface_name': 'xxx'}]}}
return_value = data[self._resource].copy()
return_value.update({'id': nw_gw_id})
instance = self.plugin.return_value
instance.create_network_gateway.return_value = return_value
res = self.api.post_json(_get_path(networkgw.COLLECTION_NAME), data)
instance.create_network_gateway.assert_called_with(
mock.ANY, network_gateway=data)
self.assertEqual(res.status_int, exc.HTTPCreated.code)
self.assertTrue(self._resource in res.json)
nw_gw = res.json[self._resource]
self.assertEqual(nw_gw['id'], nw_gw_id)
def test_network_gateway_update(self):
nw_gw_name = 'updated'
data = {self._resource: {'name': nw_gw_name}}
nw_gw_id = _uuid()
return_value = {'id': nw_gw_id,
'name': nw_gw_name}
instance = self.plugin.return_value
instance.update_network_gateway.return_value = return_value
res = self.api.put_json(_get_path('%s/%s' % (networkgw.COLLECTION_NAME,
nw_gw_id)),
data)
instance.update_network_gateway.assert_called_with(
mock.ANY, nw_gw_id, network_gateway=data)
self.assertEqual(res.status_int, exc.HTTPOk.code)
self.assertTrue(self._resource in res.json)
nw_gw = res.json[self._resource]
self.assertEqual(nw_gw['id'], nw_gw_id)
self.assertEqual(nw_gw['name'], nw_gw_name)
def test_network_gateway_delete(self):
nw_gw_id = _uuid()
instance = self.plugin.return_value
res = self.api.delete(_get_path('%s/%s' % (networkgw.COLLECTION_NAME,
nw_gw_id)))
instance.delete_network_gateway.assert_called_with(mock.ANY,
nw_gw_id)
self.assertEqual(res.status_int, exc.HTTPNoContent.code)
def test_network_gateway_get(self):
nw_gw_id = _uuid()
return_value = {self._resource: {'name': 'test',
'devices':
[{'id': _uuid(),
'interface_name': 'xxx'}],
'id': nw_gw_id}}
instance = self.plugin.return_value
instance.get_network_gateway.return_value = return_value
res = self.api.get(_get_path('%s/%s' % (networkgw.COLLECTION_NAME,
nw_gw_id)))
instance.get_network_gateway.assert_called_with(mock.ANY,
nw_gw_id,
fields=mock.ANY)
self.assertEqual(res.status_int, exc.HTTPOk.code)
def test_network_gateway_list(self):
nw_gw_id = _uuid()
return_value = [{self._resource: {'name': 'test',
'devices':
[{'id': _uuid(),
'interface_name': 'xxx'}],
'id': nw_gw_id}}]
instance = self.plugin.return_value
instance.get_network_gateways.return_value = return_value
res = self.api.get(_get_path(networkgw.COLLECTION_NAME))
instance.get_network_gateways.assert_called_with(mock.ANY,
fields=mock.ANY,
filters=mock.ANY)
self.assertEqual(res.status_int, exc.HTTPOk.code)
def test_network_gateway_connect(self):
nw_gw_id = _uuid()
nw_id = _uuid()
gw_port_id = _uuid()
mapping_data = {'network_id': nw_id,
'segmentation_type': 'vlan',
'segmentation_id': '999'}
return_value = {'connection_info': {
'network_gateway_id': nw_gw_id,
'port_id': gw_port_id,
'network_id': nw_id}}
instance = self.plugin.return_value
instance.connect_network.return_value = return_value
res = self.api.put_json(_get_path('%s/%s/connect_network' %
(networkgw.COLLECTION_NAME,
nw_gw_id)),
mapping_data)
instance.connect_network.assert_called_with(mock.ANY,
nw_gw_id,
mapping_data)
self.assertEqual(res.status_int, exc.HTTPOk.code)
nw_conn_res = res.json['connection_info']
self.assertEqual(nw_conn_res['port_id'], gw_port_id)
self.assertEqual(nw_conn_res['network_id'], nw_id)
def test_network_gateway_disconnect(self):
nw_gw_id = _uuid()
nw_id = _uuid()
mapping_data = {'network_id': nw_id}
instance = self.plugin.return_value
res = self.api.put_json(_get_path('%s/%s/disconnect_network' %
(networkgw.COLLECTION_NAME,
nw_gw_id)),
mapping_data)
instance.disconnect_network.assert_called_with(mock.ANY,
nw_gw_id,
mapping_data)
self.assertEqual(res.status_int, exc.HTTPOk.code)
class NetworkGatewayDbTestCase(test_db_plugin.QuantumDbPluginV2TestCase):
""" Unit tests for Network Gateway DB support """
def setUp(self):
test_config['plugin_name_v2'] = '%s.%s' % (
__name__, TestNetworkGatewayPlugin.__name__)
ext_mgr = TestExtensionManager()
test_config['extension_manager'] = ext_mgr
self.resource = networkgw.RESOURCE_NAME.replace('-', '_')
super(NetworkGatewayDbTestCase, self).setUp()
def _create_network_gateway(self, fmt, tenant_id, name=None,
devices=None, arg_list=None, **kwargs):
data = {self.resource: {'tenant_id': tenant_id,
'devices': devices}}
if name:
data[self.resource]['name'] = name
for arg in arg_list or ():
# Arg must be present and not empty
if arg in kwargs and kwargs[arg]:
data[self.resource][arg] = kwargs[arg]
nw_gw_req = self.new_create_request(networkgw.COLLECTION_NAME,
data, fmt)
if (kwargs.get('set_context') and tenant_id):
# create a specific auth context for this request
nw_gw_req.environ['quantum.context'] = context.Context(
'', tenant_id)
return nw_gw_req.get_response(self.ext_api)
@contextlib.contextmanager
def _network_gateway(self, name='gw1', devices=None,
fmt='json', tenant_id=_uuid()):
if not devices:
devices = [{'id': _uuid(), 'interface_name': 'xyz'}]
res = self._create_network_gateway(fmt, tenant_id, name=name,
devices=devices)
network_gateway = self.deserialize(fmt, res)
if res.status_int >= 400:
raise exc.HTTPClientError(code=res.status_int)
yield network_gateway
self._delete(networkgw.COLLECTION_NAME,
network_gateway[self.resource]['id'])
def _gateway_action(self, action, network_gateway_id, network_id,
segmentation_type, segmentation_id=None,
expected_status=exc.HTTPOk.code):
connection_data = {'network_id': network_id,
'segmentation_type': segmentation_type}
if segmentation_id:
connection_data['segmentation_id'] = segmentation_id
req = self.new_action_request(networkgw.COLLECTION_NAME,
connection_data,
network_gateway_id,
"%s_network" % action)
res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, expected_status)
return self.deserialize('json', res)
def _test_connect_and_disconnect_network(self, segmentation_type,
segmentation_id=None):
with self._network_gateway() as gw:
with self.network() as net:
body = self._gateway_action('connect',
gw[self.resource]['id'],
net['network']['id'],
segmentation_type,
segmentation_id)
self.assertTrue('connection_info' in body)
connection_info = body['connection_info']
for attr in ('network_id', 'port_id',
'network_gateway_id'):
self.assertTrue(attr in connection_info)
# fetch port and confirm device_id
gw_port_id = connection_info['port_id']
port_body = self._show('ports', gw_port_id)
self.assertEquals(port_body['port']['device_id'],
gw[self.resource]['id'])
# Clean up - otherwise delete will fail
body = self._gateway_action('disconnect',
gw[self.resource]['id'],
net['network']['id'],
segmentation_type,
segmentation_id)
# Check associated port has been deleted too
body = self._show('ports', gw_port_id,
expected_code=exc.HTTPNotFound.code)
def test_create_network_gateway(self):
name = 'test-gw'
devices = [{'id': _uuid(), 'interface_name': 'xxx'},
{'id': _uuid(), 'interface_name': 'yyy'}]
keys = [('devices', devices), ('name', name)]
with self._network_gateway(name=name, devices=devices) as gw:
for k, v in keys:
self.assertEquals(gw[self.resource][k], v)
def _test_delete_network_gateway(self, exp_gw_count=0):
name = 'test-gw'
devices = [{'id': _uuid(), 'interface_name': 'xxx'},
{'id': _uuid(), 'interface_name': 'yyy'}]
with self._network_gateway(name=name, devices=devices):
# Nothing to do here - just let the gateway go
pass
# Verify nothing left on db
session = db_api.get_session()
gw_query = session.query(nicira_networkgw_db.NetworkGateway)
dev_query = session.query(nicira_networkgw_db.NetworkGatewayDevice)
self.assertEqual(exp_gw_count, len(gw_query.all()))
self.assertEqual(0, len(dev_query.all()))
def test_delete_network_gateway(self):
self._test_delete_network_gateway()
def test_update_network_gateway(self):
with self._network_gateway() as gw:
data = {self.resource: {'name': 'new_name'}}
req = self.new_update_request(networkgw.COLLECTION_NAME,
data,
gw[self.resource]['id'])
res = self.deserialize('json', req.get_response(self.ext_api))
self.assertEqual(res[self.resource]['name'],
data[self.resource]['name'])
def test_get_network_gateway(self):
with self._network_gateway(name='test-gw') as gw:
req = self.new_show_request(networkgw.COLLECTION_NAME,
gw[self.resource]['id'])
res = self.deserialize('json', req.get_response(self.ext_api))
self.assertEquals(res[self.resource]['name'],
gw[self.resource]['name'])
def test_list_network_gateways(self):
with self._network_gateway(name='test-gw-1') as gw1:
with self._network_gateway(name='test_gw_2') as gw2:
req = self.new_list_request(networkgw.COLLECTION_NAME)
res = self.deserialize('json', req.get_response(self.ext_api))
key = self.resource + 's'
self.assertEquals(len(res[key]), 2)
self.assertEquals(res[key][0]['name'],
gw1[self.resource]['name'])
self.assertEquals(res[key][1]['name'],
gw2[self.resource]['name'])
def test_connect_and_disconnect_network(self):
self._test_connect_and_disconnect_network('flat')
def test_connect_and_disconnect_network_with_segmentation_id(self):
self._test_connect_and_disconnect_network('vlan', 999)
def test_connect_network_multiple_times(self):
with self._network_gateway() as gw:
with self.network() as net_1:
self._gateway_action('connect',
gw[self.resource]['id'],
net_1['network']['id'],
'vlan', 555)
self._gateway_action('connect',
gw[self.resource]['id'],
net_1['network']['id'],
'vlan', 777)
self._gateway_action('disconnect',
gw[self.resource]['id'],
net_1['network']['id'],
'vlan', 555)
self._gateway_action('disconnect',
gw[self.resource]['id'],
net_1['network']['id'],
'vlan', 777)
def test_connect_network_multiple_gateways(self):
with self._network_gateway() as gw_1:
with self._network_gateway() as gw_2:
with self.network() as net_1:
self._gateway_action('connect',
gw_1[self.resource]['id'],
net_1['network']['id'],
'vlan', 555)
self._gateway_action('connect',
gw_2[self.resource]['id'],
net_1['network']['id'],
'vlan', 555)
self._gateway_action('disconnect',
gw_1[self.resource]['id'],
net_1['network']['id'],
'vlan', 555)
self._gateway_action('disconnect',
gw_2[self.resource]['id'],
net_1['network']['id'],
'vlan', 555)
def test_connect_network_mapping_in_use_returns_409(self):
with self._network_gateway() as gw:
with self.network() as net_1:
self._gateway_action('connect',
gw[self.resource]['id'],
net_1['network']['id'],
'vlan', 555)
with self.network() as net_2:
self._gateway_action('connect',
gw[self.resource]['id'],
net_2['network']['id'],
'vlan', 555,
expected_status=exc.HTTPConflict.code)
# Clean up - otherwise delete will fail
self._gateway_action('disconnect',
gw[self.resource]['id'],
net_1['network']['id'],
'vlan', 555)
def test_connect_invalid_network_returns_400(self):
with self._network_gateway() as gw:
self._gateway_action('connect',
gw[self.resource]['id'],
'hohoho',
'vlan', 555,
expected_status=exc.HTTPBadRequest.code)
def test_connect_unspecified_network_returns_400(self):
with self._network_gateway() as gw:
self._gateway_action('connect',
gw[self.resource]['id'],
None,
'vlan', 555,
expected_status=exc.HTTPBadRequest.code)
def test_disconnect_network_ambiguous_returns_409(self):
with self._network_gateway() as gw:
with self.network() as net_1:
self._gateway_action('connect',
gw[self.resource]['id'],
net_1['network']['id'],
'vlan', 555)
self._gateway_action('connect',
gw[self.resource]['id'],
net_1['network']['id'],
'vlan', 777)
# This should raise
self._gateway_action('disconnect',
gw[self.resource]['id'],
net_1['network']['id'],
'vlan',
expected_status=exc.HTTPConflict.code)
self._gateway_action('disconnect',
gw[self.resource]['id'],
net_1['network']['id'],
'vlan', 555)
self._gateway_action('disconnect',
gw[self.resource]['id'],
net_1['network']['id'],
'vlan', 777)
def test_delete_active_gateway_port_returns_409(self):
with self._network_gateway() as gw:
with self.network() as net_1:
body = self._gateway_action('connect',
gw[self.resource]['id'],
net_1['network']['id'],
'vlan', 555)
# fetch port id and try to delete it
gw_port_id = body['connection_info']['port_id']
self._delete('ports', gw_port_id,
expected_code=exc.HTTPConflict.code)
body = self._gateway_action('disconnect',
gw[self.resource]['id'],
net_1['network']['id'],
'vlan', 555)
def test_delete_network_gateway_active_connections_returns_409(self):
with self._network_gateway() as gw:
with self.network() as net_1:
self._gateway_action('connect',
gw[self.resource]['id'],
net_1['network']['id'],
'flat')
self._delete(networkgw.COLLECTION_NAME,
gw[self.resource]['id'],
expected_code=exc.HTTPConflict.code)
self._gateway_action('disconnect',
gw[self.resource]['id'],
net_1['network']['id'],
'flat')
def test_disconnect_non_existing_connection_returns_404(self):
with self._network_gateway() as gw:
with self.network() as net_1:
self._gateway_action('connect',
gw[self.resource]['id'],
net_1['network']['id'],
'vlan', 555)
self._gateway_action('disconnect',
gw[self.resource]['id'],
net_1['network']['id'],
'vlan', 999,
expected_status=exc.HTTPNotFound.code)
self._gateway_action('disconnect',
gw[self.resource]['id'],
net_1['network']['id'],
'vlan', 555)
class TestNetworkGatewayPlugin(db_base_plugin_v2.QuantumDbPluginV2,
nicira_networkgw_db.NetworkGatewayMixin):
""" Simple plugin class for testing db support for network gateway ext """
supported_extension_aliases = ["network-gateway"]
def delete_port(self, context, id, nw_gw_port_check=True):
if nw_gw_port_check:
port = self._get_port(context, id)
self.prevent_network_gateway_port_deletion(context, port)
super(TestNetworkGatewayPlugin, self).delete_port(context, id)