Add interfaces from flags to adapter interface

When render_configs is called without an adapters_instance it used to
construct an adapters_instance which lacked any relation data. This
was, in effect, useless (the pre-existing docstring comment says as
much). Usually render_configs is called via render_with_interfaces
which inturn has gets its interface list excplicitly passed in.
However, this approach is not possible when needing to trigger a
config render from a generic layer as the generic layer does not know
which interfaces to pass.

This change adds code to dynamically build the interface list from
the flags which have been set already.

Change-Id: I1958226576c73d0ce0e9fd4c1423f86addadb454
This commit is contained in:
Liam Young 2018-11-05 10:24:47 +00:00
parent b75c8b4161
commit 48bac1b871
2 changed files with 64 additions and 15 deletions

View File

@ -16,6 +16,7 @@ import charmhelpers.core.templating
import charmhelpers.core.unitdata as unitdata
import charmhelpers.fetch as fetch
import charms.reactive as reactive
import charms.reactive.flags as flags
import charms.reactive.relations as relations
import charms_openstack.adapters as os_adapters
@ -735,15 +736,6 @@ class BaseOpenStackCharmActions(object):
"""Render the configuration files identified in the list passed as
configs.
If adapters_instance is None then the self.adapters_instance is used
that was setup in the __init__() method. Note, if no interfaces were
passed (the default) then there will be no interfaces.
TODO: need to work out how to make this function more useful - at the
moment, with a default setup, this function is only useful to
render_with_interfaces() which constructs a new adapters_instance
anyway.
Configs may not only be loaded via OpenStack loaders but also via
string templates passed via config options or from relation data.
This must be explicitly declared via string_templates dict of a given
@ -755,7 +747,16 @@ class BaseOpenStackCharmActions(object):
:param adapters_instance: [optional] the adapters_instance to use.
"""
if adapters_instance is None:
adapters_instance = self.adapters_instance
interfaces = []
for f in flags.get_flags():
ep_from_f = relations.endpoint_from_flag(f)
if ep_from_f:
interfaces.append(ep_from_f)
try:
adapters_instance = self.adapters_class(interfaces,
charm_instance=self)
except TypeError:
adapters_instance = self.adapters_class(interfaces)
with self.restart_on_change():
for conf in configs:

View File

@ -465,8 +465,49 @@ class TestMyOpenStackCharm(BaseOpenStackCharmTest):
self.patch_object(chm_core.os_templating,
'get_loader',
return_value='my-loader')
# self.patch_target('adapter_instance', new='my-adapter')
self.target.render_configs(['path1'])
self.target.render_configs(
['path1'],
adapters_instance=self.target.adapters_instance)
self.assertEqual(d[0], 1)
self.render.assert_called_once_with(
source='path1',
template_loader='my-loader',
target='path1',
context=mock.ANY,
config_template=None,
group='root',
perms=0o640,
)
# assert the context was an MyAdapter instance.
context = self.render.call_args_list[0][1]['context']
assert isinstance(context, MyAdapter)
self.assertEqual(context.interfaces, ['interface1', 'interface2'])
def test_render_configs_construct_adapters_instance(self):
# give us a way to check that the context manager was called.
from contextlib import contextmanager
d = [0]
@contextmanager
def fake_restart_on_change():
d[0] += 1
yield
self.patch_target('restart_on_change', new=fake_restart_on_change)
self.patch_object(chm_core.charmhelpers.core.templating, 'render')
self.patch_object(chm_core.os_templating,
'get_loader',
return_value='my-loader')
self.patch_object(
chm_core.flags,
'get_flags',
return_value=['interface1.available', 'interface2.ready'])
self.patch_object(
chm_core.relations,
'endpoint_from_flag',
side_effect=lambda x: x.split('.')[0])
self.target.render_configs(
['path1'])
self.assertEqual(d[0], 1)
self.render.assert_called_once_with(
source='path1',
@ -505,7 +546,9 @@ class TestMyOpenStackCharm(BaseOpenStackCharmTest):
adapters_instance.options = mock.MagicMock()
adapters_instance.options.t_prop = config_template
self.target.render_configs(['path1'])
self.target.render_configs(
['path1'],
adapters_instance=self.target.adapters_instance)
self.assertEqual(d[0], 1)
self.render.assert_called_once_with(
source='path1',
@ -534,7 +577,10 @@ class TestMyOpenStackCharm(BaseOpenStackCharmTest):
os_adapters.ConfigurationAdapter
)
self.assertRaises(RuntimeError, self.target.render_configs, ['path1'])
self.assertRaises(
RuntimeError,
self.target.render_configs, ['path1'],
adapters_instance=self.target.adapters_instance)
def test_render_config_from_string_no_relation(self):
"""
@ -554,7 +600,9 @@ class TestMyOpenStackCharm(BaseOpenStackCharmTest):
adapters_instance = self.target.adapters_instance
self.target.render_configs(['path1'])
self.target.render_configs(
['path1'],
adapters_instance=adapters_instance)
m.assert_called_once_with('path1', adapters_instance)
self.render.assert_not_called()