Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions neutron/agent/ovn/extensions/qos_hwol.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class OVSInterfaceEvent(row_event.RowEvent):

def __init__(self, ovn_agent):
self.ovn_agent = ovn_agent
events = (self.ROW_CREATE, self.ROW_DELETE)
events = (self.ROW_CREATE, self.ROW_UPDATE, self.ROW_DELETE)
table = 'Interface'
super().__init__(events, table, None)

Expand All @@ -58,7 +58,7 @@ def match_fn(self, event, row, old):
return True

def run(self, event, row, old):
if event == self.ROW_CREATE:
if event in (self.ROW_CREATE, self.ROW_UPDATE):
self.ovn_agent.qos_hwol_ext.add_port(
row.external_ids['iface-id'], row.name)
elif event == self.ROW_DELETE:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1353,7 +1353,8 @@ def sync_hostname_and_physical_networks(self, ctx):
LOG.debug('OVN-SB Sync hostname and physical networks started')
host_phynets_map = self.ovn_api.get_chassis_hostname_and_physnets()
current_hosts = set(host_phynets_map)
previous_hosts = segments_db.get_hosts_mapped_with_segments(ctx)
previous_hosts = segments_db.get_hosts_mapped_with_segments(
ctx, include_agent_types={ovn_const.OVN_CONTROLLER_AGENT})

stale_hosts = previous_hosts - current_hosts
for host in stale_hosts:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -908,7 +908,9 @@ def _verify_lb(test, protocol, vip_ext_port, vip_int_port):
pf_def.INTERNAL_IP_ADDRESS: p1_ip}
pf_obj = self.pf_plugin.create_floatingip_port_forwarding(
self.context, fip_id, **fip_attrs(fip_pf_args))
m_publish.assert_called_once()
call = mock.call('port_forwarding', 'after_create', self.pf_plugin,
payload=mock.ANY)
m_publish.assert_has_calls([call])

# Assert load balancer for port forwarding was not created
self.assertFalse(self._find_pf_lb(router_id, fip_id))
Expand All @@ -926,7 +928,9 @@ def _verify_lb(test, protocol, vip_ext_port, vip_int_port):
m_publish.reset_mock()
self.pf_plugin.update_floatingip_port_forwarding(
self.context, pf_obj['id'], fip_id, **fip_attrs(fip_pf_args))
m_publish.assert_called_once()
call = mock.call('port_forwarding', 'after_update', self.pf_plugin,
payload=mock.ANY)
m_publish.assert_has_calls([call])

# Assert load balancer for port forwarding is stale
_verify_lb(self, 'tcp', 2222, 22)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1818,6 +1818,22 @@ def setUp(self):
def _sync_resources(self):
self.sb_synchronizer.sync_hostname_and_physical_networks(self.ctx)

def create_agent(self, host, bridge_mappings=None, agent_type=None):
if agent_type is None:
agent_type = ovn_const.OVN_CONTROLLER_AGENT
if bridge_mappings is None:
bridge_mappings = {}
agent = {
'host': host,
'agent_type': agent_type,
'binary': '/bin/test',
'topic': 'test_topic',
'configurations': {'bridge_mappings': bridge_mappings}
}
_, status = self.plugin.create_or_update_agent(self.context, agent)

return status['id']

def create_segment(self, network_id, physical_network, segmentation_id):
segment_data = {'network_id': network_id,
'physical_network': physical_network,
Expand Down Expand Up @@ -1858,6 +1874,7 @@ def test_ovn_sb_sync_delete_stale_host(self):
segment = self.create_segment(network_id, 'physnet1', 50)
segments_db.update_segment_host_mapping(
self.ctx, 'host1', {segment['id']})
_ = self.create_agent('host1', bridge_mappings={'physnet1': 'eth0'})
segment_hosts = segments_db.get_hosts_mapped_with_segments(self.ctx)
self.assertEqual({'host1'}, segment_hosts)
# Since there is no chassis in the sb DB, host1 is the stale host
Expand All @@ -1866,6 +1883,36 @@ def test_ovn_sb_sync_delete_stale_host(self):
segment_hosts = segments_db.get_hosts_mapped_with_segments(self.ctx)
self.assertFalse(segment_hosts)

def test_ovn_sb_sync_host_with_no_agent_not_deleted(self):
with self.network() as network:
network_id = network['network']['id']
segment = self.create_segment(network_id, 'physnet1', 50)
segments_db.update_segment_host_mapping(
self.ctx, 'host1', {segment['id']})
_ = self.create_agent('host1', bridge_mappings={'physnet1': 'eth0'},
agent_type="Not OVN Agent")
segment_hosts = segments_db.get_hosts_mapped_with_segments(self.ctx)
self.assertEqual({'host1'}, segment_hosts)
# There is no chassis in the sb DB, host1 does not have an agent
# so it is not deleted.
self._sync_resources()
segment_hosts = segments_db.get_hosts_mapped_with_segments(self.ctx)
self.assertEqual({'host1'}, segment_hosts)

def test_ovn_sb_sync_host_with_other_agent_type_not_deleted(self):
with self.network() as network:
network_id = network['network']['id']
segment = self.create_segment(network_id, 'physnet1', 50)
segments_db.update_segment_host_mapping(
self.ctx, 'host1', {segment['id']})
segment_hosts = segments_db.get_hosts_mapped_with_segments(self.ctx)
self.assertEqual({'host1'}, segment_hosts)
# There is no chassis in the sb DB, host1 does not have an agent
# so it is not deleted.
self._sync_resources()
segment_hosts = segments_db.get_hosts_mapped_with_segments(self.ctx)
self.assertEqual({'host1'}, segment_hosts)

def test_ovn_sb_sync(self):
with self.network() as network:
network_id = network['network']['id']
Expand All @@ -1878,6 +1925,9 @@ def test_ovn_sb_sync(self):
segments_db.update_segment_host_mapping(
self.ctx, 'host3', {seg1['id']})
segment_hosts = segments_db.get_hosts_mapped_with_segments(self.ctx)
_ = self.create_agent('host1')
_ = self.create_agent('host2', bridge_mappings={'physnet2': 'eth0'})
_ = self.create_agent('host3', bridge_mappings={'physnet3': 'eth0'})
self.assertEqual({'host1', 'host2', 'host3'}, segment_hosts)
self.add_fake_chassis('host2', ['physnet2'])
self.add_fake_chassis('host3', ['physnet3'])
Expand Down
29 changes: 16 additions & 13 deletions neutron/tests/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import fixtures
import netaddr
from neutron_lib.callbacks import priority_group
from neutron_lib import constants
from neutron_lib.services.logapi import constants as log_const
from neutron_lib.utils import helpers
Expand All @@ -27,15 +28,15 @@
from oslo_utils import timeutils


# NOTE(yamahata): from neutron-lib 1.9.1, callback priority was added and
# priority_group module was added for constants of priority.
# test the existence of the module of priority_group to check if
# callback priority is supported or not.
_CALLBACK_PRIORITY_SUPPORTED = True
# NOTE(ykarel): from neutron-lib 3.9.0, cancellable flag was added
# test the existence of the is_cancellable_event function to check if
# cancellable flag is supported or not. This compatibility check can
# be removed once neutron-lib >= 3.9.0 in requirements.txt.
_CANCELLABLE_FLAG_SUPPORTED = True
try:
from neutron_lib.callbacks import priority_group # noqa
from neutron_lib.callbacks.events import is_cancellable_event # noqa
except ImportError:
_CALLBACK_PRIORITY_SUPPORTED = False
_CANCELLABLE_FLAG_SUPPORTED = False

LAST_RANDOM_PORT_RANGE_GENERATED = 1

Expand Down Expand Up @@ -146,12 +147,14 @@ def make_mock_plugin_json_encodable(plugin_instance_mock):


def get_subscribe_args(*args):
# NOTE(yamahata): from neutron-lib 1.9.1, callback priority was added.
# old signature: (callback, resource, event)
# new signature: (callback, resource, event, priority=PRIORITY_DEFAULT)
if len(args) == 3 and _CALLBACK_PRIORITY_SUPPORTED:
args = list(args) # don't modify original list
args.append(priority_group.PRIORITY_DEFAULT)
args = list(args) # don't modify original list
args.append(priority_group.PRIORITY_DEFAULT)
# NOTE(ykarel): from neutron-lib 3.9.0, cancellable flag was added.
# old signature: (callback, resource, event, priority=PRIORITY_DEFAULT)
# new signature: (callback, resource, event, priority=PRIORITY_DEFAULT,
# cancellable=False)
if len(args) == 4 and _CANCELLABLE_FLAG_SUPPORTED:
args.append(False)
return args


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1169,8 +1169,10 @@ def test_ovn_sb_sync(self):

with mock.patch.object(ovn_db_sync.segments_db,
'get_hosts_mapped_with_segments',
return_value=hosts_in_neutron):
return_value=hosts_in_neutron) as mock_ghmws:
ovn_sb_synchronizer.sync_hostname_and_physical_networks(mock.ANY)
mock_ghmws.assert_called_once_with(
mock.ANY, include_agent_types={ovn_const.OVN_CONTROLLER_AGENT})
all_hosts = set(hostname_with_physnets.keys()) | hosts_in_neutron
self.assertEqual(
len(all_hosts),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
fixes:
- |
When synchronizing the OVN databases, either when running the migration
command or during startup, the code responsible for synchronization will
only clean up segment-to-host mappings for hosts with agent_type
``OVN Controller agent``. Before, the synchronization would clean up
(delete) segment-to-host mappings for non-OVN hosts. Fixes bug:
`2040172 <https://bugs.launchpad.net/neutron/+bug/2040172>`_.