vmware-nsx/vmware_nsx/tests/unit/services/flowclassifier/test_nsxv_driver.py
Adit Sarfaty 60fc5a748d NSX|V: support large port ranges in service insertion
Adding a range of source/destination ports in a flow classifier rule should
not be done by adding each specific port, but sending it to the NSX as
a range.
This fix allows us to remove the restriction of only 15 ports in a range.

Change-Id: Ie6ccd8a2932bc1e75ed380c176f79008a46b4c59
2017-07-09 12:19:01 +03:00

271 lines
11 KiB
Python

# Copyright 2016 VMware, 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 mock
from oslo_config import cfg
from oslo_utils import importutils
from vmware_nsx.services.flowclassifier.nsx_v import driver as nsx_v_driver
from vmware_nsx.tests import unit as vmware
from vmware_nsx.tests.unit.nsx_v.vshield import fake_vcns
from neutron.api import extensions as api_ext
from neutron.common import config
from neutron_lib.api.definitions import portbindings
from neutron_lib import context
from neutron_lib.plugins import directory
from networking_sfc.db import flowclassifier_db as fdb
from networking_sfc.extensions import flowclassifier
from networking_sfc.services.flowclassifier.common import context as fc_ctx
from networking_sfc.services.flowclassifier.common import exceptions as fc_exc
from networking_sfc.tests import base
from networking_sfc.tests.unit.db import test_flowclassifier_db
class TestNsxvFlowClassifierDriver(
test_flowclassifier_db.FlowClassifierDbPluginTestCaseBase,
base.NeutronDbPluginV2TestCase):
resource_prefix_map = dict([
(k, flowclassifier.FLOW_CLASSIFIER_PREFIX)
for k in flowclassifier.RESOURCE_ATTRIBUTE_MAP.keys()
])
def setUp(self):
# init the flow classifier plugin
flowclassifier_plugin = (
test_flowclassifier_db.DB_FLOWCLASSIFIER_PLUGIN_CLASS)
service_plugins = {
flowclassifier.FLOW_CLASSIFIER_EXT: flowclassifier_plugin
}
fdb.FlowClassifierDbPlugin.supported_extension_aliases = [
flowclassifier.FLOW_CLASSIFIER_EXT]
fdb.FlowClassifierDbPlugin.path_prefix = (
flowclassifier.FLOW_CLASSIFIER_PREFIX
)
super(TestNsxvFlowClassifierDriver, self).setUp(
ext_mgr=None,
plugin=None,
service_plugins=service_plugins
)
self.flowclassifier_plugin = importutils.import_object(
flowclassifier_plugin)
ext_mgr = api_ext.PluginAwareExtensionManager(
test_flowclassifier_db.extensions_path,
{
flowclassifier.FLOW_CLASSIFIER_EXT: self.flowclassifier_plugin
}
)
app = config.load_paste_app('extensions_test_app')
self.ext_api = api_ext.ExtensionMiddleware(app, ext_mgr=ext_mgr)
self.ctx = context.get_admin_context()
# use the fake vcns
mock_vcns = mock.patch(vmware.VCNS_NAME, autospec=True)
mock_vcns_instance = mock_vcns.start()
self.fc2 = fake_vcns.FakeVcns()
mock_vcns_instance.return_value = self.fc2
# use the nsxv flow classifier driver
self._profile_id = 'serviceprofile-1'
cfg.CONF.set_override('service_insertion_profile_id',
self._profile_id, 'nsxv')
cfg.CONF.set_override('service_insertion_redirect_all',
True, 'nsxv')
self.driver = nsx_v_driver.NsxvFlowClassifierDriver()
self.driver.initialize()
self._fc_name = 'test1'
self._fc_description = 'test 1'
self._fc_source = '10.10.0.0/24'
self._fc_dest = '20.10.0.0/24'
self._fc_prot = 'TCP'
self._fc_source_ports = range(100, 115)
self._fc_dest_ports = range(80, 81)
self._fc = {'name': self._fc_name,
'description': self._fc_description,
'logical_source_port': None,
'logical_destination_port': None,
'source_ip_prefix': self._fc_source,
'destination_ip_prefix': self._fc_dest,
'protocol': self._fc_prot,
'source_port_range_min': self._fc_source_ports[0],
'source_port_range_max': self._fc_source_ports[-1],
'destination_port_range_min': self._fc_dest_ports[0],
'destination_port_range_max': self._fc_dest_ports[-1]}
def tearDown(self):
super(TestNsxvFlowClassifierDriver, self).tearDown()
def test_driver_init(self):
self.assertEqual(self._profile_id, self.driver._profile_id)
self.assertEqual(self.driver._security_group_id, '0')
orig_get_plugin = directory.get_plugin
def mocked_get_plugin(plugin=None):
# mock only the core plugin
if plugin:
return orig_get_plugin(plugin)
return mock_nsxv_plugin
mock_nsxv_plugin = mock.Mock()
fc_plugin = directory.get_plugin(flowclassifier.FLOW_CLASSIFIER_EXT)
with mock.patch.object(directory, 'get_plugin',
new=mocked_get_plugin):
with mock.patch.object(
mock_nsxv_plugin,
'add_vms_to_service_insertion') as fake_add:
with mock.patch.object(
fc_plugin,
'create_flow_classifier') as fake_create:
self.driver.init_complete(None, None, {})
# check that the plugin was called to add vms to the
# security group
self.assertTrue(fake_add.called)
# check that redirect_all flow classifier entry
# was created
self.assertTrue(fake_create.called)
def test_create_flow_classifier_precommit(self):
with self.flow_classifier(flow_classifier=self._fc) as fc:
fc_context = fc_ctx.FlowClassifierContext(
self.flowclassifier_plugin, self.ctx,
fc['flow_classifier']
)
# just make sure it does not raise an exception
self.driver.create_flow_classifier_precommit(fc_context)
def test_create_flow_classifier_precommit_logical_source_port(self):
with self.port(
name='port1',
device_owner='compute',
device_id='test',
arg_list=(
portbindings.HOST_ID,
),
**{portbindings.HOST_ID: 'test'}
) as src_port:
with self.flow_classifier(flow_classifier={
'name': 'test1',
'logical_source_port': src_port['port']['id']
}) as fc:
fc_context = fc_ctx.FlowClassifierContext(
self.flowclassifier_plugin, self.ctx,
fc['flow_classifier']
)
self.assertRaises(
fc_exc.FlowClassifierBadRequest,
self.driver.create_flow_classifier_precommit,
fc_context)
def test_create_flow_classifier_precommit_logical_dest_port(self):
with self.port(
name='port1',
device_owner='compute',
device_id='test',
arg_list=(
portbindings.HOST_ID,
),
**{portbindings.HOST_ID: 'test'}
) as dst_port:
with self.flow_classifier(flow_classifier={
'name': 'test1',
'logical_destination_port': dst_port['port']['id']
}) as fc:
fc_context = fc_ctx.FlowClassifierContext(
self.flowclassifier_plugin, self.ctx,
fc['flow_classifier']
)
self.assertRaises(
fc_exc.FlowClassifierBadRequest,
self.driver.create_flow_classifier_precommit,
fc_context)
def _validate_rule_structure(self, rule):
self.assertEqual(self._fc_description, rule.find('notes').text)
self.assertEqual('ipv4', rule.find('packetType').text)
self.assertEqual(
self._fc_source,
rule.find('sources').find('source').find('value').text)
self.assertEqual(
self._fc_dest,
rule.find('destinations').find('destination').find('value').text)
ports = "%s-%s" % (self._fc_source_ports[0], self._fc_source_ports[-1])
if self._fc_source_ports[0] == self._fc_source_ports[-1]:
ports = str(self._fc_source_ports[0])
self.assertEqual(
ports,
rule.find('services').find('service').find('sourcePort').text)
ports = "%s-%s" % (self._fc_dest_ports[0], self._fc_dest_ports[-1])
if self._fc_dest_ports[0] == self._fc_dest_ports[-1]:
ports = str(self._fc_dest_ports[0])
self.assertEqual(
ports,
rule.find('services').find('service').find('destinationPort').text)
self.assertEqual(
self._fc_prot,
rule.find('services').find('service').find('protocolName').text)
self.assertTrue(rule.find('name').text.startswith(self._fc_name))
def test_create_flow_classifier(self):
with self.flow_classifier(flow_classifier=self._fc) as fc:
fc_context = fc_ctx.FlowClassifierContext(
self.flowclassifier_plugin, self.ctx,
fc['flow_classifier']
)
with mock.patch.object(
self.driver,
'update_redirect_section_in_backed') as mock_update_section:
self.driver.create_flow_classifier(fc_context)
self.assertTrue(mock_update_section.called)
section = mock_update_section.call_args[0][0]
self._validate_rule_structure(section.find('rule'))
def test_update_flow_classifier(self):
with self.flow_classifier(flow_classifier=self._fc) as fc:
fc_context = fc_ctx.FlowClassifierContext(
self.flowclassifier_plugin, self.ctx,
fc['flow_classifier']
)
self.driver.create_flow_classifier(fc_context)
with mock.patch.object(
self.driver,
'update_redirect_section_in_backed') as mock_update_section:
self.driver.update_flow_classifier(fc_context)
self.assertTrue(mock_update_section.called)
section = mock_update_section.call_args[0][0]
self._validate_rule_structure(section.find('rule'))
def test_delete_flow_classifier(self):
with self.flow_classifier(flow_classifier=self._fc) as fc:
fc_context = fc_ctx.FlowClassifierContext(
self.flowclassifier_plugin, self.ctx,
fc['flow_classifier']
)
self.driver.create_flow_classifier(fc_context)
with mock.patch.object(
self.driver,
'update_redirect_section_in_backed') as mock_update_section:
self.driver.delete_flow_classifier(fc_context)
self.assertTrue(mock_update_section.called)
section = mock_update_section.call_args[0][0]
# make sure the rule is not there
self.assertIsNone(section.find('rule'))