On Tue, Mar 14, 2017 at 2:18 PM, sandy <
windov...@gmail.com> wrote:
> when and where pillar/state code is jinja-afied and evaluated as
> a function of the master/minion location, on a time-line, more or less for
> each of the following - salt. salt-call, and salt-run. Including relevant
> data/pillar contexts. :-)
This would indeed be a great addition to the docs. CliffsNotes version:
1. A Minion requests its Pillar from the Master.
This is triggered by calling state.apply, state.highstate,
saltutil.refresh_pillar, & pillar.items. It does not matter where or
what calls any of those functions on the Minion (`salt`, `salt-call`,
Orchestrate, etc), the result is the same.
2. The Master generates Pillar for that requesting Minion.
It uses the following data: the Minion ID, the Minion's Grains
(already cached on the Master), the Minion's opts (the parsed Minion
config file).
3. Salt's normal Renderer pipeline generates the Pillar.
In short: the default pipeline is `#!jinja|yaml`, which means a
`foo.sls` is first run through the Jinja templating engine, then the
result of that is run through the YAML parser producing the final
Pillar data structure. There's a video on the SaltStack YouTube
channel that goes into Renderers in the context of the State system
but they work the same on the Master for Pillar (sorry, the screen is
hard to see):
https://youtu.be/s967lYS_nd4?t=18m48s
https://docs.saltstack.com/en/latest/ref/renderers/
4. The generated Pillar is returned to the requesting Minion.
The data structure from the previous step is shipped over the wire and
kept in-memory on the Minion for quick lookup when, say, referencing
Pillar values from within Salt States. Salt States are generated on
the Minion using the same Renderer system.
> In any case, I tried converting the code from our original 'pillar' design
> model to the 'jinja' design model as described and ran into performance
> issues
It sounds like you're doing interesting things with Pillar! There are
a few tips and tricks for when you're dealing with Pillar at large
scale or when processing many files to generate Pillar:
1. Jinja is quite fast but YAML is very slow.
YAML is nice to read but it is amazingly, astoundingly, mind-numbingly
slow to parse. If you have many SLS files using the default YAML
renderer, or if you're making frequent use of {% load_yaml %} from my
example, that alone could explain the slowness.
If you need the best possible performance don't use YAML anywhere.
Change the she-bang at the top of your .sls files to use other
Renderers instead like `#!jinja|json` or even just `#!py`. If you need
to load data in from external sources stick to JSON -- or better yet
MsgPack if you can.
A highly performant version of my example from before might be:
{# /srv/pillar/phase1.jinja #}
{% set phase_1_data = {
'phase1': {
'foo': 'Foo',
'bar': 'Bar',
'baz': salt.grains.get('os_family', 'Unknown'),
},
} %}
#!jinja|json
{# /srv/pillar/phase2.sls #}
{% from "phase1.jinja" import phase_1_data with context %}
{# Stick with Jinja data structures as long as possible. #}
{% set ret = {
'phase1': phase_1_data,
'phase2': {
'is_os_family_is_known': phase_1_data != 'Unknown',
}
} %}
{# Make the final result available as JSON. #}
{{ ret | json() }}
If you set the logging level to 'debug' on the Master it will output
log entries for how long each Renderer takes:
[PROFILE ] Time (in seconds) to render '/srv/pillar/phase2.sls' using
'jinja' renderer: 0.00707197189331
2. Pillar is generated on the Master by request for each Minion separately.
If you have many Minions you may want to stagger when each one makes
that request to avoid overloading the Master all at once.
3. If you must perform heavy operations, consider caching the result.
If your Pillar generation is doing slow things like calling out to an
API or calling slow-running functions, for example, shelling out using
`cmd.run`, you may want to cache the result of that operation locally.
Another option is to move that work down to the individual Minions to
spread out the work by putting those calls in State files or using
sdb.
https://docs.saltstack.com/en/latest/topics/sdb/
> Unfortunately the jinja
> model does not seem to scale well as a function of the number of nodes. Is
> that expected with this design? Or am I doing something fundamentally
> wrong?
Hopefully the above thoughts will steer you in the right direction.
Jinja by itself can easily scale to many, many Minions but if Jinja is
doing something slow like parsing inline YAML or shelling out then all
bets are off.