salt/doc/topics/grains/index.rst

298 lines
8.9 KiB
ReStructuredText
Raw Normal View History

.. _grains:
======
Grains
======
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, though if system information changes
(for example, if network settings are changed), 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.
Listing Grains
==============
Available grains can be listed by using the 'grains.ls' module:
.. code-block:: bash
salt '*' grains.ls
Grains data can be listed by using the 'grains.items' module:
.. code-block:: bash
salt '*' grains.items
.. _static-custom-grains:
Grains in the Minion Config
===========================
Grains can also be statically assigned within the minion configuration file.
Just add the option :conf_minion:`grains` and pass options to it:
.. code-block:: yaml
grains:
roles:
- webserver
- memcache
deployment: datacenter4
cabinet: 13
cab_u: 14-15
Then status data specific to your servers can be retrieved via Salt, or used
inside of the State system for matching. It also makes targeting, in the case
of the example above, simply based on specific data about your deployment.
Grains in /etc/salt/grains
==========================
If you do not want to place your custom static grains in the minion config
file, you can also put them in ``/etc/salt/grains`` on the minion. They are configured in the
same way as in the above example, only without a top-level ``grains:`` key:
.. code-block:: yaml
roles:
- webserver
- memcache
deployment: datacenter4
cabinet: 13
cab_u: 14-15
Matching Grains in the Top File
===============================
With correctly configured grains on the Minion, the :term:`top file` used in
Pillar or during Highstate can be made very efficient. For example, consider
the following configuration:
.. code-block:: yaml
'node_type:webserver':
- match: grain
- webserver
'node_type:postgres':
- match: grain
- postgres
'node_type:redis':
- match: grain
- redis
'node_type:lb':
- match: grain
- lb
For this example to work, you would need to have defined the grain
``node_type`` for the minions you wish to match. This simple example is nice,
but too much of the code is similar. To go one step further, Jinja templating
can be used to simplify the :term:`top file`.
.. code-block:: yaml
{% set the_node_type = salt['grains.get']('node_type', '') %}
{% if the_node_type %}
'node_type:{{ the_node_type }}':
- match: grain
- {{ the_node_type }}
{% endif %}
Using Jinja templating, only one match entry needs to be defined.
.. note::
The example above uses the :mod:`grains.get <salt.modules.grains.get>`
function to account for minions which do not have the ``node_type`` grain
set.
.. _writing-grains:
Writing Grains
==============
The grains are derived by executing all of the "public" functions (i.e. those
which do not begin with an underscore) found in the modules located in the
Salt's core grains code, followed by those in any custom grains modules. The
functions in a grains module must return a Python :ref:`dict
<python2:typesmapping>`, where the dictionary keys are the names of grains, and
each key's value is that value for that grain.
Custom grains modules should be placed in a subdirectory named ``_grains``
located under the :conf_master:`file_roots` specified by the master config
file. The default path would be ``/srv/salt/_grains``. Custom grains modules
will be distributed to the minions when :mod:`state.highstate
<salt.modules.state.highstate>` is run, or by executing the
:mod:`saltutil.sync_grains <salt.modules.saltutil.sync_grains>` or
:mod:`saltutil.sync_all <salt.modules.saltutil.sync_all>` functions.
Grains modules are easy to write, and (as noted above) only need to return a
dictionary. For example:
.. code-block:: python
def yourfunction():
# initialize a grains dictionary
grains = {}
# Some code for logic that sets grains like
grains['yourcustomgrain'] = True
grains['anothergrain'] = 'somevalue'
return grains
When to Use a Custom Grain
--------------------------
Before adding new grains, consider what the data is and remember that grains
should (for the most part) be static data.
If the data is something that is likely to change, consider using :doc:`Pillar
<../pillar/index>` or an execution module instead. If it's a simple set of
key/value pairs, pillar is a good match. If compiling the information requires
that system commands be run, then putting this information in an execution
module is likely a better idea.
Good candidates for grains are data that is useful for targeting minions in the
:ref:`top file <states-top>` or the Salt CLI. The name and data structure of
the grain should be designed to support many platforms, operating systems or
applications. Also, keep in mind that Jinja templating in Salt supports
referencing pillar data as well as invoking functions from execution modules,
so there's no need to place information in grains to make it available to Jinja
templates. For example:
.. code-block:: text
...
...
{{ salt['module.function_name']('argument_1', 'argument_2') }}
{{ pillar['my_pillar_key'] }}
...
...
.. warning::
Custom grains will not be available in the top file until after the first
:ref:`highstate <running-highstate>`. To make custom grains available on a
minion's first highstate, it is recommended to use :ref:`this example
<minion-start-reactor>` to ensure that the custom grains are synced when
the minion starts.
Loading Custom Grains
---------------------
If you have multiple functions specifying grains that are called from a ``main``
function, be sure to prepend grain function names with an underscore. This prevents
Salt from including the loaded grains from the grain functions in the final
grain data structure. For example, consider this custom grain file:
.. code-block:: python
#!/usr/bin/env python
def _my_custom_grain():
my_grain = {'foo': 'bar', 'hello': 'world'}
return my_grain
def main():
# initialize a grains dictionary
grains = {}
grains['my_grains'] = _my_custom_grain()
return grains
The output of this example renders like so:
.. code-block:: bash
# salt-call --local grains.items
local:
----------
<Snipped for brevity>
my_grains:
----------
foo:
bar
hello:
world
However, if you don't prepend the ``my_custom_grain`` function with an underscore,
the function will be rendered twice by Salt in the items output: once for the
``my_custom_grain`` call itself, and again when it is called in the ``main``
function:
.. code-block:: bash
# salt-call --local grains.items
local:
----------
<Snipped for brevity>
foo:
bar
<Snipped for brevity>
hello:
world
<Snipped for brevity>
my_grains:
----------
foo:
bar
hello:
world
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. Core grains.
2. Custom grains in ``/etc/salt/grains``.
3. Custom grains in ``/etc/salt/minion``.
4. Custom grain modules in ``_grains`` directory, synced to minions.
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.
Examples of Grains
==================
The core module in the grains package is where the main grains are loaded by
the Salt minion and provides the principal example of how to write grains:
:blob:`salt/grains/core.py`
Syncing Grains
==============
Syncing grains can be done a number of ways, they are automatically synced when
:mod:`state.highstate <salt.modules.state.highstate>` is called, or (as noted
above) the grains can be manually synced and reloaded by calling the
:mod:`saltutil.sync_grains <salt.modules.saltutil.sync_grains>` or
:mod:`saltutil.sync_all <salt.modules.saltutil.sync_all>` functions.