salt/doc/ref/modules/index.rst
Nicole Thomas 216d9fdc9a [develop] Merge forward from 2016.3 to develop (#32494)
* fix sorting by latest version when called with an attribute

* remove reference to master_alive_check

* Fixes saltstack/salt#28262

* Resolve memory leak in authentication

* outputter virt_list does not exist anymore

* Update proxmox documentation

* Fix documentation on boto_asg and boto_elb modules and states

* modules.win_timezone: don't list all zones in debug log

* Correcty index glusterfs bricks

Fixes issue #32311

* Cleaner deprecation process with decorators

* Add deprecation decorator scaffold

* Capture type error and unhandled exceptions while function calls

* Aware of the current and future version of deprecation

* Implement initially is_deprecated decorator

* Add an alias for the capitalization

* Fix capitalization easier way

* Remove an extra line

* Add successor name to the deprecation decorator.

* Granulate logging and error messages.

* Implement function swapper

* Raise later the caught exception

* Clarify exception message

* Save function original name

* Remove an extra line

* Hide an alternative hidden function name in the error message, preserving the error itself

* Rename variable as private

* Add a method to detect if a function is using its previous version

* Message to the log and/or raise an exception accordingly to the status of used function

* Log an error along with the exception

* Add internal method documentation

* Add documentation and usage process for decorator "is_deprecated"

* Add documentation and process usage for the decorator "with_deprecated"

* Hide private method name

* Fix PEP8, re-word the error message

* Deprecate basic uptime function

* Add initial decorator unit test

* Rename old/new functions, mock versions

* Move frequent data to the test setup

* Add logging on EOL exception

* Rename and document high to low version test on is_deprecated

* Implement a test on low to high version of is_deprecated decorator

* Add a correction to the test description

* Remove a dead code

* Implement a test for high to low version on is_deprecated, using with_successor param

* Correct typso adn mistaeks

* Implement high to low version with successor param on is_deprecated

* Setup a virtual name for the module

* Implement test for with_deprecated should raise an exception if same deprecated function not found

* Implement test for with_deprecated an old function is picked up if configured

* Correct test description purpose

* Implement test with_deprecated when no deprecation is requested

* Add logging test to the configured deprecation request

* Add logging testing when deprecated version wasn't requested

* Implement test EOL for with_deprecated decorator

* Correct test explanation

* Rename the test

* Implement with_deprecated no EOL, deprecated other function name

* Implement with_deprecated, deprecated other function name, EOL reached

* Add test description for the with_deprecated + with_name + EOL

* Fix confusing test names

* Add logging test to the is_deprecated decorator when function as not found.

* Add more test point to each test, remove empty lines

* Bugfix: at certain conditions a wrong alias name is reported to the log

* Fix a typo in a comment

* Add test for the logging

* Disable a pylint: None will _never_ be raised

* Fix test for the deprecated "status.uptime" version

* Bugfix: Do not yank raised exceptions

* Remove unnecessary decorator

* Add test for the new uptime

* Add test for the new uptime fails when /proc/uptime does not exists

* Rename old test case

* Skip test for the UTC time, unless freeze time is used.

* Fix pylint

* Fix documentation

* Bugfix: proxy-pass the docstring of the decorated function

* Lint fix

* Fixes saltstack/salt#28262 for 2015.5 branch

* Update master config docs

* Improve git_pillar documentation/logging

* Add note about different behavior of top file in git_pillar

* Make log entry for a missing pillar SLS file more accurate for git_pillar

* FreeBSD supports packages in format java/openjdk7 so the prior commit broke that functionality. Check freebsd/pkg#1409 for more info.

* FreeBSD supports packages in format java/openjdk7 so the prior commit broke that functionality. Check freebsd/pkg#1409 for more info.

* Update glusterfs_test to be inline with #32312

* Fix salt-cloud paralell provisioning

Closes #31632

* Ignore Raspbian in service.py __virtual__ (#32421)

* Ignore Raspbian in service.py __virtual__

This prevents more than one execution module from trying to load as the
service virtual module.

Refs: #32413

* pack __salt__ before loading provider overrides

We can (and should) pack here since we're just packing a reference to the
object. __salt__ needs to be available when we're loading our provider
overrides

* Fix broken __salt__ dict in provider override

Using ret.items() here sets ``__salt__`` to its items (tuple containing
function name and reference), breaking usage of ``__salt__`` inside
overridden functions.

* Merge #32293 with test fixes (#32418)

* Fix issue #11497

* Remove check for working directory presence in tests

* Fix Domainname introspection

Default value needs to be extracted from the container itself,
because dockerd set Domainname value when network_mode=host.

* Add pgjsonb_queue to queue doc index

* Pylint fixes

* Pass parser options into batch mode

Resolves #31738

* Changed the target file in file.symlink test (#32443)

* Argument name in docs should match actual arg name (#32445)

Fixes #31851

* tests.integration: bypass MacOS TMPDIR, gettempdir (#32447)

Updates 0edd532, 8f558a5.

When logging in as root over `ssh root@host`, `$TMPDIR` and
`tempfile.gettempdir()` are both set to a variation of:
```
/private/var/folders/zz/zyxvpxvq6csfxvn_n0000000000000/T/
```
When logging in as root over `sudo -i`, `$TMPDIR` is unset and
`tempfile.gettempdir()` is set to `/tmp`.

My guess is that the second case is an unintended or uncorrected omision
by Apple as they have introduced the longer, randomized temp path in a
recent version of MacOS.

* Issue #28706: Fix state user.present behavior. (#32448)

- As mentionned in issue #28706, state user.present no longer remove
      user from groups if the keyword 'groups' with empty value '[]' is not
      explicitly set, salt will assume current groups are still wanted.

* tests.integration: fix 4230c8a

* Move the tables of virtual modules to individual documentation pages

* Add new doc pages to toctree

* Add external ref to windows package manager docs

* Improve docstrings

* Add documentation on virtual module provider overrides to the module docs

* Clarify the scope of the provider param in states.

* Add link to provider override docs to all package providers

* Add link to provider override docs to all service providers

* Add link to provider override docs to all user providers

* dd link to provider override docs to all shadow providers

* Add link to provider override docs to all group providers

* Backport 31164 and 31364 (#32474)

* Don't send REQ while another one is waiting for response.

The message has to be removed from the queue the only *after* it's
already processed to don't confuse send() functionality that expects
empty queue means: there's no active sendings.

* Fixed zeromq ReqMessageClient destroy

* Add link to provider override docs to opkg.py

This is a companion to https://github.com/saltstack/salt/pull/32458, but
this module was not added until the 2016.3 branch, so the documentation
is being updated there for this module.

* Add documentation for some master/minion configs (#32454)

Refs #32400

Adds docs for:

- cli_summary
- event_return_queue
- event_return_whitelist
- event_return_blacklist
- file_recv_max_size
- fileserver_followsymlinks
- fileserver_ignoresymlinks
- fileserver_limit_traversal

* Automatically detect correct MySQL password column for 5.7 and fix setting passwords (#32440)

* Automatically detect MySQL password column

* Fix changing password in MySQL 5.7

* Fix lint test

* Fix unit tests (?)

They will still fail if "authentication_string" is legitimately the right column name, but I don't know what to do about that.

* Additional unit test fix

* Only unsub if we have a jid

Closes #32479
2016-04-11 17:07:15 -06:00

561 lines
18 KiB
ReStructuredText

.. _writing-execution-modules:
=========================
Writing Execution Modules
=========================
Salt execution modules are the functions called by the :command:`salt` command.
Modules Are Easy to Write!
==========================
Writing Salt execution modules is straightforward.
A Salt execution module is a Python or `Cython`_ module
placed in a directory called ``_modules/``
within the :conf_master:`file_roots` as specified by the master config file. By
default this is ``/srv/salt/_modules`` on Linux systems.
Modules placed in ``_modules/`` will be synced to the minions when any of the following
Salt functions are called:
* :mod:`state.apply <salt.modules.state.apply_>`
* :mod:`saltutil.sync_modules <salt.modules.saltutil.sync_modules>`
* :mod:`saltutil.sync_all <salt.modules.saltutil.sync_all>`
Note that a module's default name is its filename
(i.e. ``foo.py`` becomes module ``foo``), but that its name can be overridden
by using a :ref:`__virtual__ function <virtual-modules>`.
If a Salt module has errors and cannot be imported, the Salt minion will continue
to load without issue and the module with errors will simply be omitted.
If adding a Cython module the file must be named ``<modulename>.pyx`` so that
the loader knows that the module needs to be imported as a Cython module. The
compilation of the Cython module is automatic and happens when the minion
starts, so only the ``*.pyx`` file is required.
.. _`Cython`: http://cython.org/
Zip Archives as Modules
=======================
Python 2.3 and higher allows developers to directly import zip archives containing Python code.
By setting :conf_minion:`enable_zip_modules` to ``True`` in the minion config, the Salt loader
will be able to import ``.zip`` files in this fashion. This allows Salt module developers to
package dependencies with their modules for ease of deployment, isolation, etc.
For a user, Zip Archive modules behave just like other modules. When executing a function from a
module provided as the file ``my_module.zip``, a user would call a function within that module
as ``my_module.<function>``.
Creating a Zip Archive Module
-----------------------------
A Zip Archive module is structured similarly to a simple `Python package`_. The ``.zip`` file contains
a single directory with the same name as the module. The module code traditionally in ``<module_name>.py``
goes in ``<module_name>/__init__.py``. The dependency packages are subdirectories of ``<module_name>/``.
Here is an example directory structure for the ``lumberjack`` module, which has two library dependencies
(``sleep`` and ``work``) to be included.
.. code-block:: bash
modules $ ls -R lumberjack
__init__.py sleep work
lumberjack/sleep:
__init__.py
lumberjack/work:
__init__.py
The contents of ``lumberjack/__init__.py`` show how to import and use these included libraries.
.. code-block:: python
# Libraries included in lumberjack.zip
from lumberjack import sleep, work
def is_ok(person):
''' Checks whether a person is really a lumberjack '''
return sleep.all_night(person) and work.all_day(person)
Then, create the zip:
.. code-block:: bash
modules $ zip -r lumberjack lumberjack
adding: lumberjack/ (stored 0%)
adding: lumberjack/__init__.py (deflated 39%)
adding: lumberjack/sleep/ (stored 0%)
adding: lumberjack/sleep/__init__.py (deflated 7%)
adding: lumberjack/work/ (stored 0%)
adding: lumberjack/work/__init__.py (deflated 7%)
modules $ unzip -l lumberjack.zip
Archive: lumberjack.zip
Length Date Time Name
-------- ---- ---- ----
0 08-21-15 20:08 lumberjack/
348 08-21-15 20:08 lumberjack/__init__.py
0 08-21-15 19:53 lumberjack/sleep/
83 08-21-15 19:53 lumberjack/sleep/__init__.py
0 08-21-15 19:53 lumberjack/work/
81 08-21-15 19:21 lumberjack/work/__init__.py
-------- -------
512 6 files
Once placed in :conf_master:`file_roots`, Salt users can distribute and use ``lumberjack.zip`` like any other module.
.. code-block:: bash
$ sudo salt minion1 saltutil.sync_modules
minion1:
- modules.lumberjack
$ sudo salt minion1 lumberjack.is_ok 'Michael Palin'
minion1:
True
.. _`Python package`: https://docs.python.org/2/tutorial/modules.html#packages
.. _cross-calling-execution-modules:
Cross Calling Execution Modules
===============================
All of the Salt execution modules are available to each other and modules can call
functions available in other execution modules.
The variable ``__salt__`` is packed into the modules after they are loaded into
the Salt minion.
The ``__salt__`` variable is a :ref:`Python dictionary <python2:typesmapping>`
containing all of the Salt functions. Dictionary keys are strings representing the
names of the modules and the values are the functions themselves.
Salt modules can be cross-called by accessing the value in the ``__salt__`` dict:
.. code-block:: python
def foo(bar):
return __salt__['cmd.run'](bar)
This code will call the `run` function in the :mod:`cmd <salt.modules.cmdmod>`
module and pass the argument ``bar`` to it.
Preloaded Execution Module Data
===============================
When interacting with execution modules often it is nice to be able to read information
dynamically about the minion or to load in configuration parameters for a module.
Salt allows for different types of data to be loaded into the modules by the
minion.
Grains Data
-----------
The values detected by the Salt Grains on the minion are available in a
:ref:`dict <python2:typesmapping>` named ``__grains__`` and can be accessed
from within callable objects in the Python modules.
To see the contents of the grains dictionary for a given system in your deployment
run the :func:`grains.items` function:
.. code-block:: bash
salt 'hostname' grains.items --output=pprint
Any value in a grains dictionary can be accessed as any other Python dictionary. For
example, the grain representing the minion ID is stored in the ``id`` key and from
an execution module, the value would be stored in ``__grains__['id']``.
Module Configuration
--------------------
Since parameters for configuring a module may be desired, Salt allows for
configuration information from the minion configuration file to be passed to
execution modules.
Since the minion configuration file is a YAML document, arbitrary configuration
data can be passed in the minion config that is read by the modules. It is therefore
**strongly** recommended that the values passed in the configuration file match
the module name. A value intended for the ``test`` execution module should be named
``test.<value>``.
The test execution module contains usage of the module configuration and the default
configuration file for the minion contains the information and format used to
pass data to the modules. :mod:`salt.modules.test`, :file:`conf/minion`.
Printout Configuration
======================
Since execution module functions can return different data, and the way the data is
printed can greatly change the presentation, Salt has a printout configuration.
When writing a module the ``__outputter__`` dictionary can be declared in the module.
The ``__outputter__`` dictionary contains a mapping of function name to Salt
Outputter.
.. code-block:: python
__outputter__ = {
'run': 'txt'
}
This will ensure that the text outputter is used.
.. _virtual-modules:
Virtual Modules
===============
Virtual modules let you override the name of a module in order to use the same
name to refer to one of several similar modules. The specific module that is
loaded for a virtual name is selected based on the current platform or
environment.
For example, packages are managed across platforms using the ``pkg`` module.
``pkg`` is a virtual module name that is
an alias for the specific package manager module that is loaded on a specific
system (for example, :mod:`yumpkg <salt.modules.yumpkg>` on RHEL/CentOS systems
, and :mod:`aptpkg <salt.modules.aptpkg>` on Ubuntu).
Virtual module names are set using the ``__virtual__`` function and the
:ref:`virtual name <modules-virtual-name>`.
``__virtual__`` Function
========================
The ``__virtual__`` function returns either a :ref:`string <python2:typesseq>`,
:py:data:`True`, :py:data:`False`, or :py:data:`False` with an :ref:`error
string <modules-error-info>`. If a string is returned then the module is loaded
using the name of the string as the virtual name. If ``True`` is returned the
module is loaded using the current module name. If ``False`` is returned the
module is not loaded. ``False`` lets the module perform system checks and
prevent loading if dependencies are not met.
Since ``__virtual__`` is called before the module is loaded, ``__salt__`` will be
unavailable as it will not have been packed into the module at this point in time.
.. note::
Modules which return a string from ``__virtual__`` that is already used by
a module that ships with Salt will _override_ the stock module.
.. _modules-error-info:
Returning Error Information from ``__virtual__``
------------------------------------------------
Optionally, Salt plugin modules, such as execution, state, returner, beacon,
etc. modules may additionally return a string containing the reason that a
module could not be loaded. For example, an execution module called ``cheese``
and a corresponding state module also called ``cheese``, both depending on a
utility called ``enzymes`` should have ``__virtual__`` functions that handle
the case when the dependency is unavailable.
.. code-block:: python
'''
Cheese execution (or returner/beacon/etc.) module
'''
try:
import enzymes
HAS_ENZYMES = True
except ImportError:
HAS_ENZYMES = False
def __virtual__():
'''
only load cheese if enzymes are available
'''
if HAS_ENZYMES:
return 'cheese'
else:
return False, 'The cheese execution module cannot be loaded: enzymes unavailable.'
.. code-block:: python
'''
Cheese state module
'''
def __virtual__():
'''
only load cheese if enzymes are available
'''
# predicate loading of the cheese state on the corresponding execution module
if 'cheese.slice' in __salt__:
return 'cheese'
else:
return False, 'The cheese state module cannot be loaded: enzymes unavailable.'
Examples
--------
The package manager modules are among the best examples of using the
``__virtual__`` function. A table of all the virtual ``pkg`` modules can be
found :ref:`here <virtual-pkg>`.
.. _module-provider-override:
Overriding Virtual Module Providers
-----------------------------------
Salt often uses OS grains (``os``, ``osrelease``, ``os_family``, etc.) to
determine which module should be loaded as the virtual module for ``pkg``,
``service``, etc. Sometimes this OS detection is incomplete, with new distros
popping up, existing distros changing init systems, etc. The virtual modules
likely to be affected by this are in the list below (click each item for more
information):
- :ref:`pkg <virtual-pkg>`
- :ref:`service <virtual-service>`
- :ref:`user <virtual-user>`
- :ref:`shadow <virtual-shadow>`
- :ref:`group <virtual-group>`
If Salt is using the wrong module for one of these, first of all, please
`report it on the issue tracker`__, so that this issue can be resolved for a
future release. To make it easier to troubleshoot, please also provide the
:py:mod:`grains.items <salt.modules.grains.items>` output, taking care to
redact any sensitive information.
Then, while waiting for the SaltStack development team to fix the issue, Salt
can be made to use the correct module using the :conf_minion:`providers` option
in the minion config file:
.. code-block:: yaml
providers:
service: systemd
pkg: aptpkg
The above example will force the minion to use the :py:mod:`systemd
<salt.modules.systemd>` module to provide service mangement, and the
:py:mod:`aptpkg <salt.modules.aptpkg>` module to provide package management.
.. __: https://github.com/saltstack/salt/issues/new
.. _modules-virtual-name:
``__virtualname__``
===================
``__virtualname__`` is a variable that is used by the documentation build
system to know the virtual name of a module without calling the ``__virtual__``
function. Modules that return a string from the ``__virtual__`` function
must also set the ``__virtualname__`` variable.
To avoid setting the virtual name string twice, you can implement
``__virtual__`` to return the value set for ``__virtualname__`` using a pattern
similar to the following:
.. code-block:: python
# Define the module's virtual name
__virtualname__ = 'pkg'
def __virtual__():
'''
Confine this module to Mac OS with Homebrew.
'''
if salt.utils.which('brew') and __grains__['os'] == 'MacOS':
return __virtualname__
return False
Documentation
=============
Salt execution modules are documented. The :func:`sys.doc` function will return the
documentation for all available modules:
.. code-block:: bash
salt '*' sys.doc
The ``sys.doc`` function simply prints out the docstrings found in the modules; when
writing Salt execution modules, please follow the formatting conventions for docstrings as
they appear in the other modules.
Adding Documentation to Salt Modules
------------------------------------
It is strongly suggested that all Salt modules have documentation added.
To add documentation add a `Python docstring`_ to the function.
.. code-block:: python
def spam(eggs):
'''
A function to make some spam with eggs!
CLI Example::
salt '*' test.spam eggs
'''
return eggs
Now when the sys.doc call is executed the docstring will be cleanly returned
to the calling terminal.
.. _`Python docstring`: http://docs.python.org/2/glossary.html#term-docstring
Documentation added to execution modules in docstrings will automatically be added
to the online web-based documentation.
Add Execution Module Metadata
-----------------------------
When writing a Python docstring for an execution module, add information about the module
using the following field lists:
.. code-block:: text
:maintainer: Thomas Hatch <thatch@saltstack.com, Seth House <shouse@saltstack.com>
:maturity: new
:depends: python-mysqldb
:platform: all
The maintainer field is a comma-delimited list of developers who help maintain
this module.
The maturity field indicates the level of quality and testing for this module.
Standard labels will be determined.
The depends field is a comma-delimited list of modules that this module depends
on.
The platform field is a comma-delimited list of platforms that this module is
known to run on.
Log Output
==========
You can call the logger from custom modules to write messages to the minion
logs. The following code snippet demonstrates writing log messages:
.. code-block:: python
import logging
log = logging.getLogger(__name__)
log.info('Here is Some Information')
log.warning('You Should Not Do That')
log.error('It Is Busted')
Private Functions
=================
In Salt, Python callable objects contained within an execution module are made available
to the Salt minion for use. The only exception to this rule is a callable
object with a name starting with an underscore ``_``.
Objects Loaded Into the Salt Minion
-----------------------------------
.. code-block:: python
def foo(bar):
return bar
class baz:
def __init__(self, quo):
pass
Objects NOT Loaded into the Salt Minion
---------------------------------------
.. code-block:: python
def _foobar(baz): # Preceded with an _
return baz
cheese = {} # Not a callable Python object
.. note::
Some callable names also end with an underscore ``_``, to avoid keyword clashes
with Python keywords. When using execution modules, or state modules, with these
in them the trailing underscore should be omitted.
Useful Decorators for Modules
=============================
Depends Decorator
-----------------
When writing execution modules there are many times where some of the module will
work on all hosts but some functions have an external dependency, such as a service
that needs to be installed or a binary that needs to be present on the system.
Instead of trying to wrap much of the code in large try/except blocks, a decorator can
be used.
If the dependencies passed to the decorator don't exist, then the salt minion will remove
those functions from the module on that host.
If a "fallback_function" is defined, it will replace the function instead of removing it
.. code-block:: python
import logging
from salt.utils.decorators import depends
log = logging.getLogger(__name__)
try:
import dependency_that_sometimes_exists
except ImportError as e:
log.trace('Failed to import dependency_that_sometimes_exists: {0}'.format(e))
@depends('dependency_that_sometimes_exists')
def foo():
'''
Function with a dependency on the "dependency_that_sometimes_exists" module,
if the "dependency_that_sometimes_exists" is missing this function will not exist
'''
return True
def _fallback():
'''
Fallback function for the depends decorator to replace a function with
'''
return '"dependency_that_sometimes_exists" needs to be installed for this function to exist'
@depends('dependency_that_sometimes_exists', fallback_function=_fallback)
def foo():
'''
Function with a dependency on the "dependency_that_sometimes_exists" module.
If the "dependency_that_sometimes_exists" is missing this function will be
replaced with "_fallback"
'''
return True
In addition to global dependencies the depends decorator also supports raw booleans.
.. code-block:: python
from salt.utils.decorators import depends
HAS_DEP = False
try:
import dependency_that_sometimes_exists
HAS_DEP = True
except ImportError:
pass
@depends(HAS_DEP)
def foo():
return True