Merge pull request #63316 from barneysowood/state-events-option

Add state_events option for state module functions
This commit is contained in:
Gareth J. Greenaway 2023-02-03 08:31:07 -08:00 committed by GitHub
commit 3aa8c67ea1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 176 additions and 7 deletions

3
changelog/63316.added Normal file
View file

@ -0,0 +1,3 @@
Adds a state_events option to state.highstate, state.apply, state.sls, state.sls_id.
This allows users to enable state_events on a per use basis rather than having to
enable them globally for all state runs.

View file

@ -795,7 +795,6 @@ In this example, `cmd.run` would be run only if either of the `file.managed`
states generated changes and at least one of the watched state's "result" is
``True``.
.. _requisites-fire-event:
Altering States
---------------
@ -1125,6 +1124,8 @@ salt/states/ file.
``mod_run_check_cmd`` is used to check for the check_cmd options. To override
this one, include a ``mod_run_check_cmd`` in the states file for the state.
.. _requisites-fire-event:
Fire Event Notifications
========================

View file

@ -90,8 +90,15 @@ Job events
.. salt:event:: salt/job/<JID>/prog/<MID>/<RUN NUM>
Fired each time a each function in a state run completes execution. Must be
enabled using the :conf_master:`state_events` option.
Fired each time a each function in a state run completes execution. Can
also be fired on individual state if the :ref:`fire_event <requisites-fire-event>`
option is set on that state.
Can be enabled for all state runs in the Salt master config with the
:conf_master:`state_events` option. To enable for an individual state
run, pass ``state_events=True`` to the :py:mod:`state <salt.modules.state>`
function being used.
:var data: The data returned from the state module function.
:var id: The minion ID.

View file

@ -705,6 +705,12 @@ def apply_(mods=None, **kwargs):
salt '*' state.apply localconfig=/path/to/minion.yml
state_events
The state_events option sends progress events as each function in
a state run completes execution.
.. versionadded:: 3006.0
.. rubric:: APPLYING INDIVIDUAL SLS FILES (A.K.A. :py:func:`STATE.SLS <salt.modules.state.sls>`)
@ -816,6 +822,12 @@ def apply_(mods=None, **kwargs):
module types.
.. versionadded:: 2017.7.8,2018.3.3,2019.2.0
state_events
The state_events option sends progress events as each function in
a state run completes execution.
.. versionadded:: 3006.0
"""
if mods:
return sls(mods, **kwargs)
@ -974,7 +986,7 @@ def run_request(name="default", **kwargs):
return {}
def highstate(test=None, queue=None, **kwargs):
def highstate(test=None, queue=None, state_events=None, **kwargs):
"""
Retrieve the state data from the salt master for this minion and execute it
@ -1072,6 +1084,12 @@ def highstate(test=None, queue=None, **kwargs):
.. versionadded:: 2015.8.4
state_events
The state_events option sends progress events as each function in
a state run completes execution.
.. versionadded:: 3006.0
CLI Examples:
.. code-block:: bash
@ -1128,6 +1146,9 @@ def highstate(test=None, queue=None, **kwargs):
"is specified."
)
if state_events is not None:
opts["state_events"] = state_events
try:
st_ = salt.state.HighState(
opts,
@ -1186,7 +1207,15 @@ def highstate(test=None, queue=None, **kwargs):
return ret
def sls(mods, test=None, exclude=None, queue=None, sync_mods=None, **kwargs):
def sls(
mods,
test=None,
exclude=None,
queue=None,
sync_mods=None,
state_events=None,
**kwargs
):
"""
Execute the states in one or more SLS files
@ -1296,6 +1325,12 @@ def sls(mods, test=None, exclude=None, queue=None, sync_mods=None, **kwargs):
.. versionadded:: 2017.7.8,2018.3.3,2019.2.0
state_events
The state_events option sends progress events as each function in
a state run completes execution.
.. versionadded:: 3006.0
CLI Example:
.. code-block:: bash
@ -1382,6 +1417,9 @@ def sls(mods, test=None, exclude=None, queue=None, sync_mods=None, **kwargs):
except KeyError:
log.warning("Invalid custom module type '%s', ignoring", module_type)
if state_events is not None:
opts["state_events"] = state_events
try:
st_ = salt.state.HighState(
opts,
@ -1765,7 +1803,7 @@ def show_states(queue=None, **kwargs):
return list(states.keys())
def sls_id(id_, mods, test=None, queue=None, **kwargs):
def sls_id(id_, mods, test=None, queue=None, state_events=None, **kwargs):
"""
Call a single ID from the named module(s) and handle all requisites
@ -1835,6 +1873,9 @@ def sls_id(id_, mods, test=None, queue=None, **kwargs):
"is specified."
)
if state_events is not None:
opts["state_events"] = state_events
try:
st_ = salt.state.HighState(
opts,

View file

@ -3742,7 +3742,9 @@ class BaseHighState:
)
opts["env_order"] = mopts.get("env_order", opts.get("env_order", []))
opts["default_top"] = mopts.get("default_top", opts.get("default_top"))
opts["state_events"] = mopts.get("state_events")
opts["state_events"] = (
opts.get("state_events") or mopts.get("state_events") or False
)
opts["state_aggregate"] = (
opts.get("state_aggregate") or mopts.get("state_aggregate") or False
)

View file

@ -0,0 +1,115 @@
"""
tests.pytests.integration.modules.state.test_state_state_events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
import logging
import time
import pytest
log = logging.getLogger(__name__)
@pytest.fixture(scope="module")
def configure_state_tree(salt_master, salt_minion):
top_file = """
base:
'{}':
- state-event
""".format(
salt_minion.id
)
state_event_sls = """
show_notification:
test.show_notification:
- text: Notification
"""
with salt_master.state_tree.base.temp_file(
"top.sls", top_file
), salt_master.state_tree.base.temp_file("state-event.sls", state_event_sls):
yield
@pytest.fixture(scope="module")
def state_event_tag():
"""
State event tag to match
"""
return "salt/job/*/prog/{}/0"
def test_highstate_state_events(
event_listener,
salt_master,
salt_minion,
salt_call_cli,
configure_state_tree,
state_event_tag,
):
"""
Test state.highstate with state_events=True
"""
start_time = time.time()
ret = salt_call_cli.run("state.highstate", state_events=True)
assert ret.returncode == 0
assert ret.data
event_pattern = (salt_master.id, state_event_tag.format(salt_minion.id))
matched_events = event_listener.wait_for_events(
[event_pattern], after_time=start_time, timeout=30
)
assert matched_events.found_all_events
def test_sls_state_events(
event_listener,
salt_master,
salt_minion,
salt_call_cli,
configure_state_tree,
state_event_tag,
):
"""
Test state.sls with state_events=True
"""
start_time = time.time()
ret = salt_call_cli.run("state.sls", "state-event", state_events=True)
assert ret.returncode == 0
assert ret.data
event_pattern = (salt_master.id, state_event_tag.format(salt_minion.id))
matched_events = event_listener.wait_for_events(
[event_pattern], after_time=start_time, timeout=30
)
assert matched_events.found_all_events
def test_sls_id_state_events(
event_listener,
salt_master,
salt_minion,
salt_call_cli,
configure_state_tree,
state_event_tag,
):
"""
Test state.sls_id with state_events=True
"""
start_time = time.time()
ret = salt_call_cli.run(
"state.sls_id", "show_notification", "state-event", state_events=True
)
assert ret.returncode == 0
assert ret.data
event_pattern = (salt_master.id, state_event_tag.format(salt_minion.id))
matched_events = event_listener.wait_for_events(
[event_pattern], after_time=start_time, timeout=30
)
assert matched_events.found_all_events