Support charms providing templates with same basename

Replicate functionaltiy of ``charmhelpers.contrib.openstack``
where template files named after the absolute path of target
with path separators repalced by underscores can be used.

This convention is useful when charm author need to provide
templates with ambiguous basename.

Change-Id: I534fe52f38df7d1e409246115836223e90f080bc
Closes-Bug: #1872689
This commit is contained in:
Frode Nordahl 2020-04-14 13:16:27 +02:00
parent 720a5922db
commit f9bd43ff5d
No known key found for this signature in database
GPG Key ID: 6A5D59A3BA48373F
2 changed files with 48 additions and 10 deletions

View File

@ -794,16 +794,25 @@ class BaseOpenStackCharmActions(object):
# means we need to skip this config to avoid rendering # means we need to skip this config to avoid rendering
return return
charmhelpers.core.templating.render( def _render(source):
source=os.path.basename(conf), charmhelpers.core.templating.render(
template_loader=os_templating.get_loader( source=source,
'templates/', self.release), template_loader=os_templating.get_loader(
target=conf, 'templates/', self.release),
context=adapters_instance, target=conf,
config_template=config_template, context=adapters_instance,
group=self.group, config_template=config_template,
perms=self.permission_override_map.get(conf) or 0o640, group=self.group,
) perms=self.permission_override_map.get(conf) or 0o640,
)
try:
_render(os.path.basename(conf))
except LookupError:
# if no template is found try looking for files named after
# the absolute path of target with path separators replaced
# by underscores. This convention is useful when charm
# author need to provide templates with ambiguous basenames
_render('_'.join(conf.split(os.path.sep))[1:])
def render_with_interfaces(self, interfaces, configs=None): def render_with_interfaces(self, interfaces, configs=None):
"""Render the configs using the interfaces passed; overrides any """Render the configs using the interfaces passed; overrides any

View File

@ -519,6 +519,35 @@ class TestMyOpenStackCharm(BaseOpenStackCharmTest):
assert isinstance(context, MyAdapter) assert isinstance(context, MyAdapter)
self.assertEqual(context.interfaces, ['interface1', 'interface2']) self.assertEqual(context.interfaces, ['interface1', 'interface2'])
# test source template provided with filename that represents absoulute
# path of target config where path separators has been replaced by
# underscores
self.render.reset_mock()
self.render.side_effect = [LookupError, None]
self.target.render_configs(
['/etc/some/path1'],
adapters_instance=self.target.adapters_instance)
self.render.assert_has_calls([
mock.call(
source='path1',
template_loader='my-loader',
target='/etc/some/path1',
context=mock.ANY,
config_template=None,
group='root',
perms=0o640,
),
mock.call(
source='etc_some_path1',
template_loader='my-loader',
target='/etc/some/path1',
context=mock.ANY,
config_template=None,
group='root',
perms=0o640,
),
])
def test_render_configs_construct_adapters_instance(self): def test_render_configs_construct_adapters_instance(self):
# give us a way to check that the context manager was called. # give us a way to check that the context manager was called.
from contextlib import contextmanager from contextlib import contextmanager