This templated SLS file works splendidly:
{% if 'components' in salt.pillar.items() %}include:{% for component in salt.pillar.get('components').keys() %} - {{ component }}{% endfor %}{% endif %}
However, it requires changing my pillar key structure. From the original question, you see the structure as:
my-minion-id: ---------- components: - a-dependency-name
Instead, it needs to be:
my-minion-id: ---------- components: ---------- a-dependency-name: None
Note that a-dependency-name
is now a dict, and has a single key/value, None
. Thus the pillar SLS file needs to change from
components: - a-dependency-name
to
components: a-dependency-name: ~
While you can get away with not using no-value dictionaries (and thus get rid of the .keys()
in the template) and use lists instead, if you do that, you can't merge the components
from multiple different pillars; each pillar Salt applies will override the components
key from the previous, and the last pillar read will win. If you want to merge pillars (we are talking about role-based assignment, here), this would appear to be the necessary construct.
With that, the output of salt my-minion-id state.show_sls components
is then correct:
$ salt my-minion-id state.show_sls componentsmy-minion-id: ---------- a-dependency-name: ---------- ...
pillar.items()
in Jinja templates turns out not to be quite equivalent to salt.pillar.items()
; if you try using pillar.ls()
, for example, you may see the following error:
Rendering SLS 'base:components' failed: Jinja variable 'salt.pillar object' has no attribute 'ls'
Whether that means one should avoid the implicit salt.
prefix shortcut Jinja provides, or instead use a construct like {% if pillar['components'] is defined %}
(thanks, @brousch, for the advice), I can't say.