Allow use of sriovnicswitch driver with OVN

Move filtering of service plugins, mechanism drivers and tenant network
types to charm class.

Add white list for mechanism drivers.

Add black list for service plugins.

Change-Id: I55374006e3adeaf8be04ef69e2cf56619ad3bdb2
This commit is contained in:
Frode Nordahl 2020-05-06 12:08:39 +02:00
parent 058ae7e2c3
commit 469ca4db8b
No known key found for this signature in database
GPG Key ID: 6A5D59A3BA48373F
5 changed files with 146 additions and 29 deletions

View File

@ -70,7 +70,30 @@ class BaseNeutronAPIPluginCharm(charms_openstack.charm.OpenStackCharm):
# make sure we can write secrets readable by the ``neutron-server`` process
group = 'neutron'
db_migration_needed = False
service_plugins = []
# Neutron service plugins to add
svc_plugins = []
# Neutron service plugins to remove
svc_plugin_blacklist = [
# FWaaS is not supported and also deprecated
'firewall',
'firewall_v2',
# Security groups logging not supported at this time
'log',
# Port forwarding is not supported at this time
'port_forwarding',
# OVN has its own service driver for that replaces Neutron ``router``
'router',
# Neutron Dynamic Routing is not supported at this time
'neutron_dynamic_routing.services.bgp.bgp_plugin.BgpPlugin',
# VPNaaS is not supported
'vpnaas',
]
# Neutron mechanism driers to prepend
mech_drivers = ['ovn']
# Neutron mechanism drivers to allow
mech_driver_whitelist = ['sriovnicswitch']
# Neutron tenant network types to prepend
network_types = ['geneve']
def configure_tls(self, certificates_interface=None):
"""Override configure_tls method for neutron-api-plugin-ovn.
@ -108,16 +131,67 @@ class BaseNeutronAPIPluginCharm(charms_openstack.charm.OpenStackCharm):
"""
return self.db_migration_needed
@property
def service_plugins(self):
def service_plugins(self, neutron_svc_plugins=None):
"""Provide list of service plugins for current OpenStack release.
The returned variable must be set in the release specifc charm classes.
The ``svc_plugins`` class variable must be set in the release
specifc charm classes.
The ``svc_plugin_blacklist`` class variable defines which
service plugins to not use together with OVN.
:param neutron_svc_plugins: Comma separated list of service plugins
from Neutron.
:type neutron_svc_plugins: Optional[str]
:returns: List of service plugins
:rtype: List
:rtype: List[str]
"""
return self.service_plugins
neutron_svc_plugins = neutron_svc_plugins or ''
return [
service_plugin
for service_plugin in neutron_svc_plugins.split(',')
if service_plugin not in self.svc_plugin_blacklist
] + self.svc_plugins
def mechanism_drivers(self, neutron_mech_drivers=None):
"""Provide list of mechanism drivers for current OpenStack release.
The ``mech_drivers`` class variable defines which drivers to add
and must be set in the release specific charm classes.
The ``mech_driver_whitelist`` class variable defines which
mechanism drivers are allowed to use together with OVN.
:param neutron_mech_drivers: Comma separated list of mechanism drivers
from Neutron.
:type neutron_mech_drivers: Optional[str]
:returns: List of mechanism drivers
:rtype: List[str]
"""
neutron_mech_drivers = neutron_mech_drivers or ''
return self.mech_drivers + [
mech_driver
for mech_driver in neutron_mech_drivers.split(',')
if mech_driver in self.mech_driver_whitelist
]
def tenant_network_types(self, neutron_tenant_network_types=None):
"""Provide list of tenant network types for current OpenStack release.
The ``network_types`` class variable dfines which types to
prepend and must be set in the release specific charm classes.
:param neutron_tenant_network_types: Comma separated list of tenant
network types from Neutron.
:type neutron_tenant_network_types: Optional[str]
:returns: List of tenant network types
:rtype: List[str]
"""
neutron_tenant_network_types = neutron_tenant_network_types or ''
return self.network_types + [
network_type
for network_type in neutron_tenant_network_types.split(',')
]
class TrainNeutronAPIPluginCharm(BaseNeutronAPIPluginCharm):
@ -125,7 +199,7 @@ class TrainNeutronAPIPluginCharm(BaseNeutronAPIPluginCharm):
release = 'train'
packages = ['python3-networking-ovn']
db_migration_needed = True
service_plugins = ['networking_ovn.l3.l3_ovn.OVNL3RouterPlugin']
svc_plugins = ['networking_ovn.l3.l3_ovn.OVNL3RouterPlugin']
class UssuriNeutronAPIPluginCharm(BaseNeutronAPIPluginCharm):
@ -140,7 +214,7 @@ class UssuriNeutronAPIPluginCharm(BaseNeutronAPIPluginCharm):
release = 'ussuri'
packages = []
db_migration_needed = False
service_plugins = ['ovn-router']
svc_plugins = ['ovn-router']
def install(self):
"""We no longer need to install anything."""

View File

@ -59,19 +59,18 @@ def configure_neutron():
'ovsdb-cms.available')
ch_core.hookenv.log('DEBUG: neutron_config_data="{}"'
.format(neutron.neutron_config_data))
service_plugins = neutron.neutron_config_data.get(
'service_plugins', '').split(',')
service_plugins = [svc for svc in service_plugins if svc not in ['router']]
tenant_network_types = neutron.neutron_config_data.get(
'tenant_network_types', '').split(',')
tenant_network_types.insert(0, 'geneve')
def _split_if_str(s):
_s = s or ''
return _s.split()
with charm.provide_charm_instance() as instance:
service_plugins.extend(instance.service_plugins)
mechanism_drivers = instance.mechanism_drivers(
neutron.neutron_config_data.get('mechanism_drivers'))
service_plugins = instance.service_plugins(
neutron.neutron_config_data.get('service_plugins'))
tenant_network_types = instance.tenant_network_types(
neutron.neutron_config_data.get('tenant_network_types'))
options = instance.adapters_instance.options
sections = {
'ovn': [
@ -116,7 +115,7 @@ def configure_neutron():
neutron.configure_plugin(
'ovn',
service_plugins=','.join(service_plugins),
mechanism_drivers='ovn',
mechanism_drivers=','.join(mechanism_drivers),
tenant_network_types=','.join(tenant_network_types),
subordinate_configuration={
'neutron-api': {

View File

@ -77,4 +77,4 @@ commands = {posargs}
[flake8]
# E402 ignore necessary for path append before sys module import in actions
ignore = E402
ignore = E402,W504

View File

@ -87,3 +87,32 @@ class TestNeutronAPIPluginOvnCharm(Helper):
'fakekey',
cn='host',
)
def test_service_plugins(self):
c = neutron_api_plugin_ovn.UssuriNeutronAPIPluginCharm()
svc_plugins = (
'router,firewall,firewall_v2,metering,segments,log,'
'neutron_dynamic_routing.services.bgp.bgp_plugin.BgpPlugin,'
'lbaasv2,port_forwarding,vpnaas')
expect = [
'metering',
'segments',
'lbaasv2',
'ovn-router',
]
self.assertEquals(c.service_plugins(svc_plugins), expect)
def test_mechanism_drivers(self):
c = neutron_api_plugin_ovn.UssuriNeutronAPIPluginCharm()
mech_drivers = 'openvswitch,hyperv,l2population,sriovnicswitch'
expect = [
'ovn',
'sriovnicswitch',
]
self.assertEquals(c.mechanism_drivers(mech_drivers), expect)
def test_tenant_network_types(self):
c = neutron_api_plugin_ovn.UssuriNeutronAPIPluginCharm()
network_types = 'gre,vlan,flat,local'
expect = ['geneve', 'gre', 'vlan', 'flat', 'local']
self.assertEquals(c.tenant_network_types(network_types), expect)

View File

@ -64,6 +64,14 @@ class TestOvnHandlers(test_utils.PatchHelper):
self.charm
self.provide_charm_instance().__exit__.return_value = None
def patch_charm(self, attr, return_value=None):
mocked = mock.patch.object(self.charm, attr)
self._patches[attr] = mocked
started = mocked.start()
started.return_value = return_value
self._patches_start[attr] = started
setattr(self, attr, started)
def pmock(self, return_value=None):
p = mock.PropertyMock().return_value = return_value
return p
@ -93,12 +101,15 @@ class TestOvnHandlers(test_utils.PatchHelper):
neutron = mock.MagicMock()
ovsdb = mock.MagicMock()
self.endpoint_from_flag.side_effect = [neutron, ovsdb]
neutron.neutron_config_data.get.side_effect = [
'router,firewall_v2,metering,segments,'
'neutron_dynamic_routing.services.bgp.bgp_plugin.BgpPlugin,'
'lbaasv2',
'gre,vlan,flat,local',
]
neutron.neutron_config_data.get.side_effect = lambda x: {
'mechanism_drivers': (
'openvswitch,hyperv,l2population,sriovnicswitch'),
'service_plugins': (
'router,firewall_v2,metering,segments,'
'neutron_dynamic_routing.services.bgp.bgp_plugin.BgpPlugin,'
'lbaasv2'),
'tenant_network_types': 'gre,vlan,flat,local',
}.get(x)
options = self.charm.adapters_instance.options
options.ovn_key = self.pmock('aKey')
options.ovn_cert = self.pmock('aCert')
@ -111,15 +122,19 @@ 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'])
self.patch_charm('mechanism_drivers')
self.mechanism_drivers.return_value = ['ovn', 'sriovnicswitch']
self.patch_charm('service_plugins')
self.service_plugins.return_value = [
'metering', 'segments', 'lbaasv2', 'ovn-router']
self.patch_charm('tenant_network_types')
self.tenant_network_types.return_value = [
'geneve', 'gre', 'vlan', 'flat', 'local']
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,ovn-router'),
mechanism_drivers='ovn',
service_plugins='metering,segments,lbaasv2,ovn-router',
mechanism_drivers='ovn,sriovnicswitch',
tenant_network_types='geneve,gre,vlan,flat,local',
subordinate_configuration={
'neutron-api': {