Salt grains¶
Use case¶
Salt comes with an interface to derive information about the underlying system. This is called the grains interface, because it presents Salt with grains of information. Grains are collected for the operating system, domain name, IP address, kernel, OS type, memory, and many other system properties.
The grains interface is made available to Salt modules and components so that the right Salt minion commands are automatically available on the right systems.
Grain data is relatively static. However, if system information changes (such as network settings), or if a new value is assigned to a custom grain, grain data is refreshed.
Note
Grains resolve to lowercase letters. For example, FOO
and foo
target the same grain.
Grains of Salt key concepts¶
The following are some key concepts about grains:
Grains comprise system properties or other custom attributes.
Though grains can be defined in several ways, they are always derived or defined on the minion.
Grains cover data such as:
os
,kernel
,ip_interfaces
, andminion
id.Grains are generally used to determine things like which package manager should be used or if the init system is powered by systemctl.
The grains interface is available to Salt modules and components so that the right Salt minion commands are automatically available on the right systems.
Grains terminal commands¶
Listing grains¶
Available grains can be listed by using the grains.ls
module:
salt '*' grains.ls
Grains data can be listed by using the grains.items
module:
salt '*' grains.items
Targeting with grains¶
Grain data can be used when targeting minions.
For example, the following command matches all CentOS minions:
salt -G 'os:CentOS' test.version
This command matches all minions with 64-bit CPUs, and return number of CPU cores for each matching minion:
salt -G 'cpuarch:x86_64' grains.item num_cpus
Additionally, globs can be used in grain matches, and grains that are
nested in a dictionary can be matched by adding a colon for each level
that is traversed. For example, the following command will match hosts
that have a grain called ec2_tags
, which itself is a dictionary with a
key named environment and which has a value that contains the word
production:
salt -G 'ec2_tags:environment:*production*'
Configuration settings¶
To automatically accept minions based on certain characteristics, such as the uuid, you can specify certain grain values on the Salt master. Minions with matching grains will have their keys automatically accepted.
Configure the
autosign_grains_dir
in the Salt master config file:autosign_grains_dir: /etc/salt/autosign_grains
Configure the grain values to be accepted:
Place a file named like the grain in the
autosign_grains_dir
and write the values that should be accepted automatically inside that file. For example, to automatically accept minions based on their uuid, create a file named:8f7d68e2-30c5-40c6-b84a-df7e978a03ee 1d3c5473-1fbc-479e-b0c7-877705a0730f
The Salt master is now set up to accept minions with either of the two specified uuids. Multiple values must always be written into separate lines. Lines starting with a # are ignored.
Configure the Salt minion, to send the specific grains to the Salt master, in the
minion
config file:autosign_grains: - uuid
Now you should be able to start salt-minion
and run salt-call
state.apply
or any other Salt commands that require Salt master
authentication.
Defining custom grains¶
Custom grains can be set using various methods:
Using remote execution
Editing the
/etc/salt/grains
configuration fileEditing the minion configuration custom config file in
/etc/salt/minion.d/
Using a custom grains module.
Grains can be set dynamically at the command-line (remote execution):
salt minion01 grains.setval deployment datacenter4
The following is an example of setting a multi-value grain:
salt minion01 grains.setval roles ['web', 'app1', 'dev']
The previous examples will update the grains dictionary in memory and
persistently in the /etc/salt/grains
file on the minion.
Note
If this file is edited manually, the grain dictionary will be dynamically updated and available as soon as the file is written.
To statically set the grain data, add the data to the minion configuration. It
is recommended to create a custom minion configuration file in the
/etc/salt/minion.d/
directory.
grains:
deployment: datacenter4
cabinet: 14
switch_port: 4
roles:
- web
- app1
- dev
Note
Adding/updating grains using the minion configuration will require a restart
of the salt-minion
process.
Matching via a custom grain:
salt -G 'roles:app1' test.ping
The previous examples also illustrate an important point about grains values:
Grains can be any common data structure: string, int, list, boolean or dictionary.
When matching a grain that is a list, only a single list item will need to be matched. Therefore, the role grain could be matched with either web, app1, or dev.
Precedence¶
Core grains can be overridden by custom grains. As there are several ways of defining custom grains, there is an order of precedence which should be kept in mind when defining them. The order of evaluation is as follows:
Default salt defined core grains.
Custom grains in
/etc/salt/grains
on the minion.Custom grains in
/etc/salt/minion
on the minion.Custom grain modules in
_grains
directory on the master and synced to the minion.
Each successive evaluation overrides the previous ones, so any grains defined by
custom grains modules synced to minions that have the same name as a core grain
will override that core grain. Similarly, grains from /etc/salt/minion
override both core grains and custom grain modules, and grains in _grains
will override any grains of the same name.
For custom grains, if the function takes an argument grains, then the previously rendered grains will be passed in. Because the rest of the grains could be rendered in any order, the only grains that can be relied upon to be passed in are core grains. This was added in the 2019.2.0 release.
States with grains¶
The grains dictionary makes the minion’s grains directly available, and is available in all templates:
{{ grains['os'] }}
Note
The syntax here will cause an error if the grain does not exist.
The grains.get
function can be used to traverse deeper grains and set
defaults:
{{ salt['grains.get']('os') }}
{{ salt['grains.get']('os', ‘Debian’) }}
Note
The syntax used here will result in “None” being returned if the grain does not exist.