Answers: <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>
  
Answers: CC BY-SA 3.0
Answers: 2017-04-18T20:00:43.057Z
Answers: 2017-04-19T15:31:54.843Z
Answers: 2017-04-19T15:31:54.843Z
Answers: Michael Mol
Answers: <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>
  
Answers: CC BY-SA 3.0
Answers: 2017-04-18T20:07:54.007Z
Answers: 2017-04-18T20:07:54.007Z
Answers: brousch
Body: <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>
  
Comments: CC BY-SA 3.0
Comments: 2017-04-18T18:36:49.057Z
Comments: 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)
Comments: Tensibai
Comments: CC BY-SA 3.0
Comments: 2017-04-18T18:38:27.980Z
Comments: Ask that as a separate question, and I'll see if I can put together a satisfactory answer without bouncing against my NDA.
Comments: Michael Mol
Comments: CC BY-SA 3.0
Comments: 2017-04-18T18:41:43.003Z
Comments: 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 :)
Comments: Tensibai
Comments: CC BY-SA 3.0
Comments: 2017-04-18T18:43:26.100Z
Comments: 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.
Comments: Michael Mol
Comments: CC BY-SA 3.0
Comments: 2017-04-18T18:43:48.947Z
Comments: (And wouldn't "unbiased" questions be more a wiki thing? Dunno.)
Comments: Michael Mol
Comments: CC BY-SA 3.0
Comments: 2017-04-18T18:46:41.993Z
Comments: 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
Comments: Tensibai
Comments: CC BY-SA 3.0
Comments: 2017-04-18T18:47:09.383Z
Comments: Let us [continue this discussion in chat](http://chat.stackexchange.com/rooms/57307/discussion-between-michael-mol-and-tensibai).
Comments: Michael Mol
Tags: <dependency-management><salt><jinja><templating>
Title: Constructing Dependencies from a Pillar in Saltstack
UserDisplayName: Michael Mol
ThreadText: # 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-username_0-mol-and-username_1).  
  
  ---
  
  ## 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 %}
  
  ```
  
  
  ---
  
  