<p>This templated SLS file works splendidly:</p>

<pre><code>{% if 'components' in salt.pillar.items() %}

include:
{% for component in salt.pillar.get('components').keys() %}
  - {{ component }}
{% endfor %}

{% endif %}
</code></pre>

<p>However, it requires changing my pillar key structure. From the original question, you see the structure as:</p>

<pre><code>my-minion-id:
    ----------
    components:
        - a-dependency-name
</code></pre>

<p>Instead, it needs to be:</p>

<pre><code>my-minion-id:
    ----------
    components:
        ----------
        a-dependency-name:
            None
</code></pre>

<p>Note that <code>a-dependency-name</code> is now a dict, and has a single key/value, <code>None</code>. Thus the pillar SLS file needs to change from</p>

<pre><code>components:
  - a-dependency-name
</code></pre>

<p>to</p>

<pre><code>components:
  a-dependency-name: ~
</code></pre>

<p>While you can get away with not using no-value dictionaries (and thus get rid of the <code>.keys()</code> in the template) and use lists instead, if you do that, you can't merge the <code>components</code> from multiple different pillars; each pillar Salt applies will override the <code>components</code> key from the previous, and the last pillar read will win. If you want to merge pillars (we <em>are</em> talking about role-based assignment, here), this would appear to be the necessary construct.</p>

<p>With that, the output of <code>salt my-minion-id state.show_sls components</code> is then correct:</p>

<pre><code>$ salt my-minion-id state.show_sls components
my-minion-id:
    ----------
    a-dependency-name:
      ----------
      ...
</code></pre>

<p><code>pillar.items()</code> in Jinja templates turns out not to be <em>quite</em> equivalent to <code>salt.pillar.items()</code>; if you try using <code>pillar.ls()</code>, for example, you may see the following error:</p>

<pre><code>Rendering SLS 'base:components' failed: Jinja variable 'salt.pillar object' has no attribute 'ls'
</code></pre>

<p>Whether that means one should avoid the implicit <code>salt.</code> prefix shortcut Jinja provides, or instead use a construct like <code>{% if pillar['components'] is defined %}</code> (thanks, @brousch, for the advice), I can't say.</p>

CC BY-SA 3.0
2017-04-18T20:00:43.057Z
2017-04-19T15:31:54.843Z
2017-04-19T15:31:54.843Z
Michael Mol
<p>You can also do it like:</p>

<pre><code>{% if pillar['components'] is defined %}
include:
{% for component in pillar['components'] %}
 - {{ component }}
{% endfor %}
{% endif %}

{% if pillar['components'] is defined %}
components:
  require:
{% for component in pillar['components'] %}
 - {{ component }}
{% endfor %}
{% endif %}
</code></pre>

CC BY-SA 3.0
2017-04-18T20:07:54.007Z
2017-04-18T20:07:54.007Z
brousch
<p>I'm trying to create a dummy state in Salt to pull dependencies from a list derived from a pillar.</p>

<p>In my <code>top.sls</code> file, I have:</p>

<pre><code>base:
  '*':
    - components
</code></pre>

<p>Then, in <code>components.sls</code>, I have:</p>

<pre><code>{% if 'components' in pillar.items() %}
include:
{% for component in pillar.get('components',[]) %}
  - {{ component }}
{% endfor %}
{% endif %}

{% if 'components' in pillar.items() %}
components:
  require:
{% for component in pillar.get('components',[]) %}
    - {{ component }}
{% endfor %}
{% endif %}
</code></pre>

<p>When I check the pillar contents, I see:</p>

<pre><code>$ salt my-minion-id pillar.items

my-minion-id:
    ----------
    components:
        - a-dependency-name
</code></pre>

<p>But when I try to see the set of states, I see:</p>

<pre><code>$ salt my-minion-id state.show_sls components

my-minion-id:
    ----------
</code></pre>

<p>...and that's it.</p>

<p>My ultimate goal, here, is to treat the minion as hostile, so I'm trying to pull role details out of pillars instead of assigning roles in my <code>file_root</code>'s <code>top.sls</code>. It's my understanding that every minion has full access to the contents of the file_root, and I don't want a hostile minion to know the specific firewall or services of any unrelated node.</p>

<p><strong>Edit:</strong></p>

<p>I discovered that my pillar structure didn't support pillar merging, as it used lists, so I switched to a pillar-structure that used no-value dicts:</p>

<pre><code>my-minion-id:
    ----------
    components:
        ----------
        a-dependency-name:
            None
</code></pre>

CC BY-SA 3.0
2017-04-18T18:36:49.057Z
Pretty advanced question on salt stack, genuine question from a Chef user: I had understood salt as a push model, how could a node (minion ?) register itself ? (That's just out of curiosity)
Tensibai
CC BY-SA 3.0
2017-04-18T18:38:27.980Z
Ask that as a separate question, and I'll see if I can put together a satisfactory answer without bouncing against my NDA.
Michael Mol
CC BY-SA 3.0
2017-04-18T18:41:43.003Z
Fair enough, but my last inspection of salt stack didn't meet my requirements (specially on windows boxes) so I'll see if I can make something unbiased and if I really have time to. Tried as comment just in case I missed something obvious :)
Tensibai
CC BY-SA 3.0
2017-04-18T18:43:26.100Z
I don't have enough rep for chat yet, so this will have to do. But in brief: A salt minion running on a node will use DNS to find out where its salt master is, and will reach out  to the master. Master will dump the minion's key into a pending queue until someone accepts it.
Michael Mol
CC BY-SA 3.0
2017-04-18T18:43:48.947Z
(And wouldn't "unbiased" questions be more a wiki thing? Dunno.)
Michael Mol
CC BY-SA 3.0
2017-04-18T18:46:41.993Z
As far as I know association bonus works for chat, you have far over 20, so this should work for [chat] :) Thanks for the pointer minions can  ask to be registered themselves, I had missed this approach
Tensibai
CC BY-SA 3.0
2017-04-18T18:47:09.383Z
Let us [continue this discussion in chat](http://chat.stackexchange.com/rooms/57307/discussion-between-michael-mol-and-tensibai).
Michael Mol
<dependency-management><salt><jinja><templating>
Constructing Dependencies from a Pillar in Saltstack
Michael Mol
# Constructing Dependencies from a Pillar in Saltstack

(Asked by: username_0 on 2017-04-18)

I'm trying to create a dummy state in Salt to pull dependencies from a list derived from a pillar.
In my top.sls file, I have:
base:
  '*':
    - components

Then, in components.sls, I have:
{% if 'components' in pillar.items() %}
include:
{% for component in pillar.get('components',[]) %}
  - {{ component }}
{% endfor %}
{% endif %}

{% if 'components' in pillar.items() %}
components:
  require:
{% for component in pillar.get('components',[]) %}
    - {{ component }}
{% endfor %}
{% endif %}

When I check the pillar contents, I see:
$ salt my-minion-id pillar.items

my-minion-id:
    ----------
    components:
        - a-dependency-name

But when I try to see the set of states, I see:
$ salt my-minion-id state.show_sls components

my-minion-id:
    ----------

...and that's it.
My ultimate goal, here, is to treat the minion as hostile, so I'm trying to pull role details out of pillars instead of assigning roles in my file_root's top.sls. It's my understanding that every minion has full access to the contents of the file_root, and I don't want a hostile minion to know the specific firewall or services of any unrelated node.
Edit:
I discovered that my pillar structure didn't support pillar merging, as it used lists, so I switched to a pillar-structure that used no-value dicts:
my-minion-id:
    ----------
    components:
        ----------
        a-dependency-name:
            None

**Tags:** dependency-management, salt, jinja, templating

> **Comments:**
> **username_1**: Pretty advanced question on salt stack, genuine question from a Chef user: I had understood salt as a push model, how could a node (minion ?) register itself ? (That's just out of curiosity)  
> **username_0**: Ask that as a separate question, and I'll see if I can put together a satisfactory answer without bouncing against my NDA.  
> **username_1**: Fair enough, but my last inspection of salt stack didn't meet my requirements (specially on windows boxes) so I'll see if I can make something unbiased and if I really have time to. Tried as comment just in case I missed something obvious :)  
> **username_0**: I don't have enough rep for chat yet, so this will have to do. But in brief: A salt minion running on a node will use DNS to find out where its salt master is, and will reach out  to the master. Master will dump the minion's key into a pending queue until someone accepts it.  
> **username_0**: (And wouldn't "unbiased" questions be more a wiki thing? Dunno.)  
> **username_1**: As far as I know association bonus works for chat, you have far over 20, so this should work for [chat] :) Thanks for the pointer minions can  ask to be registered themselves, I had missed this approach  
> **username_0**: Let us [continue this discussion in chat](http://chat.stackexchange.com/rooms/57307/discussion-between-michael-mol-and-tensibai).  

---

## 2 answers

### Answer by username_0 on 2017-04-18. Score: 4 | Accepted answer

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 components
my-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, @username_2, for the advice), I can't say.


---

### Answer by username_2 on 2017-04-18. Score: 3

You can also do it like:
{% if pillar['components'] is defined %}
include:
{% for component in pillar['components'] %}
 - {{ component }}
{% endfor %}
{% endif %}

{% if pillar['components'] is defined %}
components:
  require:
{% for component in pillar['components'] %}
 - {{ component }}
{% endfor %}
{% endif %}


---

