Create a Salt Execution Module
Updated by Linode Written by Linode
A Salt execution module is a Python module that runs on a Salt minion. It perform tasks and returns data to the Salt master. In this tutorial you will create and install an execution module that will call the US National Weather Service API and return the current temperature at a specified weather station. This example could easily be adapted to access any API.
Before You Begin
If you haven’t already, set up a Salt master and at least one Salt minion. You can follow the first few steps of our Getting Started with Salt - Basic Installation and Setup guide.
NoteThe steps in this guide require root privileges. Be sure to run the steps below with thesudo
prefix. For more information on privileges, see our Users and Groups guide.
Prepare Salt
The files created in the following steps will be located in the /srv/salt
directory. If you have changed Salt’s default file_roots
configuration, use that directory location instead.
Begin by creating the
/srv/salt
directory if it does not already exist. This is where you will place your top file and your Salt state file:mkdir /srv/salt
Create a top file in
/srv/salt
which will be Salt’s point of entry for our Salt configuration:- /srv/salt/top.sls
-
1 2 3
base: '*': - weather
Create a state file named
weather.sls
and instruct Salt to make sure our minions have PIP installed, as well as the required Python library.- /srv/salt/weather.sls
-
1 2 3 4 5 6 7
python-pip: pkg.installed requests: pip.installed: - require: - pkg: python-pip
Apply these state changes:
salt '*' state.apply
Finally, create the
/srv/salt/_modules
directory which will contain our execution module:mkdir /srv/salt/_modules
Create the Execution Module
Create a file called
weather.py
in the/srv/salt/_modules
directory, and add the following lines to set up Salt logging and import the requests module.- /srv/salt/_modules/weather.py
-
1 2 3 4 5 6 7 8 9 10
import logging try: import requests HAS_REQUESTS = True except ImportError: HAS_REQUESTS = False log = logging.getLogger(__name__) . . .
Add the
__virtualname__
variable and the__virtual__
function.- /srv/salt/_modules/weather.py
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14
. . . __virtualname__ = 'weather' def __virtual__(): ''' Only load weather if requests is available ''' if HAS_REQUESTS: return __virtualname__ else: return False, 'The weather module cannot be loaded: requests package unavailable.' . . .
The
__virtual__
function either returns the module’s virtual name and loads the module, or returnsFalse
with an error string and the module is not loaded. Theif HAS_REQUESTS
conditional is tied to the try/except block created in the previous step through the use of theHAS_REQUESTS
variable.Add the public
get()
function and the private_make_request()
function:- /srv/salt/_modules/weather.py
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
. . . def get(signs=None): ''' Gets the Current Weather CLI Example:: salt minion weather.get KPHL This module also accepts multiple values in a comma separated list:: salt minion weather.get KPHL,KACY ''' log.debug(signs) return_value = {} signs = signs.split(',') for sign in signs: return_value[sign] = _make_request(sign) return return_value def _make_request(sign): ''' The function that makes the request for weather data from the National Weather Service. ''' request = requests.get('https://api.weather.gov/stations/{}/observations/current'.format(sign)) conditions = { "description:": request.json()["properties"]["textDescription"], "temperature": round(request.json()["properties"]["temperature"]["value"], 1) } return conditions
There are two functions in this step. The
get()
function accepts one or more weather station call signs as a comma separated list. It calls_make_request()
to make the HTTP request and returns a text description of the current weather and the temperature.It’s important to note that by adding an underscore to the beginning of the
_make_request()
function it becomes a private function, which means it is not directly accessible through the Salt command line or a state file.The complete file looks like this:
- /srv/salt/_modules/weather.py
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
import logging try: import requests HAS_REQUESTS = True except ImportError: HAS_REQUESTS = False log = logging.getLogger(__name__) __virtual_name__ = 'weather' def __virtual__(): ''' Only load weather if requests is available ''' if HAS_REQUESTS: return __virtual_name__ else: return False, 'The weather module cannot be loaded: requests package unavailable.' def get(signs=None): ''' Gets the Current Weather CLI Example:: salt minion weather.get KPHL This module also accepts multiple values in a comma seperated list:: salt minion weather.get KPHL,KACY ''' log.debug(signs) return_value = {} signs = signs.split(',') for sign in signs: return_value[sign] = _make_request(sign) return return_value def _make_request(sign): ''' The function that makes the request for weather data from the National Weather Service. ''' request = requests.get('https://api.weather.gov/stations/{}/observations/current'.format(sign)) conditions = { "description:": request.json()["properties"]["textDescription"], "temperature": round(request.json()["properties"]["temperature"]["value"], 1) } return conditions
Run the Execution Module
To run the execution module, you need to first sync it to your minions. To do this, you can call a highstate with
state.apply
, which will also try to apply the state changes you specified earlier in theweather.sls
state file. Since theweather.sls
state was already applied in the Preparing Salt section, use thesaltutil.sync_modules
function:salt '*' saltutil.sync_modules
Run the execution module on your Salt master:
salt '*' weather.get KPHL
You should see an output like the following:
salt-minion: ---------- KPHL: ---------- description:: Cloudy temperature: 17.2
Alternatively, you can run the Salt execution module locally on your Salt minion by entering the following:
salt-call weather.get KVAY,KACY
You should get an output like the following:
local: ---------- KACY: ---------- description:: Cloudy temperature: 18.9 KVAY: ---------- description:: Cloudy temperature: 16.7
You have now successfully created and installed a Salt execution module.
More Information
You may wish to consult the following resources for additional information on this topic. While these are provided in the hope that they will be useful, please note that we cannot vouch for the accuracy or timeliness of externally hosted materials.
Join our Community
Find answers, ask questions, and help others.
This guide is published under a CC BY-ND 4.0 license.