Skip to content

Commit

Permalink
Fix and extend render function
Browse files Browse the repository at this point in the history
This `render` function can be used to render a template e.g. in jinja
using the tower lookup:

    #! jinja
    {{ render('another_file.j2') }}

This file will be rendered using the same tower rendering pipeline as
all other files. It therefore supprots shebang, any other renderer and
any tower helper.
  • Loading branch information
jgraichen committed May 11, 2020
1 parent c891003 commit 54c69cc
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 5 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Added
- Added `merge-last`, `merge-first`, `remove` and `overwrite` merge strategies for dictionaries
- Improve logging source and exception for rendering errors (#10)
- Extended `render` context function to support relative lookup

### Fixed
- Fix `render` context function to use correct `basedir` variable
- Add `basedir` variable when rendering top file

## [1.2.0] - 2020-01-31
### Added
Expand Down
14 changes: 9 additions & 5 deletions salt_tower/pillar/tower.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def run(self, top):

base = os.path.dirname(top)

for item in self._load_top(top):
for item in self._load_top(top, base):
if isinstance(item, str):
self._load_item(base, item)

Expand All @@ -135,8 +135,8 @@ def _match_minion(self, tgt):
LOGGER.exception(err)
return False

def _load_top(self, top):
data = self._compile(top)
def _load_top(self, top, base):
data = self._compile(top, context={'basedir': base})

if not isinstance(data, dict):
LOGGER.critical("Tower top must be a dict, but is %s.", type(data))
Expand Down Expand Up @@ -256,8 +256,12 @@ def _compile(
context["tower"] = self

def render(tmpl, renderer="text"):
file = os.path.join(context.get("base"), tmpl)
file = os.path.abspath(file)
if (tmpl.startswith("./") or tmpl.startswith("../")):
path = os.path.join(context["tmpldir"], tmpl)
elif not tmpl.startswith("/"):
path = os.path.join(context["basedir"], tmpl)

file = os.path.abspath(path)

if not os.path.isfile(file):
raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), file)
Expand Down
72 changes: 72 additions & 0 deletions test/pillar/test_tower.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,3 +430,75 @@ def test_error_invalid_file(env):

with pytest.raises(SaltRenderError):
env.ext_pillar()


def test_render_func(env):
env.setup({
'tower.sls':
'''
base:
- index
''',
'index.sls':
'''
key: !include test/conf.j2
''',
'test/conf.j2':
'''
#! jinja | text strip
{{ render('test/conf2.j2') }}
''',
'test/conf2.j2':
'''
This is a test.
''',
})

assert env.ext_pillar() == {'key': 'This is a test.'}


def test_render_func_relative(env):
env.setup({
'tower.sls':
'''
base:
- index
''',
'index.sls':
'''
key: !include test/conf.j2
''',
'test/conf.j2':
'''
#! jinja | text strip
{{ render('./conf2.j2') }}
''',
'test/conf2.j2':
'''
This is a test.
''',
})

assert env.ext_pillar() == {'key': 'This is a test.'}


def test_render_func_in_top(env):
env.setup({
'tower.sls':
'''
base:
- '*':
- key: !include test/conf.j2
''',
'test/conf.j2':
'''
#! jinja | text strip
{{ render('./conf2.j2') }}
''',
'test/conf2.j2':
'''
This is a test.
''',
})

assert env.ext_pillar() == {'key': 'This is a test.'}

0 comments on commit 54c69cc

Please sign in to comment.