4.6 KiB
Utility Modules - Code Reuse in Custom Modules
2015.5.0
2016.11.0 These can now be synced to the Master for use in custom Runners, and in custom execution modules called within Pillar SLS files.
When extending Salt by writing custom (state modules
<writing-state-modules>
), execution modules
<writing-execution-modules>
, etc., sometimes there is a
need for a function to be available to more than just one kind of custom
module. For these cases, Salt supports what are called "utility
modules". These modules are like normal execution modules, but instead
of being invoked in Salt code using __salt__
, the
__utils__
prefix is used instead.
For example, assuming the following simple utility module, saved to
salt://_utils/foo.py
# -*- coding: utf-8 -*-
'''
My utils module
---------------
This module contains common functions for use in my other custom types.
'''
def bar():
return 'baz'
Once synced to a minion, this function would be available to other custom Salt types like so:
# -*- coding: utf-8 -*-
'''
My awesome execution module
---------------------------
'''
def observe_the_awesomeness():
'''
Prints information from my utility module
CLI Example:
.. code-block:: bash
salt '*' mymodule.observe_the_awesomeness
'''
return __utils__['foo.bar']()
Utility modules, like any other kind of Salt extension, support using
a __virtual__ function <modules-virtual-name>
to
conditionally load them, or load them under a different namespace. For
instance, if the utility module above were named
salt://_utils/mymodule.py
it could be made to be loaded as
the foo
utility module with a __virtual__
function.
# -*- coding: utf-8 -*-
'''
My utils module
---------------
This module contains common functions for use in my other custom types.
'''
def __virtual__():
'''
Load as a different name
'''
return 'foo'
def bar():
return 'baz'
2018.3.0 Instantiating objects from classes declared in util modules works with Master side modules, such as Runners, Outputters, etc.
Also you could even write your utility modules in object oriented fashion:
# -*- coding: utf-8 -*-
'''
My OOP-style utils module
-------------------------
This module contains common functions for use in my other custom types.
'''
class Foo(object):
def __init__(self):
pass
def bar(self):
return 'baz'
And import them into other custom modules:
# -*- coding: utf-8 -*-
'''
My awesome execution module
---------------------------
'''
import mymodule
def observe_the_awesomeness():
'''
Prints information from my utility module
CLI Example:
.. code-block:: bash
salt '*' mymodule.observe_the_awesomeness
'''
= mymodule.Foo()
foo return foo.bar()
These are, of course, contrived examples, but they should serve to
show some of the possibilities opened up by writing utility modules.
Keep in mind though that states still have access to all of the
execution modules, so it is not necessary to write a utility module to
make a function available to both a state and an execution module. One
good use case for utility modules is one where it is necessary to invoke
the same function from a custom outputter
<all-salt.output>
/returner, as well as an execution
module.
Utility modules placed in salt://_utils/
will be synced
to the minions when a highstate <running-highstate>
is run, as well as
when any of the following Salt functions are called:
saltutil.sync_utils <salt.modules.saltutil.sync_utils>
saltutil.sync_all <salt.modules.saltutil.sync_all>
As of the 2019.2.0 release, as well as 2017.7.7 and 2018.3.2 in their
respective release cycles, the sync
argument to state.apply
<salt.modules.state.apply_>
/state.sls <salt.modules.state.sls>
can be
used to sync custom types when running individual SLS files.
To sync to the Master, use either of the following:
saltutil.sync_utils <salt.runners.saltutil.sync_utils>
saltutil.sync_all <salt.runners.saltutil.sync_all>