
Implementation of trunk driver for NSX-P Change-Id: I3a86037520a8399b526a83188540c098f92f2d57
263 lines
11 KiB
Python
263 lines
11 KiB
Python
# Copyright (c) 2016 VMware, Inc.
|
|
#
|
|
# 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 neutron.tests import base
|
|
|
|
from neutron_lib import context
|
|
from oslo_utils import importutils
|
|
|
|
from vmware_nsx.extensions import projectpluginmap
|
|
from vmware_nsx.services.trunk.nsx_p import driver as trunk_driver
|
|
from vmware_nsx.tests.unit.nsx_p import test_plugin as test_nsx_p_plugin
|
|
|
|
PLUGIN_NAME = 'vmware_nsx.plugins.nsx_p.plugin.NsxPolicyPlugin'
|
|
|
|
|
|
class TestNsxpTrunkHandler(test_nsx_p_plugin.NsxPPluginTestCaseMixin,
|
|
base.BaseTestCase):
|
|
|
|
def _get_port_tags_and_network(self, context, port_id):
|
|
return 'net_' + port_id[-1:], []
|
|
|
|
def setUp(self):
|
|
super(TestNsxpTrunkHandler, self).setUp()
|
|
self.context = context.get_admin_context()
|
|
self.core_plugin = importutils.import_object(PLUGIN_NAME)
|
|
self.handler = trunk_driver.NsxpTrunkHandler(self.core_plugin)
|
|
self.handler._get_port_tags_and_network = mock.Mock(
|
|
side_effect=self._get_port_tags_and_network)
|
|
self.trunk_1 = mock.Mock()
|
|
self.trunk_1.port_id = "parent_port_1"
|
|
self.trunk_1.id = "trunk_1_id"
|
|
|
|
self.trunk_2 = mock.Mock()
|
|
self.trunk_2.port_id = "parent_port_2"
|
|
|
|
self.sub_port_a = mock.Mock()
|
|
self.sub_port_a.segmentation_id = 40
|
|
self.sub_port_a.trunk_id = "trunk-1"
|
|
self.sub_port_a.port_id = "sub_port_a"
|
|
self.sub_port_a.segmentation_type = 'vlan'
|
|
|
|
self.sub_port_b = mock.Mock()
|
|
self.sub_port_b.segmentation_id = 41
|
|
self.sub_port_b.trunk_id = "trunk-2"
|
|
self.sub_port_b.port_id = "sub_port_b"
|
|
self.sub_port_b.segmentation_type = 'vlan'
|
|
|
|
self.sub_port_c = mock.Mock()
|
|
self.sub_port_c.segmentation_id = 43
|
|
self.sub_port_c.trunk_id = "trunk-2"
|
|
self.sub_port_c.port_id = "sub_port_c"
|
|
self.sub_port_c.segmentation_type = 'vlan'
|
|
|
|
def test_trunk_created(self):
|
|
# Create trunk with no subport
|
|
self.trunk_1.sub_ports = []
|
|
with mock.patch.object(
|
|
self.handler.plugin_driver.nsxpolicy.segment_port,
|
|
'attach') as m_attach:
|
|
self.handler.trunk_created(self.context, self.trunk_1)
|
|
m_attach.assert_called_with(
|
|
'net_1', self.trunk_1.port_id, attachment_type='PARENT',
|
|
tags=[{'tag': self.trunk_1.id,
|
|
'scope': 'os-neutron-trunk-id'}],
|
|
vif_id=self.trunk_1.port_id)
|
|
|
|
# Create trunk with 1 subport
|
|
self.trunk_1.sub_ports = [self.sub_port_a]
|
|
with mock.patch.object(
|
|
self.handler.plugin_driver.nsxpolicy.segment_port,
|
|
'attach') as m_attach:
|
|
self.handler.trunk_created(self.context, self.trunk_1)
|
|
calls = [
|
|
mock.call.m_attach(
|
|
'net_1', self.trunk_1.port_id, attachment_type='PARENT',
|
|
tags=[{'tag': self.trunk_1.id,
|
|
'scope': 'os-neutron-trunk-id'}],
|
|
vif_id=self.trunk_1.port_id),
|
|
mock.call.m_attach(
|
|
'net_a', self.sub_port_a.port_id, 'CHILD',
|
|
self.sub_port_a.port_id,
|
|
context_id=self.trunk_1.port_id,
|
|
tags=[{'tag': self.sub_port_a.trunk_id,
|
|
'scope': 'os-neutron-trunk-id'}],
|
|
traffic_tag=self.sub_port_a.segmentation_id)]
|
|
m_attach.assert_has_calls(calls, any_order=True)
|
|
|
|
# Create trunk with multiple subports
|
|
self.trunk_2.sub_ports = [self.sub_port_b, self.sub_port_c]
|
|
with mock.patch.object(
|
|
self.handler.plugin_driver.nsxpolicy.segment_port,
|
|
'attach') as m_attach:
|
|
self.handler.trunk_created(self.context, self.trunk_2)
|
|
calls = [
|
|
mock.call.m_attach(
|
|
'net_2', self.trunk_2.port_id, attachment_type='PARENT',
|
|
tags=[{'tag': self.trunk_2.id,
|
|
'scope': 'os-neutron-trunk-id'}],
|
|
vif_id=self.trunk_2.port_id),
|
|
mock.call.m_attach(
|
|
'net_b', self.sub_port_b.port_id, 'CHILD',
|
|
self.sub_port_b.port_id,
|
|
context_id=self.trunk_2.port_id,
|
|
tags=[{'tag': self.sub_port_b.trunk_id,
|
|
'scope': 'os-neutron-trunk-id'}],
|
|
traffic_tag=self.sub_port_b.segmentation_id),
|
|
mock.call.m_attach(
|
|
'net_c', self.sub_port_c.port_id, 'CHILD',
|
|
self.sub_port_c.port_id,
|
|
context_id=self.trunk_2.port_id,
|
|
tags=[{'tag': self.sub_port_c.trunk_id,
|
|
'scope': 'os-neutron-trunk-id'}],
|
|
traffic_tag=self.sub_port_c.segmentation_id)]
|
|
m_attach.assert_has_calls(calls, any_order=True)
|
|
|
|
def test_trunk_deleted(self):
|
|
# Delete trunk with no subport
|
|
self.trunk_1.sub_ports = []
|
|
with mock.patch.object(
|
|
self.handler.plugin_driver.nsxpolicy.segment_port,
|
|
'detach') as m_detach:
|
|
self.handler.trunk_deleted(self.context, self.trunk_1)
|
|
m_detach.assert_called_with(
|
|
'net_1', self.trunk_1.port_id, tags=mock.ANY)
|
|
|
|
# Delete trunk with 1 subport
|
|
self.trunk_1.sub_ports = [self.sub_port_a]
|
|
with mock.patch.object(
|
|
self.handler.plugin_driver.nsxpolicy.segment_port,
|
|
'detach') as m_detach:
|
|
self.handler.trunk_deleted(self.context, self.trunk_1)
|
|
calls = [
|
|
mock.call.m_detach(
|
|
'net_1', self.trunk_1.port_id, tags=mock.ANY),
|
|
mock.call.m_detach(
|
|
'net_a', self.sub_port_a.port_id, tags=mock.ANY)]
|
|
m_detach.assert_has_calls(calls, any_order=True)
|
|
|
|
# Delete trunk with multiple subports
|
|
self.trunk_2.sub_ports = [self.sub_port_b, self.sub_port_c]
|
|
with mock.patch.object(
|
|
self.handler.plugin_driver.nsxpolicy.segment_port,
|
|
'detach') as m_detach:
|
|
self.handler.trunk_deleted(self.context, self.trunk_2)
|
|
calls = [
|
|
mock.call.m_detach(
|
|
'net_2', self.trunk_2.port_id, tags=mock.ANY),
|
|
mock.call.m_detach(
|
|
'net_b', self.sub_port_b.port_id, tags=mock.ANY),
|
|
mock.call.m_detach(
|
|
'net_c', self.sub_port_c.port_id, tags=mock.ANY)]
|
|
m_detach.assert_has_calls(calls, any_order=True)
|
|
|
|
def test_subports_added(self):
|
|
# Update trunk with no subport
|
|
sub_ports = []
|
|
with mock.patch.object(
|
|
self.handler.plugin_driver.nsxpolicy.segment_port,
|
|
'attach') as m_attach:
|
|
self.handler.subports_added(self.context, self.trunk_1, sub_ports)
|
|
m_attach.assert_not_called()
|
|
|
|
# Update trunk with 1 subport
|
|
sub_ports = [self.sub_port_a]
|
|
with mock.patch.object(
|
|
self.handler.plugin_driver.nsxpolicy.segment_port,
|
|
'attach') as m_attach:
|
|
self.handler.subports_added(self.context, self.trunk_1, sub_ports)
|
|
m_attach.assert_called_with(
|
|
'net_a', self.sub_port_a.port_id, 'CHILD',
|
|
self.sub_port_a.port_id,
|
|
context_id=self.trunk_1.port_id,
|
|
tags=[{'tag': self.sub_port_a.trunk_id,
|
|
'scope': 'os-neutron-trunk-id'}],
|
|
traffic_tag=self.sub_port_a.segmentation_id)
|
|
|
|
# Update trunk with multiple subports
|
|
sub_ports = [self.sub_port_b, self.sub_port_c]
|
|
with mock.patch.object(
|
|
self.handler.plugin_driver.nsxpolicy.segment_port,
|
|
'attach') as m_attach:
|
|
self.handler.subports_added(self.context, self.trunk_2, sub_ports)
|
|
calls = [
|
|
mock.call.m_attach(
|
|
'net_b', self.sub_port_b.port_id, 'CHILD',
|
|
self.sub_port_b.port_id,
|
|
context_id=self.trunk_2.port_id,
|
|
tags=[{'tag': self.sub_port_b.trunk_id,
|
|
'scope': 'os-neutron-trunk-id'}],
|
|
traffic_tag=self.sub_port_b.segmentation_id),
|
|
mock.call.m_attach(
|
|
'net_c', self.sub_port_c.port_id, 'CHILD',
|
|
self.sub_port_c.port_id,
|
|
context_id=self.trunk_2.port_id,
|
|
tags=[{'tag': self.sub_port_c.trunk_id,
|
|
'scope': 'os-neutron-trunk-id'}],
|
|
traffic_tag=self.sub_port_c.segmentation_id)]
|
|
m_attach.assert_has_calls(calls, any_order=True)
|
|
|
|
def test_subports_deleted(self):
|
|
# Update trunk to remove no subport
|
|
sub_ports = []
|
|
with mock.patch.object(
|
|
self.handler.plugin_driver.nsxpolicy.segment_port,
|
|
'detach') as m_detach:
|
|
self.handler.subports_deleted(
|
|
self.context, self.trunk_1, sub_ports)
|
|
m_detach.assert_not_called()
|
|
|
|
# Update trunk to remove 1 subport
|
|
sub_ports = [self.sub_port_a]
|
|
with mock.patch.object(
|
|
self.handler.plugin_driver.nsxpolicy.segment_port,
|
|
'detach') as m_detach:
|
|
self.handler.subports_deleted(
|
|
self.context, self.trunk_1, sub_ports)
|
|
m_detach.assert_called_with(
|
|
'net_a', self.sub_port_a.port_id, tags=mock.ANY)
|
|
|
|
# Update trunk to remove multiple subports
|
|
sub_ports = [self.sub_port_b, self.sub_port_c]
|
|
with mock.patch.object(
|
|
self.handler.plugin_driver.nsxpolicy.segment_port,
|
|
'detach') as m_detach:
|
|
self.handler.subports_deleted(
|
|
self.context, self.trunk_2, sub_ports)
|
|
calls = [
|
|
mock.call.m_detach(
|
|
'net_b', self.sub_port_b.port_id, tags=mock.ANY),
|
|
mock.call.m_detach(
|
|
'net_c', self.sub_port_c.port_id, tags=mock.ANY)]
|
|
m_detach.assert_has_calls(calls, any_order=True)
|
|
|
|
|
|
class TestNsxpTrunkDriver(base.BaseTestCase):
|
|
def setUp(self):
|
|
super(TestNsxpTrunkDriver, self).setUp()
|
|
|
|
def test_is_loaded(self):
|
|
core_plugin = mock.Mock()
|
|
driver = trunk_driver.NsxpTrunkDriver.create(core_plugin)
|
|
with mock.patch.object(core_plugin, 'plugin_type',
|
|
return_value=projectpluginmap.NsxPlugins.NSX_P):
|
|
self.assertTrue(driver.is_loaded)
|
|
|
|
with mock.patch.object(core_plugin, 'plugin_type',
|
|
return_value=projectpluginmap.NsxPlugins.NSX_T):
|
|
self.assertFalse(driver.is_loaded)
|