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, and minion 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.
Salt grains

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.

  1. Configure the autosign_grains_dir in the Salt master config file:

    /etc/salt/master.d/grains.conf#
    autosign_grains_dir: /etc/salt/autosign_grains
    
  2. 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:

    /etc/salt/autosign_grains/uuid#
    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.

  3. Configure the Salt minion, to send the specific grains to the Salt master, in the minion config file:

    /etc/salt/minion#
    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 file
  • Editing 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.

/etc/salt/minion.d/grains.conf#
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:

  1. Default salt defined core grains.
  2. Custom grains in /etc/salt/grains on the minion.
  3. Custom grains in /etc/salt/minion on the minion.
  4. 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.