Browse Source

Query PortBindingLevel table for segments bind to a port

During sync process only network segments that are bound to a port should be
sent to CVX when creating instances. For that reason, the PortBindingLevel
table should be used to get list of segments bind to a given port.

Change-Id: I712659ade0c270daa52a9cc65978f127779ce661
changes/78/517378/10
Nader Lahouti 5 years ago
parent
commit
f70f19987b
  1. 8
      networking_arista/common/db_lib.py
  2. 11
      networking_arista/ml2/rpc/arista_json.py
  3. 68
      networking_arista/tests/unit/common/test_db_lib.py
  4. 4
      networking_arista/tests/unit/ml2/rpc/test_arista_eapi_rpc_wrapper.py
  5. 293
      networking_arista/tests/unit/ml2/rpc/test_arista_json_rpc_wrapper.py

8
networking_arista/common/db_lib.py

@ -157,7 +157,9 @@ def get_port_binding_level(filters):
session = db.get_reader_session()
with session.begin():
return (session.query(ml2_models.PortBindingLevel).
filter_by(**filters).all())
filter_by(**filters).
order_by(ml2_models.PortBindingLevel.level).
all())
def get_network_segments_by_port_id(port_id):
@ -166,7 +168,9 @@ def get_network_segments_by_port_id(port_id):
segments = (session.query(segment_models.NetworkSegment,
ml2_models.PortBindingLevel).
join(ml2_models.PortBindingLevel).
filter_by(port_id=port_id).all())
filter_by(port_id=port_id).
order_by(ml2_models.PortBindingLevel.level).
all())
return [segment[0] for segment in segments]

11
networking_arista/ml2/rpc/arista_json.py

@ -459,10 +459,9 @@ class AristaRPCWrapperJSON(AristaRPCWrapperBase):
continue
network_id = neutron_port['network_id']
if network_id not in networkSegments:
networkSegments[
network_id] = self._ndb.get_all_network_segments(
network_id)
if port_id not in networkSegments:
networkSegments[port_id] = (
db_lib.get_network_segments_by_port_id(port_id))
port = self._create_port_data(port_id, tenant_id,
network_id, inst_id,
@ -474,7 +473,7 @@ class AristaRPCWrapperJSON(AristaRPCWrapperBase):
if instance_type in const.InstanceType.VIRTUAL_INSTANCE_TYPES:
portBinding = self._get_host_bindings(
port_id, inst_host, network_id,
networkSegments[network_id])
networkSegments[port_id])
elif (instance_type in
const.InstanceType.BAREMETAL_INSTANCE_TYPES):
switch_profile = json.loads(port_profiles[
@ -482,7 +481,7 @@ class AristaRPCWrapperJSON(AristaRPCWrapperBase):
portBinding = self._get_switch_bindings(
port_id, inst_host, network_id,
switch_profile['local_link_information'],
networkSegments[network_id])
networkSegments[port_id])
if port_id not in portBindings:
portBindings[port_id] = portBinding
else:

68
networking_arista/tests/unit/common/test_db_lib.py

@ -32,6 +32,74 @@ class DbLibTest(testlib_api.SqlTestCase):
"neutron.db.db_base_plugin_v2.NeutronDbPluginV2")
directory.add_plugin(plugin_constants.CORE, plugin_klass())
def test_binding_level_and_network_segments(self):
"""Test get_port_binding_level and get_network_segments_by_port_id"""
tenant_id = 't1'
network_id = '11111111-2222-3333-4444-555555555555'
network_ctx = utils.create_network(tenant_id,
network_id,
5000,
network_type='vxlan',
physical_network=None)
segments = [{'id': network_id,
'segmentation_id': 5000,
'physical_network': None,
'network_type': 'vxlan',
'is_dynamic': False},
{'id': None,
'segmentation_id': 500,
'physical_network': 'physnet1',
'network_type': 'vlan',
'is_dynamic': True},
{'id': None,
'segmentation_id': 600,
'physical_network': 'physnet2',
'network_type': 'vlan',
'is_dynamic': True}]
for segment in segments:
if segment['is_dynamic']:
dyn_seg = utils.create_dynamic_segment(
network_id, segment['segmentation_id'],
segment['network_type'], segment['physical_network'])
segment['id'] = dyn_seg['id']
# create ports with different dynamic segments on different hosts
device_id_1 = 'dev1'
port_id_1 = 'p1'
host_1 = 'h1'
utils.create_port(tenant_id, network_id, device_id_1,
port_id_1, network_ctx, host=host_1,
dynamic_segment=segments[1])
device_id_2 = 'dev2'
port_id_2 = 'p2'
host_2 = 'h2'
utils.create_port(tenant_id, network_id, device_id_2,
port_id_2, network_ctx, host=host_2,
dynamic_segment=segments[2])
# Verify get_port_binding_level result
filters = {'port_id': port_id_1,
'host': host_1}
res_binding_level = db_lib.get_port_binding_level(filters)
self.assertEqual(len(res_binding_level), 2)
expected_ctxt = utils.get_port_context(
tenant_id, network_id, device_id_1, network_ctx, port_id_1,
host=host_1, dynamic_segment=segments[1])
for i in range(0, len(res_binding_level)):
self.assertEqual(dict(res_binding_level[i]),
vars(expected_ctxt._binding_levels[i]))
# Verify get_network_segments_by_port_id result
res_segs = db_lib.get_network_segments_by_port_id(port_id_1)
self.assertEqual(len(res_segs), 2)
subset_keys = {'id', 'network_type', 'physical_network',
'segmentation_id', 'is_dynamic'}
for i, rs in enumerate(res_segs):
self.assertEqual(segments[i],
{k: v for k, v in rs if k in subset_keys})
def test_get_tenants_empty(self):
tenants = db_lib.get_tenants()
self.assertEqual(tenants, set())

4
networking_arista/tests/unit/ml2/rpc/test_arista_eapi_rpc_wrapper.py

@ -25,10 +25,6 @@ from networking_arista.ml2.rpc import arista_eapi
from networking_arista.tests.unit import utils
EAPI_SEND_FUNC = ('networking_arista.ml2.rpc.arista_eapi.AristaRPCWrapperEapi'
'._send_eapi_req')
def setup_valid_config():
utils.setup_arista_wrapper_config(cfg)

293
networking_arista/tests/unit/ml2/rpc/test_arista_json_rpc_wrapper.py

@ -36,6 +36,7 @@ from networking_arista.tests.unit import utils
BASE_RPC = "networking_arista.ml2.rpc.arista_json.AristaRPCWrapperJSON."
JSON_SEND_FUNC = BASE_RPC + "_send_api_request"
RAND_FUNC = BASE_RPC + "_get_random_name"
DB_LIB_MODULE = 'networking_arista.ml2.rpc.arista_json.db_lib'
def setup_valid_config():
@ -262,7 +263,8 @@ class TestAristaJSONRPCWrapper(testlib_api.SqlTestCase):
self._verify_send_api_request_call(mock_send_api_req, calls)
@patch(JSON_SEND_FUNC)
def test_create_instance_bulk(self, mock_send_api_req):
@patch(DB_LIB_MODULE)
def test_create_instance_bulk(self, mock_db_lib, mock_send_api_req):
tenant_id = 'ten-3'
num_devices = 8
num_ports_per_device = 2
@ -301,6 +303,19 @@ class TestAristaJSONRPCWrapper(testlib_api.SqlTestCase):
'network_id': 'network-id-%d' % net_count,
'name': 'port-%d-%d' % (device_id, port_id),
'tenant_id': tenant_id,
'segments': [{
'network_id': 'network-id-%d' % net_count,
'segment_type': 'static',
'segmentation_id': (5000 + net_count),
'is_dynamic': False,
'network_type': 'vxlan',
'id': 'segment-id-%d' % (5000 + net_count)},
{'network_id': 'network-id-%d' % net_count,
'segment_type': 'dynamic',
'segmentation_id': (500 + net_count),
'is_dynamic': True,
'network_type': 'vlan',
'id': 'segment-id-%d' % (500 + net_count)}],
}
port_list.append(port)
net_count += 1
@ -309,6 +324,10 @@ class TestAristaJSONRPCWrapper(testlib_api.SqlTestCase):
for port in port_list:
create_ports.update(utils.port_dict_representation(port))
port_network_segments = {}
for port in port_list:
port_network_segments[port['portId']] = port['segments']
profiles = {}
for port in port_list:
profiles[port['portId']] = {'vnic_type': 'normal'}
@ -317,6 +336,9 @@ class TestAristaJSONRPCWrapper(testlib_api.SqlTestCase):
'vnic_type': 'baremetal',
'profile': '{"local_link_information":'
'[{"switch_id": "switch01", "port_id": "Ethernet1"}]}'}
mock_db_lib.get_network_segments_by_port_id.side_effect = (
port_network_segments.get)
self.drv.create_instance_bulk(tenant_id, create_ports, devices,
profiles)
calls = [
@ -407,64 +429,244 @@ class TestAristaJSONRPCWrapper(testlib_api.SqlTestCase):
'instanceType': 'router', 'vlanType': 'allowed'}]),
('region/RegionOne/port/port-id-0-0/binding',
'POST', [{'portId': 'port-id-0-0', 'hostBinding': [
{'segment': [], 'host': 'host_0'}]}]),
'POST', [{'portId': 'port-id-0-0',
'hostBinding': [{
'segment': [{'networkId': 'network-id-0',
'segment_type': 'static',
'segmentationId': 5000,
'type': 'vxlan',
'id': 'segment-id-5000'},
{'networkId': 'network-id-0',
'segment_type': 'dynamic',
'segmentationId': 500,
'type': 'vlan',
'id': 'segment-id-500'}],
'host': 'host_0'}]}]),
('region/RegionOne/port/port-id-0-1/binding',
'POST', [{'portId': 'port-id-0-1', 'hostBinding': [
{'segment': [], 'host': 'host_0'}]}]),
'POST', [{'portId': 'port-id-0-1',
'hostBinding': [{
'segment': [{'networkId': 'network-id-1',
'segment_type': 'static',
'segmentationId': 5001,
'type': 'vxlan',
'id': 'segment-id-5001'},
{'networkId': 'network-id-1',
'segment_type': 'dynamic',
'segmentationId': 501,
'type': 'vlan',
'id': 'segment-id-501'}],
'host': 'host_0'}]}]),
('region/RegionOne/port/port-id-1-0/binding',
'POST', [{'portId': 'port-id-1-0', 'hostBinding': [
{'segment': [], 'host': 'host_1'}]}]),
'POST', [{'portId': 'port-id-1-0',
'hostBinding': [{
'segment': [{'networkId': 'network-id-2',
'segment_type': 'static',
'segmentationId': 5002,
'type': 'vxlan',
'id': 'segment-id-5002'},
{'networkId': 'network-id-2',
'segment_type': 'dynamic',
'segmentationId': 502,
'type': 'vlan',
'id': 'segment-id-502'}],
'host': 'host_1'}]}]),
('region/RegionOne/port/port-id-1-1/binding',
'POST', [{'portId': 'port-id-1-1', 'hostBinding': [
{'segment': [], 'host': 'host_1'}]}]),
'POST', [{'portId': 'port-id-1-1',
'hostBinding': [{
'segment': [{'networkId': 'network-id-3',
'segment_type': 'static',
'segmentationId': 5003,
'type': 'vxlan',
'id': 'segment-id-5003'},
{'networkId': 'network-id-3',
'segment_type': 'dynamic',
'segmentationId': 503,
'type': 'vlan',
'id': 'segment-id-503'}],
'host': 'host_1'}]}]),
('region/RegionOne/port/port-id-2-0/binding',
'POST', [{'portId': 'port-id-2-0', 'switchBinding': [
{'interface': u'Ethernet1', 'host': 'host_2',
'segment': [], 'switch': u'switch01'}]}]),
'POST', [{'portId': 'port-id-2-0',
'switchBinding': [{
'interface': u'Ethernet1',
'host': 'host_2',
'segment': [{'networkId': 'network-id-4',
'segment_type': 'static',
'segmentationId': 5004,
'type': 'vxlan',
'id': 'segment-id-5004'},
{'networkId': 'network-id-4',
'segment_type': 'dynamic',
'segmentationId': 504,
'type': 'vlan',
'id': 'segment-id-504'}],
'switch': u'switch01'}]}]),
('region/RegionOne/port/port-id-2-1/binding',
'POST', [{'portId': 'port-id-2-1', 'switchBinding': [
{'interface': u'Ethernet1', 'host': 'host_2',
'segment': [], 'switch': u'switch01'}]}]),
'POST', [{'portId': 'port-id-2-1',
'switchBinding': [
{'interface': u'Ethernet1',
'host': 'host_2',
'segment': [{'networkId': 'network-id-5',
'segment_type': 'static',
'segmentationId': 5005,
'type': 'vxlan',
'id': 'segment-id-5005'},
{'networkId': 'network-id-5',
'segment_type': 'dynamic',
'segmentationId': 505,
'type': 'vlan',
'id': 'segment-id-505'}],
'switch': u'switch01'}]}]),
('region/RegionOne/port/port-id-3-0/binding',
'POST', [{'portId': 'port-id-3-0', 'hostBinding': [
{'segment': [], 'host': 'host_3'}]}]),
'POST', [{'portId': 'port-id-3-0',
'hostBinding': [{
'segment': [{'networkId': 'network-id-6',
'segment_type': 'static',
'segmentationId': 5006,
'type': 'vxlan',
'id': 'segment-id-5006'},
{'networkId': 'network-id-6',
'segment_type': 'dynamic',
'segmentationId': 506,
'type': 'vlan',
'id': 'segment-id-506'}],
'host': 'host_3'}]}]),
('region/RegionOne/port/port-id-3-1/binding',
'POST', [{'portId': 'port-id-3-1', 'hostBinding': [
{'segment': [], 'host': 'host_3'}]}]),
'POST', [{'portId': 'port-id-3-1',
'hostBinding': [{
'segment': [{'networkId': 'network-id-7',
'segment_type': 'static',
'segmentationId': 5007,
'type': 'vxlan',
'id': 'segment-id-5007'},
{'networkId': 'network-id-7',
'segment_type': 'dynamic',
'segmentationId': 507,
'type': 'vlan',
'id': 'segment-id-507'}],
'host': 'host_3'}]}]),
('region/RegionOne/port/port-id-4-0/binding',
'POST', [{'portId': 'port-id-4-0', 'hostBinding': [
{'segment': [], 'host': 'host_4'}]}]),
'POST', [{'portId': 'port-id-4-0',
'hostBinding': [{
'segment': [{'networkId': 'network-id-8',
'segment_type': 'static',
'segmentationId': 5008,
'type': 'vxlan',
'id': 'segment-id-5008'},
{'networkId': 'network-id-8',
'segment_type': 'dynamic',
'segmentationId': 508,
'type': 'vlan',
'id': 'segment-id-508'}],
'host': 'host_4'}]}]),
('region/RegionOne/port/port-id-4-1/binding',
'POST', [{'portId': 'port-id-4-1', 'hostBinding': [
{'segment': [], 'host': 'host_4'}]}]),
'POST', [{'portId': 'port-id-4-1',
'hostBinding': [{
'segment': [{'networkId': 'network-id-9',
'segment_type': 'static',
'segmentationId': 5009,
'type': 'vxlan',
'id': 'segment-id-5009'},
{'networkId': 'network-id-9',
'segment_type': 'dynamic',
'segmentationId': 509,
'type': 'vlan',
'id': 'segment-id-509'}],
'host': 'host_4'}]}]),
('region/RegionOne/port/port-id-5-0/binding',
'POST', [{'portId': 'port-id-5-0', 'hostBinding': [
{'segment': [], 'host': 'host_5'}]}]),
'POST', [{'portId': 'port-id-5-0',
'hostBinding': [{
'segment': [{'networkId': 'network-id-10',
'segment_type': 'static',
'segmentationId': 5010,
'type': 'vxlan',
'id': 'segment-id-5010'},
{'networkId': 'network-id-10',
'segment_type': 'dynamic',
'segmentationId': 510,
'type': 'vlan',
'id': 'segment-id-510'}],
'host': 'host_5'}]}]),
('region/RegionOne/port/port-id-5-1/binding',
'POST', [{'portId': 'port-id-5-1', 'hostBinding': [
{'segment': [], 'host': 'host_5'}]}]),
'POST', [{'portId': 'port-id-5-1',
'hostBinding': [{
'segment': [{'networkId': 'network-id-11',
'segment_type': 'static',
'segmentationId': 5011,
'type': 'vxlan',
'id': 'segment-id-5011'},
{'networkId': 'network-id-11',
'segment_type': 'dynamic',
'segmentationId': 511,
'type': 'vlan',
'id': 'segment-id-511'}],
'host': 'host_5'}]}]),
('region/RegionOne/port/port-id-6-0/binding',
'POST', [{'portId': 'port-id-6-0', 'switchBinding': [
{'interface': u'Ethernet1', 'host': 'host_6',
'segment': [], 'switch': u'switch01'}]}]),
'POST', [{'portId': 'port-id-6-0',
'switchBinding': [{
'interface': u'Ethernet1',
'host': 'host_6',
'segment': [{'networkId': 'network-id-12',
'segment_type': 'static',
'segmentationId': 5012,
'type': 'vxlan',
'id': 'segment-id-5012'},
{'networkId': 'network-id-12',
'segment_type': 'dynamic',
'segmentationId': 512,
'type': 'vlan',
'id': 'segment-id-512'}],
'switch': u'switch01'}]}]),
('region/RegionOne/port/port-id-6-1/binding',
'POST', [{'portId': 'port-id-6-1', 'switchBinding': [
{'interface': u'Ethernet1', 'host': 'host_6',
'segment': [], 'switch': u'switch01'}]}]),
'POST', [{'portId': 'port-id-6-1',
'switchBinding': [{
'interface': u'Ethernet1',
'host': 'host_6',
'segment': [{'networkId': 'network-id-13',
'segment_type': 'static',
'segmentationId': 5013,
'type': 'vxlan',
'id': 'segment-id-5013'},
{'networkId': 'network-id-13',
'segment_type': 'dynamic',
'segmentationId': 513,
'type': 'vlan',
'id': 'segment-id-513'}],
'switch': u'switch01'}]}]),
('region/RegionOne/port/port-id-7-0/binding',
'POST', [{'portId': 'port-id-7-0', 'hostBinding': [
{'segment': [], 'host': 'host_7'}]}]),
'POST', [{'portId': 'port-id-7-0',
'hostBinding': [{
'segment': [{'networkId': 'network-id-14',
'segment_type': 'static',
'segmentationId': 5014,
'type': 'vxlan',
'id': 'segment-id-5014'},
{'networkId': 'network-id-14',
'segment_type': 'dynamic',
'segmentationId': 514,
'type': 'vlan',
'id': 'segment-id-514'}],
'host': 'host_7'}]}]),
('region/RegionOne/port/port-id-7-1/binding',
'POST', [{'portId': 'port-id-7-1', 'hostBinding': [
{'segment': [], 'host': 'host_7'}]}]),
'POST', [{'portId': 'port-id-7-1',
'hostBinding': [{
'segment': [{'networkId': 'network-id-15',
'segment_type': 'static',
'segmentationId': 5015,
'type': 'vxlan',
'id': 'segment-id-5015'},
{'networkId': 'network-id-15',
'segment_type': 'dynamic',
'segmentationId': 515,
'type': 'vlan',
'id': 'segment-id-515'}],
'host': 'host_7'}]}]),
]
self._verify_send_api_request_call(mock_send_api_req, calls, True)
@ -720,10 +922,11 @@ class RPCWrapperJSONValidConfigTrunkTestCase(testlib_api.SqlTestCase):
self.drv = arista_json.AristaRPCWrapperJSON(ndb)
self.drv._server_ip = "10.11.12.13"
self.region = 'RegionOne'
arista_json.db_lib = mock.MagicMock()
@patch(JSON_SEND_FUNC)
def test_plug_virtual_trunk_port_into_network(self, mock_send_api_req):
@patch(DB_LIB_MODULE)
def test_plug_virtual_trunk_port_into_network(self, mock_db_lib,
mock_send_api_req):
# vm
tenant_id = 'ten-1'
network_id = 'net-id-1'
@ -750,8 +953,8 @@ class RPCWrapperJSONValidConfigTrunkTestCase(testlib_api.SqlTestCase):
'segmentation_type': 'vlan'}],
'trunk_id': 'trunk_id'}
self.drv._ndb.get_network_id_from_port_id.return_value = subport_net_id
arista_json.db_lib.get_network_segments_by_port_id.return_value = \
subport_segments
mock_db_lib.get_network_segments_by_port_id.return_value = (
subport_segments)
self.drv.plug_port_into_network(vm_id, host, port_id, network_id,
tenant_id, port_name,
@ -783,7 +986,9 @@ class RPCWrapperJSONValidConfigTrunkTestCase(testlib_api.SqlTestCase):
self._verify_send_api_request_call(mock_send_api_req, calls)
@patch(JSON_SEND_FUNC)
def test_plug_baremetal_trunk_port_into_network(self, mock_send_api_req):
@patch(DB_LIB_MODULE)
def test_plug_baremetal_trunk_port_into_network(self, mock_db_lib,
mock_send_api_req):
# baremetal
tenant_id = 'ten-2'
network_id = 'net-id-1'
@ -813,8 +1018,8 @@ class RPCWrapperJSONValidConfigTrunkTestCase(testlib_api.SqlTestCase):
'switch_info': 'switch-1'}]}
bindings = switch_bindings['local_link_information']
self.drv._ndb.get_network_id_from_port_id.return_value = subport_net_id
arista_json.db_lib.get_network_segments_by_port_id.return_value = \
subport_segments
mock_db_lib.get_network_segments_by_port_id.return_value = (
subport_segments)
self.drv.plug_port_into_network(bm_id, host, port_id, network_id,
tenant_id, port_name,

Loading…
Cancel
Save