For those of you not in the know, dunder refers to a variable that is preceded and succeeded by two underscores. For instance, one of the most common dunders in Salt is __opts__
, which contains the configuration for either the Master or the Minion, depending on the context. There are a number of dunders that work together to form the glue that ties all of Salt together. Let's take a look at them in turn:
__opts__
: On a Master, the__opts__
dictionary contains a composite of the information located in the Master's configuration files (normally/etc/salt/master
plus files located in the/etc/salt/master.d/
directory), along with the default values for configuration parameters not specified, plus any internal configuration that Salt generates for its own use at runtime.On a Minion,
__opts__
contains the same sort of information (but from the/etc/salt/minion
file and the/etc/salt/minion.d/
directory), when it is connected to the Master. However, when the Minion is used in a Masterless mode (such as when called fromsalt-call --local
), any defaults are filled in as if it were a Master, rather than a Minion. This is because lookups such as pillars and files need to be provided from a Master of some sort, and in this capacity the Minion needs to play that role.__salt__
: In modules that run on the Minions (most notably execution and state modules),__salt__
contains a list of function calls to all of the available execution modules on the system. These items can be called directly, as if they were functions inside the calling module itself. For example:__salt__['disk.usage']() __salt__['cmd.run']('ls -l /') __salt__['cmd.run']('dir c:\\')
Using a function in this way is referred to as cross-calling. Because it calls out to execution modules, which are only available as a Minion, the Master does not make use of cross-calling.
__grains__
: Another Minion-only dunder is the__grains__
dictionary, which contains a copy of all of the grains computed for the Minion. This is used extensively throughout Salt to help Minions auto-detect what kinds of resources are available. It is possible to startsalt-call
without detecting grains by passing the--skip-grains
flag, like this:# salt-call --local --skip-grains test.ping
You will notice that if you try this, the Minion responds much more quickly. But if you try to use any modules much more advanced than
test
, you will quickly find out how important grains are to the functionality of the Minion.__pillar__
: Pillars have their own dunder dictionary as well, whose name is strangely singular (__pillar__
instead of__pillars__
). Unlike grains, which are generated by the Minion, pillars are generated by the Master. However, if you runsalt-call
in--local
mode like this, you will discover that as__opts__
now contains Master-side configuration, pillar configuration that would normally live on the Master will now be accepted by the Minion:# salt-call --local test.ping
This is incredibly useful for writing and debugging pillar modules, since you don't run the risk of contaminating other Minions with bad pillar data.
__context__
: This dictionary is available both to state and execution modules. When Salt fires up the first execution module (which will be thestate
module on a state run), it creates the__context__
dictionary. All of the information entered into this dictionary will persist across each subsequent module, so that different modules have a means of storing information for later use by another module. Once the final module has finished, the__context__
dictionary will be destroyed.Make sure that if you decide to use
__context__
, you check for the existence of keys in it before trying to set or use them. This is because you really have no way of knowing beforehand which order somebody will use modules in, so you shouldn't assume that things have or have not been populated.
Note
For more information about Salt dunders, check out:
https://docs.saltstack.com/en/latest/topics/development/dunder_dictionaries.html