From 469ca4db8bacdab93b6ed0d3fa9919486373eac1 Mon Sep 17 00:00:00 2001 From: Frode Nordahl Date: Wed, 6 May 2020 12:08:39 +0200 Subject: [PATCH] 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 --- .../charm/openstack/neutron_api_plugin_ovn.py | 90 +++++++++++++++++-- .../neutron_api_plugin_ovn_handlers.py | 15 ++-- tox.ini | 2 +- unit_tests/test_lib_charm_openstack_ovn.py | 29 ++++++ ...eactive_neutron_api_plugin_ovn_handlers.py | 39 +++++--- 5 files changed, 146 insertions(+), 29 deletions(-) diff --git a/src/lib/charm/openstack/neutron_api_plugin_ovn.py b/src/lib/charm/openstack/neutron_api_plugin_ovn.py index 9247f00..96bf99a 100644 --- a/src/lib/charm/openstack/neutron_api_plugin_ovn.py +++ b/src/lib/charm/openstack/neutron_api_plugin_ovn.py @@ -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.""" diff --git a/src/reactive/neutron_api_plugin_ovn_handlers.py b/src/reactive/neutron_api_plugin_ovn_handlers.py index 08fd0cf..6e68c96 100644 --- a/src/reactive/neutron_api_plugin_ovn_handlers.py +++ b/src/reactive/neutron_api_plugin_ovn_handlers.py @@ -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': { diff --git a/tox.ini b/tox.ini index 23750a8..a45c381 100644 --- a/tox.ini +++ b/tox.ini @@ -77,4 +77,4 @@ commands = {posargs} [flake8] # E402 ignore necessary for path append before sys module import in actions -ignore = E402 +ignore = E402,W504 diff --git a/unit_tests/test_lib_charm_openstack_ovn.py b/unit_tests/test_lib_charm_openstack_ovn.py index 03f79c2..c0a5224 100644 --- a/unit_tests/test_lib_charm_openstack_ovn.py +++ b/unit_tests/test_lib_charm_openstack_ovn.py @@ -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) diff --git a/unit_tests/test_reactive_neutron_api_plugin_ovn_handlers.py b/unit_tests/test_reactive_neutron_api_plugin_ovn_handlers.py index 6598fdb..53618a5 100644 --- a/unit_tests/test_reactive_neutron_api_plugin_ovn_handlers.py +++ b/unit_tests/test_reactive_neutron_api_plugin_ovn_handlers.py @@ -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': {