Handle OVS to OVN migration with neutron-gateway topologies
Merge two similar config set patterns into a common method. Add missing docstrings. Fix typos.
This commit is contained in:
@@ -40,12 +40,54 @@ class _OVNSetupHelper(test_utils.BaseCharmTest):
|
||||
return int(n_api_config['global-physnet-mtu']['value']) - (
|
||||
GENEVE_ENCAP_OVERHEAD + IP4_HEADER_SIZE)
|
||||
|
||||
def _configure_apps(self, apps, cfg,
|
||||
first_match_raise_if_none_found=False):
|
||||
"""Conditionally configure a set of applications.
|
||||
|
||||
:param apps: Applications.
|
||||
:type apps: Iterator[str]
|
||||
:param cfg: Configuration to apply.
|
||||
:type cfg: Dict[str,any]
|
||||
:param first_match_raise_if_none_found: When set the method will
|
||||
configure the first application
|
||||
it finds in the model and raise
|
||||
an exception if none are found.
|
||||
:type first_match_raise_if_none_found: bool
|
||||
:raises: RuntimeError
|
||||
"""
|
||||
for app in apps:
|
||||
try:
|
||||
zaza.model.get_application(app)
|
||||
for k, v in cfg.items():
|
||||
logging.info('Setting `{}` to "{}" on "{}"...'
|
||||
.format(k, v, app))
|
||||
with self.config_change(cfg, cfg, app):
|
||||
# The intent here is to change the config and not
|
||||
# restore it. We accomplish that by passing in the same
|
||||
# value for default and alternate.
|
||||
#
|
||||
# The reason for using the `config_change` helper for
|
||||
# this is that it already deals with all the
|
||||
# permutations of config already being set etc and does
|
||||
# not get into trouble if the test bundle already has
|
||||
# the values we try to set.
|
||||
if first_match_raise_if_none_found:
|
||||
break
|
||||
else:
|
||||
continue
|
||||
else:
|
||||
if first_match_raise_if_none_found:
|
||||
raise RuntimeError(
|
||||
'None of the expected apps ({}) are present in '
|
||||
'the model.'
|
||||
.format(apps)
|
||||
)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def configure_ngw_novs(self):
|
||||
"""Configure n-ovs and n-gw units."""
|
||||
cfg = {
|
||||
# To be able to successfully clean up after the Neutron agents we
|
||||
# need to use the 'openvswitch' `firewall-driver`.
|
||||
'firewall-driver': 'openvswitch',
|
||||
# To be able to have instances successfully survive the migration
|
||||
# without communication issues we need to lower the MTU announced
|
||||
# to instances prior to migration.
|
||||
@@ -59,25 +101,13 @@ class _OVNSetupHelper(test_utils.BaseCharmTest):
|
||||
'instance-mtu': self._get_instance_mtu_from_global_physnet_mtu()
|
||||
}
|
||||
apps = ('neutron-gateway', 'neutron-openvswitch')
|
||||
for app in apps:
|
||||
try:
|
||||
zaza.model.get_application(app)
|
||||
for k, v in cfg.items():
|
||||
logging.info('Setting `{}` to "{}" on "{}"...'
|
||||
.format(k, v, app))
|
||||
with self.config_change(cfg, cfg, app):
|
||||
# The intent here is to change the config and not restore
|
||||
# it. We accomplish that by passing in the same value for
|
||||
# default and alternate.
|
||||
#
|
||||
# The reason for using the `config_change` helper for this
|
||||
# is that it already deals with all the permutations of
|
||||
# config already being set etc and does not get into
|
||||
# trouble if the test bundle already have the values we try
|
||||
# to set.
|
||||
continue
|
||||
except KeyError:
|
||||
pass
|
||||
self._configure_apps(apps, cfg)
|
||||
cfg_ovs = {
|
||||
# To be able to successfully clean up after the Neutron agents we
|
||||
# need to use the 'openvswitch' `firewall-driver`.
|
||||
'firewall-driver': 'openvswitch',
|
||||
}
|
||||
self._configure_apps(('neutron-openvswitch',), cfg_ovs)
|
||||
|
||||
def configure_ovn_mappings(self):
|
||||
"""Copy mappings from n-gw or n-ovs application."""
|
||||
@@ -102,23 +132,8 @@ class _OVNSetupHelper(test_utils.BaseCharmTest):
|
||||
.format(src_apps)
|
||||
)
|
||||
|
||||
for app in dst_apps:
|
||||
try:
|
||||
zaza.model.get_application(app)
|
||||
for k, v in ovn_cfg.items():
|
||||
logging.info('Setting `{}` to "{}" on "{}"...'
|
||||
.format(k, v, app))
|
||||
with self.config_change(ovn_cfg, ovn_cfg, app):
|
||||
# Set values only on ovn-dedicated-chassis when present,
|
||||
# otherwise we set them on ovn-chassis.
|
||||
break
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
raise RuntimeError(
|
||||
'None of the expected apps ({}) are present in the model.'
|
||||
.format(dst_apps)
|
||||
)
|
||||
self._configure_apps(
|
||||
dst_apps, ovn_cfg, first_match_raise_if_none_found=True)
|
||||
|
||||
|
||||
def pre_migration_configuration():
|
||||
|
||||
@@ -84,7 +84,7 @@ class OVSOVNMigrationTest(test_utils.BaseCharmTest):
|
||||
def setUp(self):
|
||||
"""Perform migration steps prior to validation."""
|
||||
super(OVSOVNMigrationTest, self).setUp()
|
||||
# These steps here due to them having to be executed once and in a
|
||||
# These steps are here due to them having to be executed once and in a
|
||||
# specific order prior to running any tests. The steps should still
|
||||
# be idempotent if at all possible as a courtesy to anyone iterating
|
||||
# on the test code.
|
||||
@@ -104,6 +104,11 @@ class OVSOVNMigrationTest(test_utils.BaseCharmTest):
|
||||
|
||||
# Stop Neutron agents on hypervisors
|
||||
self._pause_units('neutron-openvswitch')
|
||||
try:
|
||||
self._pause_units('neutron-gateway')
|
||||
except KeyError:
|
||||
logging.info(
|
||||
'No neutron-gateway in deployment, skip pausing it.')
|
||||
|
||||
# Add the neutron-api-plugin-ovn subordinate which will make the
|
||||
# `neutron-api-plugin-ovn` unit appear in the deployment.
|
||||
@@ -155,7 +160,13 @@ class OVSOVNMigrationTest(test_utils.BaseCharmTest):
|
||||
self._resume_units('neutron-api')
|
||||
|
||||
# Run `cleanup` action on neutron-openvswitch units/hypervisors
|
||||
self._run_cleanup_action()
|
||||
self._run_cleanup_action('neutron-openvswitch')
|
||||
# Run `cleanup` action on neutron-gateway units when present
|
||||
try:
|
||||
self._run_cleanup_action('neutron-gateway')
|
||||
except KeyError:
|
||||
logging.info(
|
||||
'No neutron-gateway in deployment, skip cleanup of it.')
|
||||
|
||||
# Start the OVN controller on hypervisors
|
||||
#
|
||||
@@ -164,11 +175,18 @@ class OVSOVNMigrationTest(test_utils.BaseCharmTest):
|
||||
# you will program the network to a state of infinite loop.
|
||||
self._resume_units('ovn-chassis')
|
||||
|
||||
try:
|
||||
self._resume_units('ovn-dedicated-chassis')
|
||||
except KeyError:
|
||||
logging.info(
|
||||
'No ovn-dedicated-chassis in deployment, skip resume.')
|
||||
|
||||
# And we should be off to the races
|
||||
|
||||
self.one_time_init_done = True
|
||||
|
||||
def _add_neutron_api_plugin_ovn_subordinate_relation(self):
|
||||
"""Add relation between neutron-api and neutron-api-plugin-ovn."""
|
||||
try:
|
||||
logging.info('Adding relation neutron-api-plugin-ovn '
|
||||
'-> neutron-api')
|
||||
@@ -200,6 +218,7 @@ class OVSOVNMigrationTest(test_utils.BaseCharmTest):
|
||||
logging.info('done')
|
||||
|
||||
def _run_offline_neutron_morph_db_action(self):
|
||||
"""Run offline-neutron-morph-db action."""
|
||||
logging.info('Running the optional `offline-neutron-morph-db` action '
|
||||
'on neutron-api-plugin-ovn/leader')
|
||||
generic_utils.assertActionRanOK(
|
||||
@@ -213,6 +232,7 @@ class OVSOVNMigrationTest(test_utils.BaseCharmTest):
|
||||
)
|
||||
|
||||
def _run_migrate_ovn_db_action(self):
|
||||
"""Run migrate-ovn-db action."""
|
||||
logging.info('Running `migrate-ovn-db` action on '
|
||||
'neutron-api-plugin-ovn/leader')
|
||||
generic_utils.assertActionRanOK(
|
||||
@@ -230,6 +250,14 @@ class OVSOVNMigrationTest(test_utils.BaseCharmTest):
|
||||
@tenacity.retry(wait=tenacity.wait_exponential(min=5, max=60),
|
||||
reraise=True, stop=tenacity.stop_after_attempt(3))
|
||||
def _run_migrate_mtu_action(self):
|
||||
"""Run migrate-mtu action with retry.
|
||||
|
||||
The action is idempotent.
|
||||
|
||||
Due to LP: #1854518 and the point in time of the test life cycle we run
|
||||
this action the probability for the Neutron API not being available
|
||||
for the script to do its job is high, thus we retry.
|
||||
"""
|
||||
logging.info('Running `migrate-mtu` action on '
|
||||
'neutron-api-plugin-ovn/leader')
|
||||
generic_utils.assertActionRanOK(
|
||||
@@ -243,6 +271,11 @@ class OVSOVNMigrationTest(test_utils.BaseCharmTest):
|
||||
)
|
||||
|
||||
def _pause_units(self, application):
|
||||
"""Pause units of application.
|
||||
|
||||
:param application: Name of application
|
||||
:type application: str
|
||||
"""
|
||||
logging.info('Pausing {} units'.format(application))
|
||||
zaza.model.run_action_on_units(
|
||||
[unit.entity_id
|
||||
@@ -259,11 +292,17 @@ class OVSOVNMigrationTest(test_utils.BaseCharmTest):
|
||||
},
|
||||
)
|
||||
|
||||
def _run_cleanup_action(self):
|
||||
logging.info('Running `cleanup` action on neutron-openvswitch units.')
|
||||
def _run_cleanup_action(self, application):
|
||||
"""Run cleanup action on application units.
|
||||
|
||||
:param application: Name of application
|
||||
:type application: str
|
||||
"""
|
||||
logging.info('Running `cleanup` action on {} units.'
|
||||
.format(application))
|
||||
zaza.model.run_action_on_units(
|
||||
[unit.entity_id
|
||||
for unit in zaza.model.get_units('neutron-openvswitch')],
|
||||
for unit in zaza.model.get_units(application)],
|
||||
'cleanup',
|
||||
action_params={
|
||||
'i-really-mean-it': True},
|
||||
@@ -271,6 +310,11 @@ class OVSOVNMigrationTest(test_utils.BaseCharmTest):
|
||||
)
|
||||
|
||||
def _resume_units(self, application):
|
||||
"""Resume units of application.
|
||||
|
||||
:param application: Name of application
|
||||
:type application: str
|
||||
"""
|
||||
logging.info('Resuming {} units'.format(application))
|
||||
zaza.model.run_action_on_units(
|
||||
[unit.entity_id
|
||||
|
||||
Reference in New Issue
Block a user