7

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
7
  • 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)
    – Tensibai
    Commented Apr 18, 2017 at 18:36
  • Ask that as a separate question, and I'll see if I can put together a satisfactory answer without bouncing against my NDA. Commented Apr 18, 2017 at 18:38
  • 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
    Commented Apr 18, 2017 at 18:41
  • 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. Commented Apr 18, 2017 at 18:43
  • 1
    As far as I know association bonus works for chat, you have far over 20, so this should work for DevOps Chat :) Thanks for the pointer minions can ask to be registered themselves, I had missed this approach
    – Tensibai
    Commented Apr 18, 2017 at 18:46

2 Answers 2

4

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

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 %}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.