Extend configurable variables and retrieve config data

Gate ``available`` state on remote end signalling availability.

Depends-On: I9eb5f8a6039b74288a395a584f844507448cdc23
Change-Id: I44a23549e4830d89ba3182250c40dfe395767fb0
This commit is contained in:
Frode Nordahl 2019-09-24 16:34:17 +02:00
parent 1ab760f201
commit 4f7dba3da8
No known key found for this signature in database
GPG Key ID: 6A5D59A3BA48373F
3 changed files with 128 additions and 40 deletions

View File

@ -6,25 +6,46 @@ that charm.
# Usage # Usage
## States ## Flags and States
The interface provides the `{relation-name}.connected` and The interface provides the `{relation-name}.connected` and
`{relation_name}.available` states. `{relation_name}.available` flags and states.
## neutron\_config\_data
The neutron\_config\_data property allows the charm author to introspect a
subset of the principle charm context values prior to applying the context
provided by this relation.
This enables the subordinate charm to make informed decisions about how it
should configure Neutron based on how the deployment is configured.
```python
@reactive.when('neutron-plugin-api-subordinate.connected')
def configure_principle():
api_principle = reactive.endpoint_from_flag(
'neutron-plugin-api-subordinate.connected')
if 'dns' in api_principle.neutron_config_data['extension_drivers']:
...
## configure\_plugin ## configure\_plugin
The configure\_plugin method allows the following to be configured in the The configure\_plugin method allows the following to be configured in the
principle charm: principle charm:
* **neutron\_plugin**: Name of the plugin type eg 'ovs', 'odl' etc. This is not * **neutron\_plugin**: Name of the plugin type eg 'ovs', 'ovn' etc. This is not
currently used in the principle but should be set to currently used in the principle but should be set to
something representitve of the plugin type. something representitve of the plugin type.
* **core\_plugin**: Value of core\_plugin to be set in neutron.conf * **core\_plugin**: Value of core\_plugin to be set in neutron.conf
* **neutron\_plugin\_config**: File containing plugin config. This config file is * **neutron\_plugin\_config**: File containing plugin config. This config file
appended to the list of configs the neutron is appended to the list of configs the neutron
services read on startup. services read on startup.
* **service\_plugins**: Value of service\_plugins to be set in neutron.conf * **service\_plugins**: Value of service\_plugins to be set in neutron.conf
* **subordinate\_configuration**: Config to be inserted into a configuration file * **subordinate\_configuration**: Config to be inserted into a configuration
that the principle manages. file that the principle manages.
* **extension\_drivers**: Value of extension\_drivers to be set in
ml2\_conf.ini
* **neutron\_security\_groups**: Toggle whether the Neutron security group
feature should be enabled or not.
Request `foo = bar` is inserted into the `DEFAULT` section of neutron.conf Request `foo = bar` is inserted into the `DEFAULT` section of neutron.conf
@ -43,11 +64,15 @@ def configure_principle(api_principle):
} }
} }
} }
service_plugins = ','.join((
api_principle.neutron_config_data.get('service_plugins', ''),
'networking_ovn.l3.l3_ovn.OVNL3RouterPlugin'),
)
api_principle.configure_plugin( api_principle.configure_plugin(
neutron_plugin='odl', neutron_plugin='ovn',
core_plugin='neutron.plugins.ml2.plugin.Ml2Plugin', core_plugin='neutron.plugins.ml2.plugin.Ml2Plugin',
neutron_plugin_config='/etc/neutron/plugins/ml2/ml2_conf.ini', neutron_plugin_config='/etc/neutron/plugins/ml2/ml2_conf.ini',
service_plugins='router,firewall,lbaas,vpnaas,metering', service_plugins=service_plugins,
subordinate_configuration=inject_config) subordinate_configuration=inject_config)
``` ```

View File

@ -14,7 +14,8 @@ class NeutronPluginAPISubordinate(RelationBase):
def changed(self): def changed(self):
"""Set connected state""" """Set connected state"""
self.set_state('{relation_name}.connected') self.set_state('{relation_name}.connected')
self.set_state('{relation_name}.available') if self.neutron_api_ready():
self.set_state('{relation_name}.available')
@hook( @hook(
'{provides:neutron-plugin-api-subordinate}-relation-{broken,departed}') '{provides:neutron-plugin-api-subordinate}-relation-{broken,departed}')
@ -23,36 +24,67 @@ class NeutronPluginAPISubordinate(RelationBase):
self.remove_state('{relation_name}.available') self.remove_state('{relation_name}.available')
self.remove_state('{relation_name}.connected') self.remove_state('{relation_name}.connected')
@property
def neutron_config_data(self):
return json.loads(self.get_remote('neutron_config_data', "{}"))
def neutron_api_ready(self):
if self.get_remote('neutron-api-ready') == 'yes':
return True
return False
def configure_plugin(self, neutron_plugin, core_plugin=None, def configure_plugin(self, neutron_plugin, core_plugin=None,
neutron_plugin_config=None, service_plugins=None, neutron_plugin_config=None, service_plugins=None,
subordinate_configuration=None): subordinate_configuration=None,
extension_drivers=None, mechanism_drivers=None,
tenant_network_types=None,
neutron_security_groups=None):
"""Send principle plugin information """Send principle plugin information
:param neutron_plugin: str Neutron plugin name eg odl :param neutron_plugin: Neutron plugin name
:param core_plugin: str eg neutron.plugins.ml2.plugin.Ml2Plugin :type neutron_plugin: str
:param neutron-plugin-config: str /etc/neutron/plugins/ml2/ml2_conf.ini :param core_plugin: Entry point eg neutron.plugins.ml2.plugin.Ml2Plugin
:param service-plugins str: Comma delimited list of service plugins eg :type core_plugin: str
router,firewall,lbaas,vpnaas,metering :param neutron-plugin-config: /etc/neutron/plugins/ml2/ml2_conf.ini
:param subordinate_configuration dict: Configuration for the principle :type neutron-plugin-config: str
to inject into a configuration :param service-plugins: Comma delimited list of service plugins eg
file it is managing eg: router,firewall,lbaas,vpnaas,metering
# Add sections and tuples to insert values into neutron-server's :type service-plugins: str
# neutron.conf e.g. :param subordinate_configuration: Configuration for the principle
# { to inject into a configuration
# "neutron-api": { file it is managing eg:
# "/etc/neutron/neutron.conf": { # Add sections and tuples to insert values into neutron-server's
# "sections": { # neutron.conf e.g.
# 'DEFAULT': [ # {
# ('key1', 'val1') # "neutron-api": {
# ('key2', 'val2') # "/etc/neutron/neutron.conf": {
# ], # "sections": {
# 'agent': [ # 'DEFAULT': [
# ('key3', 'val3') # ('key1', 'val1')
# ], # ('key2', 'val2')
# } # ],
# } # 'agent': [
# } # ('key3', 'val3')
# } # ],
# }
# }
# }
# }
:type subordinate_configuration:
Dict[str, Dict[
str Dict[
str, List[
Union[str, str]]]]]
:param extension_drivers: Extension drivers eg dns,port_security
:type extension_drivers: str
:param mechanism_drivers: Mechanism drivers eg openvswitch,hyperv
:type mechanism_drivers: str
:param tenant_network_types: Tenant network types eg local,gre
Note that this also configures
``type_drivers``
:type tenant_network_types: str
:param neutron_security_groups: 'true' to enable security groups
:type neutron_security_groups: str
""" """
if subordinate_configuration is None: if subordinate_configuration is None:
subordinate_configuration = {} subordinate_configuration = {}
@ -62,6 +94,10 @@ class NeutronPluginAPISubordinate(RelationBase):
'core-plugin': core_plugin, 'core-plugin': core_plugin,
'neutron-plugin-config': neutron_plugin_config, 'neutron-plugin-config': neutron_plugin_config,
'service-plugins': service_plugins, 'service-plugins': service_plugins,
'extension-drivers': extension_drivers,
'mechanism-drivers': mechanism_drivers,
'tenant-network-types': tenant_network_types,
'neutron-security-groups': neutron_security_groups,
'subordinate_configuration': json.dumps(subordinate_configuration), 'subordinate_configuration': json.dumps(subordinate_configuration),
} }
conversation.set_remote(**relation_info) conversation.set_remote(**relation_info)

View File

@ -109,6 +109,12 @@ class TestNeutronPluginApiSubordinateProvides(test_utils.PatchHelper):
conversation = mock.MagicMock() conversation = mock.MagicMock()
self.patch_target('conversation', conversation) self.patch_target('conversation', conversation)
self.patch_target('set_state') self.patch_target('set_state')
self.patch_target('get_remote')
self.get_remote.return_value = None
self.target.changed()
self.set_state.assert_called_once_with('{relation_name}.connected')
self.set_state.reset_mock()
self.get_remote.return_value = 'yes'
self.target.changed() self.target.changed()
self.set_state.assert_has_calls([ self.set_state.assert_has_calls([
mock.call('{relation_name}.connected'), mock.call('{relation_name}.connected'),
@ -125,6 +131,18 @@ class TestNeutronPluginApiSubordinateProvides(test_utils.PatchHelper):
mock.call('{relation_name}.connected'), mock.call('{relation_name}.connected'),
]) ])
def test_neutron_api_ready(self):
self.patch_target('get_remote')
self.get_remote.return_value = 'yes'
self.assertTrue(self.target.neutron_api_ready())
self.get_remote.return_value = None
self.assertFalse(self.target.neutron_api_ready())
def teat_neutron_config_data(self):
self.patch_target('get_remote')
self.get_remote = json.dumps({'k': 'v'})
self.assertEquals(self.target.neutron_config_data, {'k': 'v'})
def test_configure_plugin(self): def test_configure_plugin(self):
conversation = mock.MagicMock() conversation = mock.MagicMock()
self.patch_target('conversation', conversation) self.patch_target('conversation', conversation)
@ -132,13 +150,22 @@ class TestNeutronPluginApiSubordinateProvides(test_utils.PatchHelper):
'aCorePlugin', 'aCorePlugin',
'aNeutronPluginConfig', 'aNeutronPluginConfig',
'servicePlugins1,servicePlugin2', 'servicePlugins1,servicePlugin2',
{'aKey': 'aValue'}) {'aKey': 'aValue'},
'extensionDriver1,extensionDriver2',
'mechanismDriver1,mechanismDriver2',
'typeDriver1,typeDriver2',
'toggleSecurityGroups',
)
conversation.set_remote.assert_called_once_with( conversation.set_remote.assert_called_once_with(
**{ **{
'core-plugin': 'aCorePlugin', 'core-plugin': 'aCorePlugin',
'neutron-plugin': 'aPlugin', 'neutron-plugin': 'aPlugin',
'neutron-plugin-config': 'aNeutronPluginConfig', 'neutron-plugin-config': 'aNeutronPluginConfig',
'service-plugins': 'servicePlugins1,servicePlugin2', 'service-plugins': 'servicePlugins1,servicePlugin2',
'extension-drivers': 'extensionDriver1,extensionDriver2',
'mechanism-drivers': 'mechanismDriver1,mechanismDriver2',
'tenant-network-types': 'typeDriver1,typeDriver2',
'neutron-security-groups': 'toggleSecurityGroups',
'subordinate_configuration': json.dumps({'aKey': 'aValue'})}, 'subordinate_configuration': json.dumps({'aKey': 'aValue'})},
) )