Merge pull request #48037 from terminalmage/fix-custom-types-sync-docs

Add "sync_mods" argument to state.apply/state.sls
This commit is contained in:
Nicole Thomas 2018-06-21 15:57:02 -04:00 committed by GitHub
commit 731ec0a11a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 167 additions and 49 deletions

View file

@ -148,22 +148,23 @@ Why aren't my custom modules/states/etc. available on my Minions?
-----------------------------------------------------------------
Custom modules are synced to Minions when
:mod:`saltutil.sync_modules <salt.modules.saltutil.sync_modules>`,
or :mod:`saltutil.sync_all <salt.modules.saltutil.sync_all>` is run.
Custom modules are also synced by :mod:`state.apply` when run without
any arguments.
:py:func:`saltutil.sync_modules <salt.modules.saltutil.sync_modules>`,
or :py:func:`saltutil.sync_all <salt.modules.saltutil.sync_all>` is run.
Similarly, custom states are synced to Minions when :py:func:`saltutil.sync_states
<salt.modules.saltutil.sync_states>`, or :py:func:`saltutil.sync_all
<salt.modules.saltutil.sync_all>` is run.
Similarly, custom states are synced to Minions
when :mod:`state.apply <salt.modules.state.apply_>`,
:mod:`saltutil.sync_states <salt.modules.saltutil.sync_states>`, or
:mod:`saltutil.sync_all <salt.modules.saltutil.sync_all>` is run.
They are both also synced when a :ref:`highstate <running-highstate>` is
triggered.
Custom states are also synced by :mod:`state.apply<salt.modules.state.apply_>`
when run without any arguments.
As of the Fluorine release, as well as 2017.7.7 and 2018.3.2 in their
respective release cycles, the ``sync`` argument to :py:func:`state.apply
<salt.modules.state.apply_>`/:py:func:`state.sls <salt.modules.state.sls>` can
be used to sync custom types when running individual SLS files.
Other custom types (renderers, outputters, etc.) have similar behavior, see the
documentation for the :mod:`saltutil <salt.modules.saltutil>` module for more
documentation for the :py:func:`saltutil <salt.modules.saltutil>` module for more
information.
:ref:`This reactor example <minion-start-reactor>` can be used to automatically

View file

@ -135,13 +135,18 @@ where it is necessary to invoke the same function from a custom :ref:`outputter
<all-salt.output>`/returner, as well as an execution module.
Utility modules placed in ``salt://_utils/`` will be synced to the minions when
any of the following Salt functions are called:
a :ref:`highstate <running-highstate>` is run, as well as when any of the
following Salt functions are called:
* :mod:`state.apply <salt.modules.state.apply_>`
* :mod:`saltutil.sync_utils <salt.modules.saltutil.sync_utils>`
* :mod:`saltutil.sync_all <salt.modules.saltutil.sync_all>`
* :py:func:`saltutil.sync_utils <salt.modules.saltutil.sync_utils>`
* :py:func:`saltutil.sync_all <salt.modules.saltutil.sync_all>`
As of the Fluorine release, as well as 2017.7.7 and 2018.3.2 in their
respective release cycles, the ``sync`` argument to :py:func:`state.apply
<salt.modules.state.apply_>`/:py:func:`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:
* :mod:`saltutil.sync_utils <salt.runners.saltutil.sync_utils>`
* :mod:`saltutil.sync_all <salt.runners.saltutil.sync_all>`
* :py:func:`saltutil.sync_utils <salt.runners.saltutil.sync_utils>`
* :py:func:`saltutil.sync_all <salt.runners.saltutil.sync_all>`

View file

@ -458,8 +458,7 @@ def template_str(tem, queue=False, **kwargs):
return ret
def apply_(mods=None,
**kwargs):
def apply_(mods=None, **kwargs):
'''
.. versionadded:: 2015.5.0
@ -599,6 +598,22 @@ def apply_(mods=None,
.. code-block:: bash
salt '*' state.apply test localconfig=/path/to/minion.yml
sync_mods
If specified, the desired custom module types will be synced prior to
running the SLS files:
.. code-block:: bash
salt '*' state.apply test sync_mods=states,modules
salt '*' state.apply test sync_mods=all
.. note::
This option is ignored when no SLS files are specified, as a
:ref:`highstate <running-highstate>` automatically syncs all custom
module types.
.. versionadded:: 2017.7.8,2018.3.3,Fluorine
'''
if mods:
return sls(mods, **kwargs)
@ -928,7 +943,7 @@ def highstate(test=None, queue=False, **kwargs):
return ret
def sls(mods, test=None, exclude=None, queue=False, **kwargs):
def sls(mods, test=None, exclude=None, queue=False, sync_mods=None, **kwargs):
'''
Execute the states in one or more SLS files
@ -1019,6 +1034,17 @@ def sls(mods, test=None, exclude=None, queue=False, **kwargs):
.. versionadded:: 2015.8.4
sync_mods
If specified, the desired custom module types will be synced prior to
running the SLS files:
.. code-block:: bash
salt '*' state.sls test sync_mods=states,modules
salt '*' state.sls test sync_mods=all
.. versionadded:: 2017.7.8,2018.3.3,Fluorine
CLI Example:
.. code-block:: bash
@ -1087,6 +1113,28 @@ def sls(mods, test=None, exclude=None, queue=False, **kwargs):
'{0}.cache.p'.format(kwargs.get('cache_name', 'highstate'))
)
if sync_mods is True:
sync_mods = ['all']
if sync_mods is not None:
sync_mods = salt.utils.split_input(sync_mods)
else:
sync_mods = []
if 'all' in sync_mods and sync_mods != ['all']:
# Prevent unnecessary extra syncing
sync_mods = ['all']
for module_type in sync_mods:
try:
__salt__['saltutil.sync_{0}'.format(module_type)](
saltenv=opts['environment']
)
except KeyError:
log.warning(
'Invalid custom module type \'%s\', ignoring',
module_type
)
try:
st_ = salt.state.HighState(opts,
pillar_override,

View file

@ -11,6 +11,7 @@ import os
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.unit import TestCase, skipIf
from tests.support.mock import (
Mock,
MagicMock,
patch,
mock_open,
@ -357,6 +358,9 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
'environment': None,
'__cli': 'salt',
},
'__salt__': {
'config.option': MagicMock(return_value=''),
},
},
}
@ -752,28 +756,25 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
"whitelist=sls1.sls",
pillar="A")
mock = MagicMock(return_value=True)
with patch.dict(state.__salt__,
{'config.option': mock}):
mock = MagicMock(return_value="A")
mock = MagicMock(return_value="A")
with patch.object(state, '_filter_running',
mock):
mock = MagicMock(return_value=True)
with patch.object(state, '_filter_running',
mock):
mock = MagicMock(return_value=True)
with patch.object(state, '_filter_running',
with patch.object(salt.payload, 'Serial',
mock):
mock = MagicMock(return_value=True)
with patch.object(salt.payload, 'Serial',
mock):
with patch.object(os.path,
'join', mock):
with patch.object(
state,
'_set'
'_retcode',
mock):
self.assertTrue(state.
highstate
(arg))
with patch.object(os.path,
'join', mock):
with patch.object(
state,
'_set'
'_retcode',
mock):
self.assertTrue(state.
highstate
(arg))
def test_clear_request(self):
'''
@ -914,17 +915,11 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
MockState.HighState.flag = False
mock = MagicMock(return_value=True)
with patch.dict(state.__salt__,
{'config.option':
mock}):
mock = MagicMock(return_value=
True)
with patch.object(
state,
'_filter_'
'running',
mock):
self.sub_test_sls()
with patch.object(state,
'_filter_'
'running',
mock):
self.sub_test_sls()
def sub_test_sls(self):
'''
@ -947,6 +942,75 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
None,
True))
def test_sls_sync(self):
'''
Test test.sls with the sync argument
We're only mocking the sync functions we expect to sync. If any other
sync functions are run then they will raise a KeyError, which we want
as it will tell us that we are syncing things we shouldn't.
'''
mock_empty_list = MagicMock(return_value=[])
with patch.object(state, 'running', mock_empty_list), \
patch.object(state, '_disabled', mock_empty_list), \
patch.object(state, '_get_pillar_errors', mock_empty_list):
sync_mocks = {
'saltutil.sync_modules': Mock(),
'saltutil.sync_states': Mock(),
}
with patch.dict(state.__salt__, sync_mocks):
state.sls('foo', sync_mods='modules,states')
for key in sync_mocks:
call_count = sync_mocks[key].call_count
expected = 1
assert call_count == expected, \
'{0} called {1} time(s) (expected: {2})'.format(
key, call_count, expected
)
# Test syncing all
sync_mocks = {'saltutil.sync_all': Mock()}
with patch.dict(state.__salt__, sync_mocks):
state.sls('foo', sync_mods='all')
for key in sync_mocks:
call_count = sync_mocks[key].call_count
expected = 1
assert call_count == expected, \
'{0} called {1} time(s) (expected: {2})'.format(
key, call_count, expected
)
# sync_mods=True should be interpreted as sync_mods=all
sync_mocks = {'saltutil.sync_all': Mock()}
with patch.dict(state.__salt__, sync_mocks):
state.sls('foo', sync_mods=True)
for key in sync_mocks:
call_count = sync_mocks[key].call_count
expected = 1
assert call_count == expected, \
'{0} called {1} time(s) (expected: {2})'.format(
key, call_count, expected
)
# Test syncing all when "all" is passed along with module types.
# This tests that we *only* run a sync_all and avoid unnecessary
# extra syncing.
sync_mocks = {'saltutil.sync_all': Mock()}
with patch.dict(state.__salt__, sync_mocks):
state.sls('foo', sync_mods='modules,all')
for key in sync_mocks:
call_count = sync_mocks[key].call_count
expected = 1
assert call_count == expected, \
'{0} called {1} time(s) (expected: {2})'.format(
key, call_count, expected
)
def test_pkg(self):
'''
Test to execute a packaged state run