Enable Ussuri and Focal

Make db migration optional and Train only and update OVN service
plugin entry point for Ussuri.

Add tactical workaround for LP: #1864640

To allow running lint on a Python 3.8 system (Focal), unpin
flake8.

Clean up test-requirements.txt and mock out dependencies rather
than installing them in the unit test virtualenv.

Func-Test-Pr: https://github.com/openstack-charmers/zaza-openstack-tests/pull/187
Change-Id: I8d291e35b1bc52332c4666584277eb41c88ef084
This commit is contained in:
Frode Nordahl 2020-01-27 15:30:47 +01:00 committed by Frode Nordahl
parent b24d1fc8fd
commit 6b70923679
No known key found for this signature in database
GPG Key ID: 6A5D59A3BA48373F
18 changed files with 343 additions and 77 deletions

View File

@ -23,30 +23,64 @@ NEUTRON_PLUGIN_ML2_DIR = '/etc/neutron/plugins/ml2'
@charms_openstack.adapters.config_property
def ovn_key(cls):
"""Get path of TLS key file.
:param cls: charms_openstack.adapters.ConfigurationAdapter derived class
instance. Charm class instance is at cls.charm_instance.
:type: cls: charms_openstack.adapters.ConfiguartionAdapter
:returns: Path to OVN TLS key file
:rtype: str
"""
return os.path.join(NEUTRON_PLUGIN_ML2_DIR, 'key_host')
@charms_openstack.adapters.config_property
def ovn_cert(cls):
"""Get path of TLS certificate file.
:param cls: charms_openstack.adapters.ConfigurationAdapter derived class
instance. Charm class instance is at cls.charm_instance.
:type: cls: charms_openstack.adapters.ConfiguartionAdapter
:returns: Path to OVN TLS certificate file
:rtype: str
"""
return os.path.join(NEUTRON_PLUGIN_ML2_DIR, 'cert_host')
@charms_openstack.adapters.config_property
def ovn_ca_cert(cls):
"""Get path of TLS key file.
:param cls: charms_openstack.adapters.ConfigurationAdapter derived class
instance. Charm class instance is at cls.charm_instance.
:type: cls: charms_openstack.adapters.ConfiguartionAdapter
:returns: Path to OVN TLS CA certificate file
:rtype: str
"""
return os.path.join(NEUTRON_PLUGIN_ML2_DIR,
'{}.crt'.format(cls.charm_instance.name))
class NeutronAPIPluginCharm(charms_openstack.charm.OpenStackCharm):
release = 'train'
class BaseNeutronAPIPluginCharm(charms_openstack.charm.OpenStackCharm):
abstract_class = True
name = 'neutron-api-plugin-ovn'
packages = ['python3-networking-ovn']
required_relations = ['neutron-plugin', 'ovsdb-cms']
python_version = 3
release_pkg = version_package = 'neutron-common'
# make sure we can write secrets readable by the ``neutron-server`` process
group = 'neutron'
db_migration_needed = False
service_plugins = []
def configure_tls(self, certificates_interface=None):
"""Override configure_tls method for neutron-api-plugin-ovn.
See parent method for parameter documentation.
The charm inherits from ``OpenStackCharm`` class which only writes
the CA to disk. We need to implement a handler for the layout of certs
suitable for this charms payload.
"""
tls_objects = self.get_certs_and_keys(
certificates_interface=certificates_interface)
@ -62,3 +96,52 @@ class NeutronAPIPluginCharm(charms_openstack.charm.OpenStackCharm):
tls_object['cert'],
tls_object['key'],
cn='host')
@property
def db_migration_needed(self):
"""Determine whether DB migration is needed.
The returned variable must be set in the release specifc charm classes.
:returns: Whether DB migration is needed.
:rtype: bool
"""
return self.db_migration_needed
@property
def service_plugins(self):
"""Provide list of service plugins for current OpenStack release.
The returned variable must be set in the release specifc charm classes.
:returns: List of service plugins
:rtype: List
"""
return self.service_plugins
class TrainNeutronAPIPluginCharm(BaseNeutronAPIPluginCharm):
"""The Train incarnation of the charm."""
release = 'train'
packages = ['python3-networking-ovn']
db_migration_needed = True
service_plugins = ['networking_ovn.l3.l3_ovn.OVNL3RouterPlugin']
class UssuriNeutronAPIPluginCharm(BaseNeutronAPIPluginCharm):
"""The Ussuri incarnation of the charm.
The separate ``networking-ovn`` package has been removed and has been
merged into Neutron upstream.
It is still useful to handle the configuration and relations specific to
OVN in a subordinate charm.
"""
release = 'ussuri'
packages = []
db_migration_needed = False
service_plugins = ['ovn-router']
def install(self):
"""We no longer need to install anything."""
pass

View File

@ -10,6 +10,7 @@ tags:
series:
- bionic
- eoan
- focal
subordinate: true
requires:
container:

View File

@ -26,6 +26,7 @@ charms_openstack.bus.discover()
charm.use_defaults(
'charm.installed',
'config.changed',
'charm.default-select-release',
'update-status',
'upgrade-charm',
'certificates.available',
@ -35,15 +36,19 @@ charm.use_defaults(
@reactive.when_none('neutron-plugin.db_migration',
'neutron-plugin.available')
@reactive.when('charm.installed')
def flag_db_migration():
reactive.set_flag('neutron-plugin.db_migration')
def maybe_flag_db_migration():
with charm.provide_charm_instance() as instance:
if instance.db_migration_needed:
reactive.set_flag('neutron-plugin.db_migration')
@reactive.when_none('neutron-plugin.available', 'run-default-update-status')
@reactive.when('neutron-plugin.connected')
def request_db_migration():
def maybe_request_db_migration():
neutron = reactive.endpoint_from_flag('neutron-plugin.connected')
neutron.request_db_migration()
with charm.provide_charm_instance() as instance:
if instance.db_migration_needed:
neutron.request_db_migration()
@reactive.when('neutron-plugin.connected', 'ovsdb-cms.available')
@ -57,7 +62,6 @@ def configure_neutron():
service_plugins = neutron.neutron_config_data.get(
'service_plugins', '').split(',')
service_plugins = [svc for svc in service_plugins if svc not in ['router']]
service_plugins.append('networking_ovn.l3.l3_ovn.OVNL3RouterPlugin')
tenant_network_types = neutron.neutron_config_data.get(
'tenant_network_types', '').split(',')
tenant_network_types.insert(0, 'geneve')
@ -67,6 +71,7 @@ def configure_neutron():
return _s.split()
with charm.provide_charm_instance() as instance:
service_plugins.extend(instance.service_plugins)
options = instance.adapters_instance.options
sections = {
'ovn': [
@ -74,7 +79,11 @@ def configure_neutron():
('ovn_nb_private_key', options.ovn_key),
('ovn_nb_certificate', options.ovn_cert),
('ovn_nb_ca_cert', options.ovn_ca_cert),
('ovn_sb_connection', ','.join(ovsdb.db_sb_connection_strs)),
# NOTE(fnordahl): Tactical workaround for LP: #1864640
('ovn_sb_connection', ','.join(
ovsdb.db_connection_strs(
ovsdb.cluster_remote_addrs,
ovsdb.db_sb_port + 10000))),
('ovn_sb_private_key', options.ovn_key),
('ovn_sb_certificate', options.ovn_cert),
('ovn_sb_ca_cert', options.ovn_ca_cert),
@ -111,16 +120,3 @@ def configure_neutron():
},
)
instance.assess_status()
@reactive.when('neutron-plugin.available')
def assess_status():
with charm.provide_charm_instance() as instance:
instance.assess_status()
@reactive.when('ovsdb-cms.available')
def poke_ovsdb():
ovsdb = reactive.endpoint_from_flag('ovsdb-cms.available')
ch_core.hookenv.log('DEBUG: cluster_remote_addrs="{}"'
.format(list(ovsdb.cluster_remote_addrs)))

View File

@ -8,11 +8,14 @@ applications:
mysql:
charm: cs:~openstack-charmers-next/percona-cluster
num_units: 1
hacluster-neutron-api:
charm: cs:~openstack-charmers-next/hacluster
neutron-api:
charm: cs:~openstack-charmers-next/neutron-api
num_units: 3
options:
manage-neutron-plugin-legacy-mode: false
neutron-security-groups: true
openstack-origin: cloud:bionic-train
neutron-api-plugin-ovn:
series: bionic
@ -51,3 +54,5 @@ relations:
- vault:certificates
- - neutron-api:certificates
- vault:certificates
- - hacluster-neutron-api:ha
- neutron-api:ha

View File

@ -0,0 +1,58 @@
series: bionic
applications:
keystone:
charm: cs:~openstack-charmers-next/keystone
num_units: 1
options:
openstack-origin: cloud:bionic-ussuri/proposed
mysql:
charm: cs:~openstack-charmers-next/percona-cluster
num_units: 1
hacluster-neutron-api:
charm: cs:~openstack-charmers-next/hacluster
neutron-api:
charm: cs:~openstack-charmers-next/neutron-api
num_units: 3
options:
manage-neutron-plugin-legacy-mode: false
neutron-security-groups: true
openstack-origin: cloud:bionic-ussuri/proposed
neutron-api-plugin-ovn:
series: bionic
charm: cs:~openstack-charmers-next/neutron-api-plugin-ovn
rabbitmq-server:
charm: cs:~openstack-charmers-next/rabbitmq-server
num_units: 1
vault:
charm: cs:~openstack-charmers-next/vault
num_units: 1
ovn-central:
charm: cs:~openstack-charmers-next/ovn-central
num_units: 3
options:
source: cloud:bionic-ussuri/proposed
relations:
- - mysql:shared-db
- keystone:shared-db
- - mysql:shared-db
- neutron-api:shared-db
- - neutron-api:amqp
- rabbitmq-server:amqp
- - neutron-api:identity-service
- keystone:identity-service
- - neutron-api-plugin-ovn:neutron-plugin
- neutron-api:neutron-plugin-api-subordinate
- - neutron-api-plugin-ovn:ovsdb-cms
- ovn-central:ovsdb-cms
- - vault:shared-db
- mysql:shared-db
- - ovn-central:certificates
- vault:certificates
- - neutron-api-plugin-ovn:certificates
- vault:certificates
- - keystone:certificates
- vault:certificates
- - neutron-api:certificates
- vault:certificates
- - hacluster-neutron-api:ha
- neutron-api:ha

View File

@ -1,18 +1,25 @@
series: eoan
applications:
keystone-mysql-router:
charm: cs:~openstack-charmers-next/mysql-router
keystone:
charm: cs:~openstack-charmers-next/keystone
num_units: 1
options:
openstack-origin: distro
mysql:
mysql-innodb-cluster:
charm: cs:~openstack-charmers-next/mysql-innodb-cluster
num_units: 3
neutron-mysql-router:
charm: cs:~openstack-charmers-next/mysql-router
hacluster-neutron-api:
charm: cs:~openstack-charmers-next/hacluster
neutron-api:
charm: cs:~openstack-charmers-next/neutron-api
num_units: 3
options:
manage-neutron-plugin-legacy-mode: false
neutron-security-groups: true
openstack-origin: distro
neutron-api-plugin-ovn:
series: eoan
@ -20,6 +27,8 @@ applications:
rabbitmq-server:
charm: cs:~openstack-charmers-next/rabbitmq-server
num_units: 1
vault-mysql-router:
charm: cs:~openstack-charmers-next/mysql-router
vault:
charm: cs:~openstack-charmers-next/vault
num_units: 1
@ -29,10 +38,18 @@ applications:
options:
source: distro
relations:
- - mysql:shared-db
- keystone:shared-db
- - mysql:shared-db
- neutron-api:shared-db
- - keystone:shared-db
- keystone-mysql-router:shared-db
- - neutron-api:shared-db
- neutron-mysql-router:shared-db
- - vault:shared-db
- vault-mysql-router:shared-db
- - keystone-mysql-router:db-router
- mysql-innodb-cluster:db-router
- - neutron-mysql-router:db-router
- mysql-innodb-cluster:db-router
- - vault-mysql-router:db-router
- mysql-innodb-cluster:db-router
- - neutron-api:amqp
- rabbitmq-server:amqp
- - neutron-api:identity-service
@ -41,8 +58,6 @@ relations:
- neutron-api:neutron-plugin-api-subordinate
- - neutron-api-plugin-ovn:ovsdb-cms
- ovn-central:ovsdb-cms
- - vault:shared-db
- mysql:shared-db
- - ovn-central:certificates
- vault:certificates
- - neutron-api-plugin-ovn:certificates
@ -51,3 +66,5 @@ relations:
- vault:certificates
- - neutron-api:certificates
- vault:certificates
- - hacluster-neutron-api:ha
- neutron-api:ha

View File

@ -0,0 +1,70 @@
series: focal
applications:
keystone-mysql-router:
charm: cs:~openstack-charmers-next/mysql-router
keystone:
charm: cs:~openstack-charmers-next/keystone
num_units: 1
options:
openstack-origin: distro
mysql-innodb-cluster:
charm: cs:~openstack-charmers-next/mysql-innodb-cluster
num_units: 3
neutron-mysql-router:
charm: cs:~openstack-charmers-next/mysql-router
hacluster-neutron-api:
charm: cs:~openstack-charmers-next/hacluster
neutron-api:
charm: cs:~openstack-charmers-next/neutron-api
num_units: 3
options:
manage-neutron-plugin-legacy-mode: false
neutron-security-groups: true
openstack-origin: distro
neutron-api-plugin-ovn:
series: focal
charm: cs:~openstack-charmers-next/neutron-api-plugin-ovn
rabbitmq-server:
charm: cs:~openstack-charmers-next/rabbitmq-server
num_units: 1
vault-mysql-router:
charm: cs:~openstack-charmers-next/mysql-router
vault:
charm: cs:~openstack-charmers-next/vault
num_units: 1
ovn-central:
charm: cs:~openstack-charmers-next/ovn-central
num_units: 3
options:
source: distro
relations:
- - keystone:shared-db
- keystone-mysql-router:shared-db
- - neutron-api:shared-db
- neutron-mysql-router:shared-db
- - vault:shared-db
- vault-mysql-router:shared-db
- - keystone-mysql-router:db-router
- mysql-innodb-cluster:db-router
- - neutron-mysql-router:db-router
- mysql-innodb-cluster:db-router
- - vault-mysql-router:db-router
- mysql-innodb-cluster:db-router
- - neutron-api:amqp
- rabbitmq-server:amqp
- - neutron-api:identity-service
- keystone:identity-service
- - neutron-api-plugin-ovn:neutron-plugin
- neutron-api:neutron-plugin-api-subordinate
- - neutron-api-plugin-ovn:ovsdb-cms
- ovn-central:ovsdb-cms
- - ovn-central:certificates
- vault:certificates
- - neutron-api-plugin-ovn:certificates
- vault:certificates
- - keystone:certificates
- vault:certificates
- - neutron-api:certificates
- vault:certificates
- - hacluster-neutron-api:ha
- neutron-api:ha

View File

@ -0,0 +1 @@
ha.j2

View File

@ -0,0 +1 @@
ha.j2

View File

@ -0,0 +1 @@
ha.j2

View File

@ -0,0 +1 @@
ha.j2

View File

@ -0,0 +1,4 @@
applications:
neutron-api:
options:
vip: '{{ OS_VIP00 }}'

View File

@ -1,9 +1,12 @@
charm_name: neutron-api-plugin-ovn
smoke_bundles:
- bionic-train
- bionic-ussuri
gate_bundles:
- eoan
- bionic-train
- eoan
- bionic-ussuri
dev_bundles:
- focal
target_deploy_status:
neutron-api-plugin-ovn:
workload-status: waiting
@ -17,4 +20,4 @@ target_deploy_status:
configure:
- zaza.openstack.charm_tests.vault.setup.auto_initialize_no_validation
tests:
- zaza.charm_tests.noop.tests.NoopTest
- zaza.openstack.charm_tests.neutron.tests.NeutronCreateNetworkTest

1
src/wheelhouse.txt Normal file
View File

@ -0,0 +1 @@
zipp<2.0.0

View File

@ -3,11 +3,10 @@
# requirements management in charms via bot-control. Thank you.
#
# Lint and unit test requirements
flake8>=2.2.4,<=2.4.1
stestr>=2.2.0
requests>=2.18.4
charms.reactive
mock>=1.2
nose>=1.3.7
coverage>=3.6
mock>=1.2
pep8>=1.7.0
flake8>=2.2.4
os-testr>=0.4.1
git+https://github.com/openstack/charms.openstack.git#egg=charms.openstack

View File

@ -22,18 +22,41 @@ import charms_openstack.test_mocks # noqa
charms_openstack.test_mocks.mock_charmhelpers()
import mock
import charms
class _fake_decorator(object):
def __init__(self, *args):
pass
def __call__(self, f):
return f
charms = mock.MagicMock()
sys.modules['charms'] = charms
charms.leadership = mock.MagicMock()
keystoneauth1 = mock.MagicMock()
neutronclient = mock.MagicMock()
sys.modules['charms.leadership'] = charms.leadership
keystoneauth1 = mock.MagicMock()
novaclient = mock.MagicMock()
neutron_lib = mock.MagicMock()
sys.modules['charms.leadership'] = charms.leadership
sys.modules['keystoneauth1'] = keystoneauth1
sys.modules['novaclient'] = novaclient
sys.modules['neutronclient'] = neutronclient
sys.modules['neutronclient.v2_0'] = neutronclient.v2_0
sys.modules['neutron_lib'] = neutron_lib
sys.modules['neutron_lib.constants'] = neutron_lib.constants
charms.reactive = mock.MagicMock()
charms.reactive.when = _fake_decorator
charms.reactive.when_all = _fake_decorator
charms.reactive.when_any = _fake_decorator
charms.reactive.when_not = _fake_decorator
charms.reactive.when_none = _fake_decorator
charms.reactive.when_not_all = _fake_decorator
charms.reactive.not_unless = _fake_decorator
charms.reactive.when_file_changed = _fake_decorator
charms.reactive.collect_metrics = _fake_decorator
charms.reactive.meter_status_changed = _fake_decorator
charms.reactive.only_once = _fake_decorator
charms.reactive.hook = _fake_decorator
charms.reactive.bus = mock.MagicMock()
charms.reactive.flags = mock.MagicMock()
charms.reactive.relations = mock.MagicMock()
sys.modules['charms.reactive'] = charms.reactive
sys.modules['charms.reactive.bus'] = charms.reactive.bus
sys.modules['charms.reactive.bus'] = charms.reactive.decorators
sys.modules['charms.reactive.flags'] = charms.reactive.flags
sys.modules['charms.reactive.relations'] = charms.reactive.relations
netaddr = mock.MagicMock()
sys.modules['netaddr'] = netaddr

View File

@ -51,7 +51,9 @@ class Helper(test_utils.PatchHelper):
def setUp(self):
super().setUp()
self.patch_release(
neutron_api_plugin_ovn.NeutronAPIPluginCharm.release)
neutron_api_plugin_ovn.TrainNeutronAPIPluginCharm.release)
self.patch_release(
neutron_api_plugin_ovn.UssuriNeutronAPIPluginCharm.release)
class TestNeutronAPIPluginOvnCharm(Helper):
@ -72,7 +74,7 @@ class TestNeutronAPIPluginOvnCharm(Helper):
with mock.patch('builtins.open', create=True) as mocked_open:
mocked_file = mock.MagicMock(spec=io.FileIO)
mocked_open.return_value = mocked_file
c = neutron_api_plugin_ovn.NeutronAPIPluginCharm()
c = neutron_api_plugin_ovn.UssuriNeutronAPIPluginCharm()
c.configure_cert = mock.MagicMock()
c.configure_tls()
mocked_open.assert_called_once_with(

View File

@ -31,16 +31,16 @@ class TestRegisteredHooks(test_utils.TestRegisteredHooks):
]
hook_set = {
'when_none': {
'flag_db_migration': (
'maybe_flag_db_migration': (
'neutron-plugin.db_migration',
'neutron-plugin.available',),
'request_db_migration': (
'maybe_request_db_migration': (
'neutron-plugin.available',
'run-default-update-status',),
},
'when': {
'flag_db_migration': ('charm.installed',),
'request_db_migration': ('neutron-plugin.connected',),
'maybe_flag_db_migration': ('charm.installed',),
'maybe_request_db_migration': ('neutron-plugin.connected',),
'configure_neutron': (
'neutron-plugin.connected',
'ovsdb-cms.available',),
@ -57,7 +57,6 @@ class TestOvnHandlers(test_utils.PatchHelper):
def setUp(self):
super().setUp()
# self.patch_release(octavia.OctaviaCharm.release)
self.charm = mock.MagicMock()
self.patch_object(handlers.charm, 'provide_charm_instance',
new=mock.MagicMock())
@ -69,12 +68,27 @@ class TestOvnHandlers(test_utils.PatchHelper):
p = mock.PropertyMock().return_value = return_value
return p
def test_flag_db_migration(self):
def test_maybe_flag_db_migration(self):
self.patch_object(handlers.reactive, 'set_flag')
handlers.flag_db_migration()
self.charm.db_migration_needed = self.pmock(False)
handlers.maybe_flag_db_migration()
self.assertFalse(self.set_flag.called)
self.charm.db_migration_needed = self.pmock(True)
handlers.maybe_flag_db_migration()
self.set_flag.assert_called_once_with('neutron-plugin.db_migration')
def test_request_db_migration(self):
def test_maybe_request_db_migration(self):
self.patch_object(handlers.reactive, 'endpoint_from_flag')
neutron_plugin = mock.MagicMock()
self.endpoint_from_flag.return_value = neutron_plugin
self.charm.db_migration_needed = self.pmock(False)
handlers.maybe_request_db_migration()
self.assertFalse(neutron_plugin.request_db_migration.called)
self.charm.db_migration_needed = self.pmock(True)
handlers.maybe_request_db_migration()
neutron_plugin.request_db_migration.assert_called_once_with()
def test_render(self):
self.patch_object(handlers.reactive, 'endpoint_from_flag')
neutron = mock.MagicMock()
ovsdb = mock.MagicMock()
@ -97,13 +111,14 @@ class TestOvnHandlers(test_utils.PatchHelper):
options.dhcp_default_lease_time = self.pmock(42)
options.ovn_dhcp4_global_options = self.pmock('a:A4 b:B4')
options.ovn_dhcp6_global_options = self.pmock('a:A6 b:B6')
self.charm.service_plugins = self.pmock(['ovn-router'])
handlers.configure_neutron()
neutron.configure_plugin.assert_called_once_with(
'ovn',
service_plugins=(
'firewall_v2,metering,segments,'
'neutron_dynamic_routing.services.bgp.bgp_plugin.BgpPlugin,'
'lbaasv2,networking_ovn.l3.l3_ovn.OVNL3RouterPlugin'),
'lbaasv2,ovn-router'),
mechanism_drivers='ovn',
tenant_network_types='geneve,gre,vlan,flat,local',
subordinate_configuration={
@ -138,18 +153,3 @@ class TestOvnHandlers(test_utils.PatchHelper):
},
},
)
# def test_render(self):
# self.patch_object(handlers.charm, 'use_defaults')
# self.patch_object(handlers.reactive, 'set_flag')
# self.charm.enable_services.return_value = False
# handlers.render()
# self.charm.render_with_interfaces.assert_called_once_with([])
# self.charm.enable_services.assert_called_once_with()
# self.assertFalse(self.use_defaults.called)
# self.assertFalse(self.set_flag.called)
# self.charm.assess_status.assert_called_once_with()
# self.charm.enable_services.return_value = True
# handlers.render()
# self.use_defaults.assert_called_once_with('certificates.available')
# self.set_flag.assert_called_once_with('config.rendered')