Skip to content

Commit 9d22276

Browse files
committed
get_hosts_mapped_with_segments add filter agt_type
Extend the get_hosts_mapped_with_segments method to add optional filters to include/exclude based on agent type. Uses a joined query, when both include and exclude filtering is used togheter the exclude filter is most significant. Partial-Bug: #2040172 Change-Id: I2cfd52a2657fad989e24e974fda470ecd960262b Signed-off-by: Harald Jensås <[email protected]> (cherry picked from commit 64b5787)
1 parent 3ab7d6e commit 9d22276

File tree

2 files changed

+174
-3
lines changed

2 files changed

+174
-3
lines changed

neutron/services/segments/db.py

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
from oslo_log import log as logging
3232
from oslo_utils import uuidutils
3333

34+
from neutron.db.models import agent as agent_model
35+
from neutron.db.models import segment as segment_model
3436
from neutron.db import segments_db as db
3537
from neutron import manager
3638
from neutron.objects import base as base_obj
@@ -243,14 +245,43 @@ def update_segment_host_mapping(context, host, current_segment_ids):
243245
entry.segment_id, entry.host)
244246

245247

246-
def get_hosts_mapped_with_segments(context):
248+
def get_hosts_mapped_with_segments(context, include_agent_types=None,
249+
exclude_agent_types=None):
247250
"""Get hosts that are mapped with segments.
248251
249252
L2 providers can use this method to get an overview of SegmentHostMapping,
250253
and then delete the stale SegmentHostMapping.
254+
255+
When using both include_agent_types and exclude_agent_types,
256+
exclude_agent_types is most significant.
257+
All hosts without agent are excluded when using any agent_type filter.
258+
259+
:param context: current running context information
260+
:param include_agent_types: (set) List of agent types, include hosts
261+
with matching agents.
262+
:param exclude_agent_types: (set) List of agent types, exclude hosts
263+
with matching agents.
251264
"""
252-
segment_host_mapping = network.SegmentHostMapping.get_objects(context)
253-
return {row.host for row in segment_host_mapping}
265+
def add_filter_by_agent_types(qry, include, exclude):
266+
qry = qry.join(
267+
agent_model.Agent,
268+
segment_model.SegmentHostMapping.host == agent_model.Agent.host)
269+
if include:
270+
qry = qry.filter(agent_model.Agent.agent_type.in_(include))
271+
if exclude:
272+
qry = qry.filter(agent_model.Agent.agent_type.not_in(exclude))
273+
274+
return qry
275+
276+
with db_api.CONTEXT_READER.using(context):
277+
query = context.session.query(segment_model.SegmentHostMapping)
278+
if include_agent_types or exclude_agent_types:
279+
query = add_filter_by_agent_types(query, include_agent_types,
280+
exclude_agent_types)
281+
282+
res = query.all()
283+
284+
return {row.host for row in res}
254285

255286

256287
def _get_phys_nets(agent):

neutron/tests/unit/extensions/test_segment.py

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,10 +748,37 @@ def test_get_all_hosts_mapped_with_segments(self):
748748
actual_hosts = db.get_hosts_mapped_with_segments(ctx)
749749
self.assertEqual(hosts, actual_hosts)
750750

751+
def test_get_all_hosts_mapped_with_segments_agent_type_filter(self):
752+
ctx = context.get_admin_context()
753+
hosts = set()
754+
with self.network() as network:
755+
network_id = network['network']['id']
756+
for i in range(1, 3):
757+
host = "host%s" % i
758+
segment = self._test_create_segment(
759+
network_id=network_id, physical_network='physnet%s' % i,
760+
segmentation_id=200 + i, network_type=constants.TYPE_VLAN)
761+
db.update_segment_host_mapping(
762+
ctx, host, {segment['segment']['id']})
763+
hosts.add(host)
764+
765+
# Now they are 2 hosts with segment being mapped.
766+
# host1 does not have an agent
767+
# host2 does not have an agent
768+
# Any agent_type filter excludes hosts that does not have an agent
769+
actual_hosts = db.get_hosts_mapped_with_segments(
770+
ctx, exclude_agent_types={'fake-agent-type'})
771+
self.assertEqual(set(), actual_hosts)
772+
actual_hosts = db.get_hosts_mapped_with_segments(
773+
ctx, include_agent_types={'fake-agent-type'})
774+
self.assertEqual(set(), actual_hosts)
775+
751776

752777
class TestMl2HostSegmentMappingOVS(HostSegmentMappingTestCase):
753778
_mechanism_drivers = ['openvswitch', 'logger']
754779
mock_path = 'neutron.services.segments.db.update_segment_host_mapping'
780+
agent_type_a = constants.AGENT_TYPE_OVS
781+
agent_type_b = constants.AGENT_TYPE_LINUXBRIDGE
755782

756783
def test_new_agent(self):
757784
host = 'host1'
@@ -871,9 +898,118 @@ def test_agent_with_no_mappings(self, mock):
871898
self.assertFalse(segments_host_db)
872899
self.assertFalse(mock.mock_calls)
873900

901+
def test_get_all_hosts_mapped_with_segments(self):
902+
ctx = context.get_admin_context()
903+
hosts = set()
904+
with self.network() as network:
905+
network_id = network['network']['id']
906+
for i in range(1, 3):
907+
host = "host%s" % i
908+
segment = self._test_create_segment(
909+
network_id=network_id, physical_network='physnet%s' % i,
910+
segmentation_id=200 + i, network_type=constants.TYPE_VLAN)
911+
self._register_agent(host, mappings={'physnet%s' % i: 'br-eth-1'},
912+
plugin=self.plugin)
913+
db.update_segment_host_mapping(
914+
ctx, host, {segment['segment']['id']})
915+
hosts.add(host)
916+
917+
# Now they are 2 hosts with segment being mapped.
918+
actual_hosts = db.get_hosts_mapped_with_segments(ctx)
919+
self.assertEqual(hosts, actual_hosts)
920+
921+
def test_get_all_hosts_mapped_with_segments_agent_type_filters(self):
922+
ctx = context.get_admin_context()
923+
with self.network() as network:
924+
network_id = network['network']['id']
925+
for i in range(1, 3):
926+
host = "host%s" % i
927+
segment = self._test_create_segment(
928+
network_id=network_id, physical_network='physnet%s' % i,
929+
segmentation_id=200 + i, network_type=constants.TYPE_VLAN)
930+
if i == 2:
931+
agent_type = self.agent_type_a
932+
else:
933+
agent_type = self.agent_type_b
934+
helpers.register_ovs_agent(
935+
host, agent_type=agent_type,
936+
bridge_mappings={'physnet%s' % i: 'br-eth-1'},
937+
plugin=self.plugin, start_flag=True)
938+
db.update_segment_host_mapping(
939+
ctx, host, {segment['segment']['id']})
940+
941+
# Now they are 2 hosts with segment being mapped.
942+
# host1 is agent_type_b
943+
# host2 is agent_type_a
944+
# get all hosts (host1 and host2) when not using any filtering
945+
actual_hosts = db.get_hosts_mapped_with_segments(ctx)
946+
self.assertEqual({"host1", "host2"}, actual_hosts)
947+
# get host1 when exclude agent_type_a agents
948+
actual_hosts = db.get_hosts_mapped_with_segments(
949+
ctx, exclude_agent_types={self.agent_type_a})
950+
self.assertEqual({"host1"}, actual_hosts)
951+
# get host2 when exclude agent_type_b agents
952+
actual_hosts = db.get_hosts_mapped_with_segments(
953+
ctx, exclude_agent_types={self.agent_type_b})
954+
self.assertEqual({"host2"}, actual_hosts)
955+
# get host2 when include agent_type_a agents
956+
actual_hosts = db.get_hosts_mapped_with_segments(
957+
ctx, include_agent_types={self.agent_type_a})
958+
self.assertEqual({"host2"}, actual_hosts)
959+
# get host1 when include agent_type_b agents
960+
actual_hosts = db.get_hosts_mapped_with_segments(
961+
ctx, include_agent_types={self.agent_type_b})
962+
self.assertEqual({"host1"}, actual_hosts)
963+
# get host1 and host2 when include both agent_type_a and agent_type_b
964+
actual_hosts = db.get_hosts_mapped_with_segments(
965+
ctx, include_agent_types={self.agent_type_b, self.agent_type_a})
966+
self.assertEqual({"host1", "host2"}, actual_hosts)
967+
# When using both include and exclude, exclude is most significant
968+
actual_hosts = db.get_hosts_mapped_with_segments(
969+
ctx,
970+
include_agent_types={self.agent_type_b, self.agent_type_a},
971+
exclude_agent_types={self.agent_type_b}
972+
)
973+
self.assertEqual({"host2"}, actual_hosts)
974+
# include and exclude both agent types - exclude is most significant
975+
actual_hosts = db.get_hosts_mapped_with_segments(
976+
ctx,
977+
include_agent_types={self.agent_type_b, self.agent_type_a},
978+
exclude_agent_types={self.agent_type_b, self.agent_type_a}
979+
)
980+
self.assertEqual(set(), actual_hosts)
981+
982+
def test_get_all_hosts_mapped_with_segments_agent_type_filter(self):
983+
ctx = context.get_admin_context()
984+
hosts = set()
985+
with self.network() as network:
986+
network_id = network['network']['id']
987+
for i in range(1, 3):
988+
host = "host%s" % i
989+
segment = self._test_create_segment(
990+
network_id=network_id, physical_network='physnet%s' % i,
991+
segmentation_id=200 + i, network_type=constants.TYPE_VLAN)
992+
self._register_agent(host, mappings={'physnet%s' % i: 'br-eth-1'},
993+
plugin=self.plugin)
994+
db.update_segment_host_mapping(
995+
ctx, host, {segment['segment']['id']})
996+
hosts.add(host)
997+
998+
# Now they are 2 hosts with segment being mapped.
999+
# host1 is agent_type_a
1000+
# host2 is agent_type_a
1001+
actual_hosts = db.get_hosts_mapped_with_segments(
1002+
ctx, exclude_agent_types={self.agent_type_a})
1003+
self.assertEqual(set(), actual_hosts)
1004+
actual_hosts = db.get_hosts_mapped_with_segments(
1005+
ctx, include_agent_types={self.agent_type_a})
1006+
self.assertEqual(hosts, actual_hosts)
1007+
8741008

8751009
class TestMl2HostSegmentMappingLinuxBridge(TestMl2HostSegmentMappingOVS):
8761010
_mechanism_drivers = ['linuxbridge', 'logger']
1011+
agent_type_a = constants.AGENT_TYPE_LINUXBRIDGE
1012+
agent_type_b = constants.AGENT_TYPE_OVS
8771013

8781014
def setUp(self, plugin=None):
8791015
cfg.CONF.set_override(c_experimental.EXPERIMENTAL_LINUXBRIDGE, True,
@@ -888,6 +1024,8 @@ def _register_agent(self, host, mappings=None, plugin=None):
8881024

8891025
class TestMl2HostSegmentMappingMacvtap(TestMl2HostSegmentMappingOVS):
8901026
_mechanism_drivers = ['macvtap', 'logger']
1027+
agent_type_a = constants.AGENT_TYPE_MACVTAP
1028+
agent_type_b = constants.AGENT_TYPE_OVS
8911029

8921030
def _register_agent(self, host, mappings=None, plugin=None):
8931031
helpers.register_macvtap_agent(host=host, interface_mappings=mappings,
@@ -896,6 +1034,8 @@ def _register_agent(self, host, mappings=None, plugin=None):
8961034

8971035
class TestMl2HostSegmentMappingSriovNicSwitch(TestMl2HostSegmentMappingOVS):
8981036
_mechanism_drivers = ['sriovnicswitch', 'logger']
1037+
agent_type_a = constants.AGENT_TYPE_NIC_SWITCH
1038+
agent_type_b = constants.AGENT_TYPE_OVS
8991039

9001040
def _register_agent(self, host, mappings=None, plugin=None):
9011041
helpers.register_sriovnicswitch_agent(host=host,

0 commit comments

Comments
 (0)