Browse Source

Attempt the migration to Port Groups from Maintenance worker

The migration to port groups task is now moved to the maintenance
worker. This worker holds a distributed lock within OVSDB so we'll
make sure that the migration will be performed just once.

During an update/upgrade, it may happen that newer version of
neutron-server can't migrate to Port Groups as the lock is held
by other (old instance). When all servers have been updated, the
maintenance task will perform the migration just once on the cloud
making sure that normal operation will happen.

We can remove this task in later cycles as this is just a migration
path from Address Sets to Port Groups for implementing Neutron
Security Groups.

TODO: functional test to validate the migration path to PGs.

Change-Id: I227ec967f450b26b12f19d687e94029e6ef1e558
Closes-Bug: #1789921
Signed-off-by: Daniel Alvarez <dalvarez@redhat.com>
changes/39/598239/7
Daniel Alvarez 4 years ago
parent
commit
17b15f2901
  1. 28
      networking_ovn/common/maintenance.py
  2. 6
      networking_ovn/ovn_db_sync.py
  3. 54
      networking_ovn/tests/unit/common/test_maintenance.py

28
networking_ovn/common/maintenance.py

@ -27,6 +27,7 @@ from oslo_utils import timeutils
from networking_ovn.common import constants as ovn_const
from networking_ovn.db import maintenance as db_maint
from networking_ovn.db import revision as db_rev
from networking_ovn import ovn_db_sync
LOG = log.getLogger(__name__)
@ -216,6 +217,33 @@ class DBInconsistenciesPeriodics(object):
else:
self._ovn_client.update_subnet(sn_db_obj, n_db_obj)
# The migration will run just once per neutron-server instance. If the lock
# is held by some other neutron-server instance in the cloud, we'll attempt
# to perform the migration every 10 seconds until completed.
@periodics.periodic(spacing=10, run_immediately=True)
def migrate_to_port_groups(self):
"""Perform the migration from Address Sets to Port Groups. """
# TODO(dalvarez): Remove this in U cycle when we're sure that all
# versions are running using Port Groups (and OVS >= 2.10).
# If Port Groups are not supported or we've already migrated, we don't
# need to attempt to migrate again.
if (not self._nb_idl.is_port_groups_supported() or
not self._nb_idl.get_address_sets()):
raise periodics.NeverAgain()
# Only the worker holding a valid lock within OVSDB will perform the
# migration.
if not self.has_lock:
return
admin_context = n_context.get_admin_context()
nb_sync = ovn_db_sync.OvnNbSynchronizer(
self._ovn_client._plugin, self._nb_idl, self._ovn_client._sb_idl,
None, None)
nb_sync.migrate_to_port_groups(admin_context)
raise periodics.NeverAgain()
@periodics.periodic(spacing=DB_CONSISTENCY_CHECK_INTERVAL,
run_immediately=True)
def check_for_inconsistencies(self):

6
networking_ovn/ovn_db_sync.py

@ -86,7 +86,6 @@ class OvnNbSynchronizer(OvnDbSynchronizer):
LOG.debug("Starting OVN-Northbound DB sync process")
ctx = context.get_admin_context()
self.migrate_to_port_groups(ctx)
self.sync_address_sets(ctx)
self.sync_networks_ports_and_dhcp_opts(ctx)
@ -992,7 +991,10 @@ class OvnNbSynchronizer(OvnDbSynchronizer):
# 3. Delete all existing Address Sets in NorthBound database which
# correspond to a Neutron Security Group.
# 4. Delete all the ACLs in every Logical Switch (Neutron network).
if not self.ovn_api.is_port_groups_supported():
# If Port Groups are not supported or we've already migrated, return
if (not self.ovn_api.is_port_groups_supported() or
not self.ovn_api.get_address_sets()):
return
LOG.debug('Port Groups Migration task started')

54
networking_ovn/tests/unit/common/test_maintenance.py

@ -15,6 +15,7 @@
import mock
from futurist import periodics
from neutron.tests.unit.plugins.ml2 import test_security_group as test_sg
from neutron_lib.db import api as db_api
@ -23,11 +24,12 @@ from networking_ovn.common import maintenance
from networking_ovn.common import utils
from networking_ovn.db import maintenance as db_maint
from networking_ovn.db import revision as db_rev
from networking_ovn import ovn_db_sync
from networking_ovn.tests.unit.db import base as db_base
@mock.patch.object(maintenance.DBInconsistenciesPeriodics,
'has_lock', lambda _: True)
'has_lock', mock.PropertyMock(return_value=True))
class TestDBInconsistenciesPeriodics(db_base.DBTestCase,
test_sg.Ml2SecurityGroupsTestCase):
@ -51,6 +53,56 @@ class TestDBInconsistenciesPeriodics(db_base.DBTestCase,
self.periodic.check_for_inconsistencies()
mock_fix_net.assert_called_once_with(fake_row)
def _test_migrate_to_port_groups_helper(self, pg_supported, a_sets,
migration_expected, never_again):
self.fake_ovn_client._nb_idl.is_port_groups_supported.return_value = (
pg_supported)
self.fake_ovn_client._nb_idl.get_address_sets.return_value = a_sets
with mock.patch.object(ovn_db_sync.OvnNbSynchronizer,
'migrate_to_port_groups') as mtpg:
if never_again:
self.assertRaises(periodics.NeverAgain,
self.periodic.migrate_to_port_groups)
else:
self.periodic.migrate_to_port_groups()
if migration_expected:
mtpg.assert_called_once()
else:
mtpg.assert_not_called()
def test_migrate_to_port_groups_port_groups_not_supported(self):
self._test_migrate_to_port_groups_helper(pg_supported=False,
a_sets=None,
migration_expected=False,
never_again=True)
def test_migrate_to_port_groups_not_needed(self):
self._test_migrate_to_port_groups_helper(pg_supported=True,
a_sets=None,
migration_expected=False,
never_again=True)
def test_migrate_to_port_groups(self):
# Check normal migration path: if port groups are supported by the
# schema and the migration has to be done, it will take place and
# won't be attempted in the future.
self._test_migrate_to_port_groups_helper(pg_supported=True,
a_sets=['as1', 'as2'],
migration_expected=True,
never_again=True)
def test_migrate_to_port_groups_no_lock(self):
with mock.patch.object(maintenance.DBInconsistenciesPeriodics,
'has_lock', mock.PropertyMock(
return_value=False)):
# Check that if this worker doesn't have the lock, it won't
# perform the migration and it will try again later.
self._test_migrate_to_port_groups_helper(pg_supported=True,
a_sets=['as1', 'as2'],
migration_expected=False,
never_again=False)
def _test_fix_create_update_network(self, ovn_rev, neutron_rev):
self.net['revision_number'] = neutron_rev

Loading…
Cancel
Save