Do you think IIT Guwahati certified course can help you in your career?
No
Introduction
Salt is a configuration management and distributed remote execution system. It was created with the goal to improve, simplify, and further customize the best remote execution solutions. It can maintain the remote nodes in defined states and query and execute commands on various nodes.
In this blog, we will discuss and learn the concept of Execution modules in salt.
What are Execution Modules?
Salt Execution Modules are basically functions that are called by the salt command. From version 2016.11.0 onwards, the execution modules can now also be called using the salt-run command using the salt runner. They are Cython or Python modules placed in a folder known as _modules/ at the root of the Salt fileserver.
When using the default fileserver backend, the _modules/ directory would be located in /srv/salt/_modules on most of the systems.
In the next section, we will learn about different types of Execution Modules.
Execution Modules
Let’s see different execution modules.
ZIP Archives as Execution Module
To use zip files as an execution module, set the enable_zip_modules to True in the minion config, in this way, the Salt loader will be able to import .zip files.
Cross-Calling Execution Modules
Cross-calling means all the execution modules can call functions available in another execution module as well as available to other modules.
After loading to the Salt minions, the variable __salt__ is packed into these modules.
Salt modules can be cross-called by accessing the value in the __salt__ dict:-
Let’s see how to read the minion’s data dynamically or load configuration parameters for a module.
Preloaded Execution Module Data
While working with execution modules, it is often useful to be able to read the minion’s data dynamically or to load configuration parameters for a module.
Grains Data
Salt allows different types of data to be loaded into the modules by the minion.
The values detected by the Salt Grains on the minion are available in __grains__, which is a python dictionary.
You can run the grains.items() function to see the contents of the grains dictionary for a given system.
salt 'hostname' grains.items --output=pprint
You can also try this code with Online Python Compiler
Salt allows the configuration data to pass execution modules from the minion configuration file.
The test execution module contains the usage of the module configuration.
The default configuration file has the format and information used to pass data to the modules.
__INIT__ Function
To set your execution module mode on the basis of the minion configuration, we can use the __init__(opts) function.
"""
Cheese module initialization example
"""
def __init__(opts):
"""
It allows foreign imports if configured to do so
"""
if opts.get("cheese.allow_foreign", False):
_enable_foreign_products()
You can also try this code with Online Python Compiler
Let’s see how to represent the data returned by Execution module functions.
Outputter Configuration
As we know that the execution module functions can return data in any format. It is very important to represent the output data in a nice format. To do this, salt has a specific outputter that can be set on a function-by-function basis.
You have to declare the __outputter__ dictionary in the global scope of the module.
The __outputter__ dictionary consists of a mapping of function names to Salt outputters.
__outputter__ = {"ninjas": "txt"}
You can also try this code with Online Python Compiler
This will make sure that the txt outputter is used to display output from the ninjas function.
Let’s now learn about Virtual Modules.
Virtual Modules
The virtual modules are used to override the name of a module to use a similar name to refer to one of several same-type modules. On the basis of the current environment/platform, the virtual name is selected for a specific module.
Virtual module names are set with the help of __virtual__ function and the virtual name.
__VIRTUAL__ function
The __virtual__ function returns either a True, False, String, or False with an error string.
If it returns a string, then the module will be loaded using the name of the string as the virtual name.
If it returns True, the module is loaded using the current module name.
If it returns False, the module is not loaded.
__VIRTUALNAME__
The build system uses the __virtualname__variable to determine the virtual name of a module without running the __virtual__ function.
If a module is returning a string fromthe __virtual__ function, then the __virtualname__ variable is also set.
If you want to avoid setting the virtual name string twice, you can use a pattern similar to the following to implement __virtual__ to return the value set for __virtualname__ : -
# Define the module's virtual name
__virtualname__ = "pkg"
def __virtual__():
"""
It will confine this module to Mac OS with Homebrew.
"""
if salt.utils.path.which("brew") and __grains__["os"] == "MacOS":
return __virtualname__
return False
You can also try this code with Online Python Compiler
While writing a Python docstring for an execution module, do add the information about the module using the following field lists:-
Let’s see what these fields are:-
Maintainer field is a list of developers who help maintaining these execution modules.
Maturity field denotes the level of quality and testing for these execution modules.
Depends field is a list of modules that these execution modules depends on.
Platform field is a list of platforms that these execution modules are known to run on.
Let’s learn about some useful decorators for execution modules.
Decorators for Execution Modules
The decorator that we are going to learn about is Depends Decorator.
Depends Decorator
Many times when building execution modules, parts of the modules work on all hosts, but some methods have an external dependency, such as a service that must be installed or a binary that must be present on the system.
Wrapping the code in a try/except block can make the code bulkier, instead, you can use Decorators.
If the decorator's dependencies do not exist, the salt-minion will withdraw those functions from the execution module on that host. If a fallback function is specified, it will replace the function rather than remove it. Let’s see an example:-
import logging
from salt.utils.decorators import depends
log = logging.getLogger(__name__)
try:
import ninjas
except ImportError as e:
log.trace("Failed to import ninjas: {0}".format(e))
@depends("ninjas")
def foo():
"""
Function with a dependency on the "ninjas" module,
if the "ninjas" is missing this function will not exist
"""
return True
def _fallback():
"""
It is fallback function for the depends decorator to replace a function with
"""
return '"ninjas" needs to be installed for this function to exist'
@depends("ninjas", fallback_function=_fallback)
def code():
"""
Function with a dependency on the "ninjas" module.
If the "ninjas" is missing this function will be
replaced with "_fallback"
"""
return True
You can also try this code with Online Python Compiler
Executors are used by salt minions to execute the module functions. Executors are used to modify the functions behavior, execute in a specific way like sudo executor, or do any pre-execution steps.
Functionalities of an executor:-
It can be passed as a list, and they will be used one by one in order.
If an executor returns None, the next executor will be called.
If an executor returns non-None, the execution sequencing will get terminated, and the result will be returned.
The executors' list can be passed by the minion config file in the following way:-
A salt executor is written in the same way as a salt execution module. The executors are python modules placed into the executor's folder and containing the execute function with the following signature:-
def execute(opts, data, func, args, kwargs):
...
You can also try this code with Online Python Compiler
opts: It is the dictionary containing the minion configuration options.
data: It is the dictionary containing the load data, including executor_opts passed via cmdline/API.
func, args, kwargs: Execution module function to be executed and its arguments.
Frequently Asked Questions
What is Salt?
Salt is a configuration management and distributed remote execution system. It was created with the goal to improve, simplify, and further customize the best remote execution solutions.
What are Pillars in salt?
Pillars are salt’s interface that are designed to provide global values to salt minions. Pillar is helpful for storing sensitive data to a particular minion.
What is a Grain in Salt?
Grain is a salt interface that derives information about the underlying system. Grains are collected for the IP address, domain name, OS, kernel, OS type, and various other system properties.
What are Execution Modules in Salt?
Salt Execution Modules are basically functions that are called by the salt command. They are Cython or Python modules placed in a folder known as _modules/ at the root of the Salt fileserver.
What are Executors in salt?
Executors are used by salt minions to execute the module functions. Executors are used to modify the functions behavior, execute in a specific way like sudo executor, or to do any pre-execution steps.
Conclusion
In this article, we have extensively discussed the concept of Execution Modules in Salt. I hope you enjoyed this blog on Execution Modules in Salt.