Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[master] Port #49955 to master #56815

Merged
merged 9 commits into from
Apr 23, 2020
9 changes: 9 additions & 0 deletions conf/minion
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,15 @@
#
#state_aggregate: False

# Disable requisites during state runs by specifying a single requisite
# or a list of requisites to disable.
#
# disabled_requisites: require_in
#
# disabled_requisites:
# - require
# - require_in

##### File Directory Settings #####
##########################################
# The Salt Minion can redirect all file server operations to a local directory,
Expand Down
6 changes: 6 additions & 0 deletions doc/topics/releases/sodium.rst
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,9 @@ You can set this setting in your roster file like so:
user: root
passwd: P@ssword
set_path: '$PATH:/usr/local/bin/'


State Changes
=============
- Adding a new option for the State compiler, ``disabled_requisites`` will allow
requisites to be disabled during State runs.
2 changes: 2 additions & 0 deletions salt/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,7 @@ def _gather_buffer_space():
# Allow raw_shell option when using the ssh
# client via the Salt API
"netapi_allow_raw_shell": bool,
"disabled_requisites": (six.string_types, list),
}
)

Expand Down Expand Up @@ -1216,6 +1217,7 @@ def _gather_buffer_space():
"discovery": False,
"schedule": {},
"ssh_merge_pillar": True,
"disabled_requisites": [],
}
)

Expand Down
16 changes: 16 additions & 0 deletions salt/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -1684,6 +1684,9 @@ def requisite_in(self, high):
)
extend = {}
errors = []
disabled_reqs = self.opts.get("disabled_requisites", [])
if not isinstance(disabled_reqs, list):
disabled_reqs = [disabled_reqs]
for id_, body in six.iteritems(high):
if not isinstance(body, dict):
continue
Expand All @@ -1702,6 +1705,11 @@ def requisite_in(self, high):
key = next(iter(arg))
if key not in req_in:
continue
if key in disabled_reqs:
log.warning(
"The %s requisite has been disabled, Ignoring.", key
)
continue
rkey = key.split("_")[0]
items = arg[key]
if isinstance(items, dict):
Expand Down Expand Up @@ -2543,6 +2551,9 @@ def check_requisite(self, low, running, chunks, pre=False):
Look into the running data to check the status of all requisite
states
"""
disabled_reqs = self.opts.get("disabled_requisites", [])
if not isinstance(disabled_reqs, list):
disabled_reqs = [disabled_reqs]
present = False
# If mod_watch is not available make it a require
if "watch" in low:
Expand Down Expand Up @@ -2598,6 +2609,11 @@ def check_requisite(self, low, running, chunks, pre=False):
reqs["prerequired"] = []
for r_state in reqs:
if r_state in low and low[r_state] is not None:
if r_state in disabled_reqs:
log.warning(
"The %s requisite has been disabled, Ignoring.", r_state
)
continue
for req in low[r_state]:
if isinstance(req, six.string_types):
req = {"id": req}
Expand Down
83 changes: 83 additions & 0 deletions tests/unit/test_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,89 @@ def test_verify_retry_parsing(self):
with patch.object(state_obj, "_run_check", return_value=mock):
self.assertDictContainsSubset(expected_result, state_obj.call(low_data))

def test_render_requisite_require_disabled(self):
"""
Test that the state compiler correctly deliver a rendering
exception when a requisite cannot be resolved
"""
with patch("salt.state.State._gather_pillar") as state_patch:
high_data = {
"step_one": OrderedDict(
[
(
"test",
[
OrderedDict(
[("require", [OrderedDict([("test", "step_two")])])]
),
"succeed_with_changes",
{"order": 10000},
],
),
("__sls__", "test.disable_require"),
("__env__", "base"),
]
),
"step_two": {
"test": ["succeed_with_changes", {"order": 10001}],
"__env__": "base",
"__sls__": "test.disable_require",
},
}

minion_opts = self.get_temp_config("minion")
minion_opts["disabled_requisites"] = ["require"]
state_obj = salt.state.State(minion_opts)
ret = state_obj.call_high(high_data)
run_num = ret["test_|-step_one_|-step_one_|-succeed_with_changes"][
"__run_num__"
]
self.assertEqual(run_num, 0)

def test_render_requisite_require_in_disabled(self):
"""
Test that the state compiler correctly deliver a rendering
exception when a requisite cannot be resolved
"""
with patch("salt.state.State._gather_pillar") as state_patch:
high_data = {
"step_one": {
"test": ["succeed_with_changes", {"order": 10000}],
"__env__": "base",
"__sls__": "test.disable_require_in",
},
"step_two": OrderedDict(
[
(
"test",
[
OrderedDict(
[
(
"require_in",
[OrderedDict([("test", "step_one")])],
)
]
),
"succeed_with_changes",
{"order": 10001},
],
),
("__sls__", "test.disable_require_in"),
("__env__", "base"),
]
),
}

minion_opts = self.get_temp_config("minion")
minion_opts["disabled_requisites"] = ["require_in"]
state_obj = salt.state.State(minion_opts)
ret = state_obj.call_high(high_data)
run_num = ret["test_|-step_one_|-step_one_|-succeed_with_changes"][
"__run_num__"
]
self.assertEqual(run_num, 0)


class HighStateTestCase(TestCase, AdaptedConfigurationTestCaseMixin):
def setUp(self):
Expand Down