mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Add some docs on render pipe.
Also, added a stateconf state so that its stateconf.set function can be used by the stateconf renderer.
This commit is contained in:
parent
a76331e0e1
commit
7f3ac3fe89
5 changed files with 84 additions and 52 deletions
|
@ -45,6 +45,39 @@ use the Python or ``py`` renderer:
|
|||
|
||||
The first line is a shebang that references the ``py`` renderer.
|
||||
|
||||
Composing Renderers
|
||||
-------------------
|
||||
A render can be composed from other renderers by connecting them in a series
|
||||
of pipes(``|``). In fact, the default ``Jinja + YAML`` renderer is implemented
|
||||
by combining a yaml renderer and a jinja renderer. Such renderer configuration
|
||||
is specified as: ``jinja | yaml``.
|
||||
|
||||
Other renderer combinations are possible, here's a few examples:
|
||||
|
||||
``yaml``
|
||||
i.e, just YAML, no templating.
|
||||
|
||||
``mako | yaml``
|
||||
pass the input to the ``mako`` renderer, whose output is then fed into the
|
||||
``yaml`` renderer.
|
||||
|
||||
``jinja | mako | yaml``
|
||||
This one allows you to use both jinja and mako templating syntax in the
|
||||
input and then parse the final rendererd output as YAML.
|
||||
|
||||
For backward compatibility, ``jinja | yaml`` can also be written as
|
||||
``yaml_jinja``, and similarly, the ``yaml_mako``, ``yaml_wempy``,
|
||||
``json_jinja``, ``json_mako``, and ``json_wempy`` renderers are all supported
|
||||
as well.
|
||||
|
||||
Keep in mind that not all renderers can be used alone or with any other renderers.
|
||||
For example, the template renderers shouldn't be used alone as their outputs are
|
||||
just strings, which still need to be parsed by another renderer to turn them into
|
||||
highstate data structures. Also, for example, it doesn't make sense to specify
|
||||
``yaml | jinja`` either, because the output of the yaml renderer is a highstate
|
||||
data structure(a dict in Python), which cannot be used as the input to a template
|
||||
renderer. Therefore, when combining renderers, you should know what each renderer
|
||||
accepts as input and what it returns as output.
|
||||
|
||||
Writing Renderers
|
||||
-----------------
|
||||
|
@ -64,26 +97,13 @@ renderers included with Salt can be found here:
|
|||
|
||||
:blob:`salt/renderers`
|
||||
|
||||
Here is a simple Jinja + YAML example:
|
||||
Here is a simple YAML renderer example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Import Python libs
|
||||
import os
|
||||
|
||||
# Import Third Party libs
|
||||
import yaml
|
||||
from jinja2 import Template
|
||||
|
||||
def render(template):
|
||||
'''
|
||||
Render the data passing the functions and grains into the rendering system
|
||||
'''
|
||||
if not os.path.isfile(template):
|
||||
return {}
|
||||
passthrough = {}
|
||||
passthrough.update(__salt__)
|
||||
passthrough.update(__grains__)
|
||||
template = Template(open(template, 'r').read())
|
||||
yaml_data = template.render(**passthrough)
|
||||
return yaml.load(yaml_data)
|
||||
def render(yaml_data, env='', sls='', argline='', **kws):
|
||||
if not isinstance(yaml_data, basestring):
|
||||
yaml_data = yaml_data.read()
|
||||
data = yaml.load(yaml_data)
|
||||
return data if data else {}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""
|
||||
This module provides a custom renderer that process a salt file with a
|
||||
specified templating engine(eg, jinja) and a chosen data renderer(eg, yaml),
|
||||
extract arguments for any ``state.config`` state and provide the extracted
|
||||
extract arguments for any ``stateconf.set`` state and provide the extracted
|
||||
arguments (including salt specific args, such as 'require', etc) as template
|
||||
context. The goal is to make writing reusable/configurable/ parameterized
|
||||
salt files easier and cleaner, therefore, additionally, it also:
|
||||
|
@ -14,12 +14,12 @@ salt files easier and cleaner, therefore, additionally, it also:
|
|||
<%include file="templates/sls-parts.mako"/>
|
||||
<%namespace file="salt://lib/templates/utils.mako" import="helper"/>
|
||||
|
||||
- Recognizes the special state function, ``state.config``, that configures a
|
||||
- Recognizes the special state function, ``stateconf.set``, that configures a
|
||||
default list of named arguments useable within the template context of
|
||||
the salt file. Example::
|
||||
|
||||
sls_params:
|
||||
state.config:
|
||||
stateconf.set:
|
||||
- name1: value1
|
||||
- name2: value2
|
||||
- name3:
|
||||
|
@ -41,10 +41,10 @@ salt files easier and cleaner, therefore, additionally, it also:
|
|||
|
||||
This even works with ``include`` + ``extend`` so that you can override
|
||||
the default configured arguments by including the salt file and then extend
|
||||
the ``state.config`` states that come from the included salt file.
|
||||
the ``stateconf.set`` states that come from the included salt file.
|
||||
|
||||
Notice that the end of configuration marker(``# --- end of state config --``)
|
||||
is needed to separate the use of 'state.config' form the rest of your salt
|
||||
is needed to separate the use of 'stateconf.set' form the rest of your salt
|
||||
file.
|
||||
|
||||
- Adds support for relative include and exclude of .sls files. Example::
|
||||
|
@ -89,7 +89,7 @@ salt files easier and cleaner, therefore, additionally, it also:
|
|||
|
||||
extend:
|
||||
.file::sls_params:
|
||||
state.config:
|
||||
stateconf.set:
|
||||
- name1: something
|
||||
|
||||
Above will be pre-processed into::
|
||||
|
@ -99,11 +99,11 @@ salt files easier and cleaner, therefore, additionally, it also:
|
|||
|
||||
extend:
|
||||
some.file::sls_params:
|
||||
state.config:
|
||||
stateconf.set:
|
||||
- name1: something
|
||||
|
||||
- Optionally(disable via the `-G` renderer option), generates a
|
||||
``state.config`` goal state(state id named as ``.goal`` by default) that
|
||||
``stateconf.set`` goal state(state id named as ``.goal`` by default) that
|
||||
requires all other states in the salt file.
|
||||
|
||||
Such goal state is intended to be required by some state in an including
|
||||
|
@ -168,7 +168,7 @@ re-write or renames state id's and their references.
|
|||
# - support synthetic argument? Eg,
|
||||
#
|
||||
# apache:
|
||||
# state.config:
|
||||
# stateconf.set:
|
||||
# - host: localhost
|
||||
# - port: 1234
|
||||
# - url: 'http://${host}:${port}/'
|
||||
|
@ -176,7 +176,7 @@ re-write or renames state id's and their references.
|
|||
# Currently, this won't work, but can be worked around like so:
|
||||
#
|
||||
# apache:
|
||||
# state.config:
|
||||
# stateconf.set:
|
||||
# - host: localhost
|
||||
# - port: 1234
|
||||
# ## - url: 'http://${host}:${port}/'
|
||||
|
@ -202,11 +202,24 @@ __opts__ = {
|
|||
'stateconf_end_marker': r'#\s*-+\s*end of state config\s*-+',
|
||||
# eg, something like "# --- end of state config --" works by default.
|
||||
|
||||
'stateconf_goal_state': '.goal'
|
||||
'stateconf_goal_state': '.goal',
|
||||
# name of the state id for the generated goal state.
|
||||
|
||||
'stateconf_state_func': 'stateconf.set'
|
||||
# names the state and the state function to be recognized as a special state
|
||||
# from which to gather sls file context variables. It should be specified
|
||||
# in the 'state.func' notation, and both the state module and the function must
|
||||
# actually exist and the function should be a dummy, no-op state function that
|
||||
# simply returns a dict(name=name, result=True, changes={}, comment='')
|
||||
}
|
||||
|
||||
|
||||
STATE_FUNC = STATE_NAME = ''
|
||||
|
||||
STATE_FUNC = __opts__['stateconf_state_func']
|
||||
STATE_NAME = STATE_FUNC.split('.')[0]
|
||||
|
||||
|
||||
MOD_BASENAME = ospath.basename(__file__)
|
||||
INVALID_USAGE_ERROR = SaltRenderError(
|
||||
"Invalid use of %s renderer!\n"
|
||||
|
@ -318,7 +331,7 @@ def render(template_file, env='', sls='', argline='', **kws):
|
|||
process_sls_data(sls_templ[:match.start()], extract=True)
|
||||
|
||||
# if some config has been extracted then remove the sls-name prefix
|
||||
# of the keys in the extracted state.config context to make them easier
|
||||
# of the keys in the extracted stateconf.set context to make them easier
|
||||
# to use in the salt file.
|
||||
if STATE_CONF:
|
||||
tmplctx = STATE_CONF.copy()
|
||||
|
@ -526,7 +539,7 @@ def add_goal_state(data):
|
|||
for sid, _, state, _ in \
|
||||
statelist(data, set(['include', 'exclude', 'extend'])):
|
||||
reqlist.append({state_name(state): sid})
|
||||
data[goal_sid] = {'state.config': [dict(require=reqlist)]}
|
||||
data[goal_sid] = {STATE_FUNC: [dict(require=reqlist)]}
|
||||
|
||||
def state_name(sname):
|
||||
"""Return the name of the state regardless if sname is
|
||||
|
@ -545,14 +558,14 @@ class Bunch(dict):
|
|||
# With sls:
|
||||
#
|
||||
# state_id:
|
||||
# state.config:
|
||||
# stateconf.set:
|
||||
# - name1: value1
|
||||
#
|
||||
# STATE_CONF is:
|
||||
# { state_id => {name1: value1} }
|
||||
#
|
||||
STATE_CONF = {} # state.config
|
||||
STATE_CONF_EXT = {} # state.config under extend: ...
|
||||
STATE_CONF = {} # stateconf.set
|
||||
STATE_CONF_EXT = {} # stateconf.set under extend: ...
|
||||
|
||||
def extract_state_confs(data, is_extend=False):
|
||||
for state_id, state_dict in data.iteritems():
|
||||
|
@ -560,10 +573,10 @@ def extract_state_confs(data, is_extend=False):
|
|||
extract_state_confs(state_dict, True)
|
||||
continue
|
||||
|
||||
if 'state' in state_dict:
|
||||
key = 'state'
|
||||
elif 'state.config' in state_dict:
|
||||
key = 'state.config'
|
||||
if STATE_NAME in state_dict:
|
||||
key = STATE_NAME
|
||||
elif STATE_FUNC in state_dict:
|
||||
key = STATE_FUNC
|
||||
else:
|
||||
continue
|
||||
|
||||
|
|
|
@ -138,14 +138,6 @@ def _is_true(v):
|
|||
raise ValueError('Failed parsing boolean value: {0}'.format(v))
|
||||
|
||||
|
||||
def _no_op(name, **kws):
|
||||
'''
|
||||
No-op state to support state config via the stateconf renderer.
|
||||
'''
|
||||
return dict(name=name, result=True, changes={}, comment='')
|
||||
config = _no_op
|
||||
|
||||
|
||||
def _run_check(cmd_kwargs, onlyif, unless, cwd, user, group, shell):
|
||||
'''
|
||||
Execute the onlyif logic and return data if the onlyif fails
|
||||
|
|
7
salt/states/stateconf.py
Normal file
7
salt/states/stateconf.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
def _no_op(name, **kws):
|
||||
'''
|
||||
No-op state to support state config via the stateconf renderer.
|
||||
'''
|
||||
return dict(name=name, result=True, changes={}, comment='')
|
||||
|
||||
set = context = _no_op
|
|
@ -31,13 +31,13 @@ class StateConfigRendererTestCase(TestCase):
|
|||
def test_state_config(self):
|
||||
result = render_sls('''
|
||||
.sls_params:
|
||||
state.config:
|
||||
stateconf.set:
|
||||
- name1: value1
|
||||
- name2: value2
|
||||
|
||||
.extra:
|
||||
state:
|
||||
- config
|
||||
stateconf:
|
||||
- set
|
||||
- name: value
|
||||
|
||||
# --- end of state config ---
|
||||
|
@ -151,7 +151,7 @@ extend:
|
|||
''', sls='test.goalstate', argline='yaml . jinja')
|
||||
self.assertTrue(len(result), len('ABCDE')+1)
|
||||
|
||||
reqs = result['test.goalstate::goal']['state.config'][0]['require']
|
||||
reqs = result['test.goalstate::goal']['stateconf.set'][0]['require']
|
||||
self.assertEqual(set([i.itervalues().next() for i in reqs]),
|
||||
set('ABCDE'))
|
||||
|
||||
|
@ -201,7 +201,7 @@ G:
|
|||
self.assertEqual(G_req[1]['cmd'], 'D')
|
||||
self.assertEqual(G_req[2]['cmd'], 'F')
|
||||
|
||||
goal_args = result['test::goal']['state.config']
|
||||
goal_args = result['test::goal']['stateconf.set']
|
||||
self.assertEqual(len(goal_args), 1)
|
||||
self.assertEqual(
|
||||
[i.itervalues().next() for i in goal_args[0]['require']],
|
||||
|
|
Loading…
Add table
Reference in a new issue