Group checks for failhard setting in () in state.check_failhard function

Fixes #38683

When two states combine the `require`, `failhard`, and `order` options,
the `order` option should be ignored because `require` is present. Then
the `failhard` option should make the state run fail.

The check for "failhard" in the `check_failhard` function in the state
compiler was too broad. We want "failhard" to be true AND tag to be in
the `running` dict. Without the parens around the first OR statement,
we were bypassing the AND requirement because failhard was found.

Since the second state's tag was not found in the running dict, the state
run stacktraces on a KeyError.
This commit is contained in:
rallytime 2017-04-03 14:41:54 -06:00
parent 02a1f642ab
commit ede4c28887
3 changed files with 35 additions and 2 deletions

View file

@ -1825,8 +1825,7 @@ class State(object):
tag = _gen_tag(low)
if self.opts.get('test', False):
return False
if (low.get('failhard', False) or self.opts['failhard']
and tag in running):
if (low.get('failhard', False) or self.opts['failhard']) and tag in running:
if running[tag]['result'] is None:
return False
return not running[tag]['result']

View file

@ -0,0 +1,13 @@
a:
test.show_notification:
- name: a
- text: message
- require:
- test: b
- order: 1
- failhard: True
b:
test.fail_with_changes:
- name: b
- failhard: True

View file

@ -1112,6 +1112,27 @@ class StateModuleTest(integration.ModuleCase,
self.assertEqual(state_run[bar_state]['comment'],
'Command "echo bar" run')
def test_issue_38683_require_order_failhard_combination(self):
'''
This tests the case where require, order, and failhard are all used together in a state definition.
Previously, the order option, which used in tandem with require and failhard, would cause the state
compiler to stacktrace. This exposed a logic error in the ``check_failhard`` function of the state
compiler. With the logic error resolved, this test should now pass.
See https://github.com/saltstack/salt/issues/38683 for more information.
'''
state_run = self.run_function(
'state.sls',
mods='requisites.require_order_failhard_combo'
)
state_id = 'test_|-b_|-b_|-fail_with_changes'
self.assertIn(state_id, state_run)
self.assertEqual(state_run[state_id]['comment'], 'Failure!')
self.assertFalse(state_run[state_id]['result'])
if __name__ == '__main__':
from integration import run_tests
run_tests(StateModuleTest)