Sometimes debugging with print()
and extra logs sprinkled everywhere is not
the best strategy.
IPython is a helpful debug tool that has an interactive python environment which can be embedded in python programs.
First the system will require IPython to be installed.
# Debian
apt-get install ipython
# Arch Linux
pacman -Syu ipython2
# RHEL/CentOS (via EPEL)
yum install python-ipython
Now, in the troubling python module, add the following line at a location where the debugger should be started:
test = "test123"
import IPython
IPython.embed_kernel()
After running a Salt command that hits that line, the following will show up in the log file:
[CRITICAL] To connect another client to this kernel, use:
[IPKernelApp] --existing kernel-31271.json
Now on the system that invoked embed_kernel
, run the following command from
a shell:
# NOTE: use ipython2 instead of ipython for Arch Linux
ipython console --existing
This provides a console that has access to all the vars and functions, and even supports tab-completion.
print(test)
test123
To exit IPython and continue running Salt, press Ctrl-d
to logout.
These are things that may be defined by the module to influence various things.
Called before __virtual__()
grains and proxy modules
__proxyenabled__ as a list containing the names of the proxy types that the module supports.
Salt provides several special "dunder" dictionaries as a convenience for Salt
development. These include __opts__
, __context__
, __salt__
, and
others. This document will describe each dictionary and detail where they exist
and what information and/or functionality they provide.
The following dunder dictionaries are always defined, but may be empty
__context__
__grains__
__pillar__
__opts__
Defined in: All modules
The __opts__
dictionary contains all of the options passed in the
configuration file for the master or minion.
Note
In many places in salt, instead of pulling raw data from the __opts__
dict, configuration data should be pulled from the salt get functions
such as config.get, aka - __salt__['config.get']('foo:bar')
The get functions also allow for dict traversal via the : delimiter.
Consider using get functions whenever using __opts__
or __pillar__
and __grains__
(when using grains for configuration data)
The configuration file data made available in the __opts__
dictionary is the
configuration data relative to the running daemon. If the modules are loaded and
executed by the master, then the master configuration data is available, if the
modules are executed by the minion, then the minion configuration is
available. Any additional information passed into the respective configuration
files is made available
Defined in: Auth, Beacons, Engines, Execution, Executors, Outputters, Pillars, Proxies, Renderers, Returners, Runners, SDB, SSH Wrappers, State, Thorium
__salt__
contains the execution module functions. This allows for all
functions to be called as they have been set up by the salt loader.
__salt__["cmd.run"]("fdisk -l")
__salt__["network.ip_addrs"]()
Note
When used in runners or outputters, __salt__
references other
runner/outputter modules, and not execution modules.
Filled in for: Execution, Pillar, Renderer, Returner, SSH Wrapper, State.
The __grains__
dictionary contains the grains data generated by the minion
that is currently being worked with. In execution modules, state modules and
returners this is the grains of the minion running the calls, when generating
the external pillar the __grains__
is the grains data from the minion that
the pillar is being generated for.
While __grains__
is defined for every module, it's only filled in for some.
Filled in for: Execution, Renderer, Returner, SSH Wrapper, State
The __pillar__
dictionary contains the pillar for the respective minion.
While __pillar__
is defined for every module, it's only filled in for some.
Filled in for: Pillar
The __ext_pillar__
dictionary contains the external pillar modules.
During a state run the __context__
dictionary persists across all states
that are run and then is destroyed when the state ends.
When running an execution module __context__
persists across all module
executions until the modules are refreshed; such as when
saltutil.sync_all
or
state.apply
are executed.
A great place to see how to use __context__
is in the cp.py module in
salt/modules/cp.py. The fileclient authenticates with the master when it is
instantiated and then is used to copy files to the minion. Rather than create a
new fileclient for each file that is to be copied down, one instance of the
fileclient is instantiated in the __context__
dictionary and is reused for
each file. Here is an example from salt/modules/cp.py:
if not "cp.fileclient" in __context__:
__context__["cp.fileclient"] = salt.fileclient.get_file_client(__opts__)
Note
Because __context__ may or may not have been destroyed, always be sure to check for the existence of the key in __context__ and generate the key before using it.
Defined in: Cloud, Engine, Execution, File Server, Grain, Pillar, Proxy, Roster, Runner, SDB, State
Defined in: Beacon, Engine, Execution, Executor, Proxy, Renderer, Returner, State, Util
Defined in: Engine, Roster, Thorium
Note
When used in engines, it should be called __runners__ (plural)
Defined in: Executor
Defined in: Proxy
Defined in: Thorium
Defined in: Renderers, State
Defined in: State
Defined in: SDB
Defined for: Runners, Execution Modules, Wheels
__jid__
: The job ID
__user__
: The user
__tag__
: The jid tag
__jid_event__
: A salt.utils.event.NamespacedEvent
.
NamespacedEvent
defines a single
method fire_event
, that takes data and tag. The Runner docs has examples.