mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Properly render the high state loaded from templates. Fixes #2068.
Previously using `state.template` or `state.template_str` would not be checked/rendered into proper formatting resulting in some templates not being correctly executed. For example, the following template worked: ``` /tmp/issue-2068-template-str: virtualenv: - managed - no_site_packages: True - distribute: True pep8-pip: pip: - installed - name: pep8 - bin_env: /tmp/issue-2068-template-str - mirrors: http://testpypi.python.org/pypi - require: - virtualenv: /tmp/issue-2068-template-str ``` as opposed to the following which did not work: ``` /tmp/issue-2068-template-str: virtualenv.managed: - no_site_packages: True - distribute: True pep8-pip: pip.installed: - name: pep8 - bin_env: /tmp/issue-2068-template-str - mirrors: http://testpypi.python.org/pypi - require: - virtualenv: /tmp/issue-2068-template-str ``` The dotted names should be converted into lists for example, which was the problems with the two examples above.
This commit is contained in:
parent
677a08fe7d
commit
2211afa63a
2 changed files with 115 additions and 6 deletions
|
@ -1054,15 +1054,99 @@ class State(object):
|
|||
ret = self.call_chunks(chunks)
|
||||
return ret
|
||||
|
||||
def render_template(self, high, template):
|
||||
errors = []
|
||||
if not high:
|
||||
return high, errors
|
||||
|
||||
if not isinstance(high, dict):
|
||||
errors.append(
|
||||
'Template {0} does not render to a dictionary'.format(template)
|
||||
)
|
||||
return high, errors
|
||||
|
||||
invalid_items = ('include', 'exclude', 'extends')
|
||||
for item in invalid_items:
|
||||
if item in high:
|
||||
errors.append(
|
||||
'The \'{0}\' declaration found on \'{1}\' is invalid when '
|
||||
'rendering single templates'.format(item, template)
|
||||
)
|
||||
return high, errors
|
||||
|
||||
for name in high:
|
||||
if not isinstance(high[name], dict):
|
||||
if isinstance(high[name], string_types):
|
||||
# Is this is a short state, it needs to be padded
|
||||
if '.' in high[name]:
|
||||
comps = high[name].split('.')
|
||||
high[name] = {
|
||||
#'__sls__': template,
|
||||
#'__env__': None,
|
||||
comps[0]: [comps[1]]
|
||||
}
|
||||
continue
|
||||
|
||||
errors.append(
|
||||
'Name {0} in template {1} is not a dictionary'.format(
|
||||
name, template
|
||||
)
|
||||
)
|
||||
continue
|
||||
skeys = set()
|
||||
for key in sorted(high[name]):
|
||||
if key.startswith('_'):
|
||||
continue
|
||||
if not isinstance(high[name][key], list):
|
||||
continue
|
||||
if '.' in key:
|
||||
comps = key.split('.')
|
||||
# Salt doesn't support state files such as:
|
||||
#
|
||||
# /etc/redis/redis.conf:
|
||||
# file.managed:
|
||||
# - source: salt://redis/redis.conf
|
||||
# - user: redis
|
||||
# - group: redis
|
||||
# - mode: 644
|
||||
# file.comment:
|
||||
# - regex: ^requirepass
|
||||
#
|
||||
# XXX: Bad example here since no features requiring a
|
||||
# master should be here.
|
||||
if comps[0] in skeys:
|
||||
errors.append(
|
||||
'Name \'{0}\' in template \'{1}\' contains '
|
||||
'multiple state decs of the same type'.format(
|
||||
name, template
|
||||
)
|
||||
)
|
||||
continue
|
||||
high[name][comps[0]] = high[name].pop(key)
|
||||
high[name][comps[0]].append(comps[1])
|
||||
skeys.add(comps[0])
|
||||
continue
|
||||
skeys.add(key)
|
||||
|
||||
#if '__sls__' not in high[name]:
|
||||
# high[name]['__sls__'] = template
|
||||
#if '__env__' not in high[name]:
|
||||
# high[name]['__env__'] = None
|
||||
|
||||
return high, errors
|
||||
|
||||
def call_template(self, template):
|
||||
'''
|
||||
Enforce the states in a template
|
||||
'''
|
||||
high = compile_template(
|
||||
template, self.rend, self.opts['renderer'])
|
||||
if high:
|
||||
return self.call_high(high)
|
||||
return high
|
||||
if not high:
|
||||
return high
|
||||
high, errors = self.render_template(high, template)
|
||||
if errors:
|
||||
return errors
|
||||
return self.call_high(high)
|
||||
|
||||
def call_template_str(self, template):
|
||||
'''
|
||||
|
@ -1070,9 +1154,12 @@ class State(object):
|
|||
'''
|
||||
high = compile_template_str(
|
||||
template, self.rend, self.opts['renderer'])
|
||||
if high:
|
||||
return self.call_high(high)
|
||||
return high
|
||||
if not high:
|
||||
return high
|
||||
high, errors = self.render_template(high, '<template-str>')
|
||||
if errors:
|
||||
return errors
|
||||
return self.call_high(high)
|
||||
|
||||
|
||||
class BaseHighState(object):
|
||||
|
|
|
@ -209,6 +209,17 @@ fi
|
|||
if os.path.isdir(venv_dir):
|
||||
shutil.rmtree(venv_dir)
|
||||
|
||||
# Now using state.template
|
||||
try:
|
||||
ret = self.run_function('state.template', [template_path])
|
||||
self.assertTrue(isinstance(ret, dict))
|
||||
self.assertNotEqual(ret, {})
|
||||
for part in ret.itervalues():
|
||||
self.assertTrue(part['result'])
|
||||
finally:
|
||||
if os.path.isdir(venv_dir):
|
||||
shutil.rmtree(venv_dir)
|
||||
|
||||
# Now the problematic #2068 including dot's
|
||||
try:
|
||||
ret = self.run_function(
|
||||
|
@ -246,6 +257,17 @@ fi
|
|||
if os.path.isdir(venv_dir):
|
||||
shutil.rmtree(venv_dir)
|
||||
|
||||
# Now using state.template
|
||||
try:
|
||||
ret = self.run_function('state.template', [template_path])
|
||||
self.assertTrue(isinstance(ret, dict))
|
||||
self.assertNotEqual(ret, {})
|
||||
for part in ret.itervalues():
|
||||
self.assertTrue(part['result'])
|
||||
finally:
|
||||
if os.path.isdir(venv_dir):
|
||||
shutil.rmtree(venv_dir)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
|
|
Loading…
Add table
Reference in a new issue