Accounting for a case when multiple onfails are used along with requires. Previously if you have multiple states using 'onfail' and two of those states using a 'require' against the first one state, the last two will run even if the 'onfail' isn't met because the 'require' is met because the first state returns true even though it didn't excute. This change adds an additional hidden variable that is used when checking requisities to determine if the state actually ran.

This commit is contained in:
Gareth J. Greenaway 2018-03-15 17:45:42 -07:00
parent 0a68c22332
commit 152c43c843
No known key found for this signature in database
GPG Key ID: 10B62F8A7CAD7A41
4 changed files with 104 additions and 1 deletions

View File

@ -2207,7 +2207,8 @@ class State(object):
if r_state == 'prereq' and not run_dict[tag]['result'] is None:
fun_stats.add('pre')
else:
fun_stats.add('met')
if run_dict[tag].get('__state_ran__', True):
fun_stats.add('met')
if 'unmet' in fun_stats:
status = 'unmet'
@ -2462,6 +2463,7 @@ class State(object):
'duration': duration,
'start_time': start_time,
'comment': 'State was not run because onfail req did not change',
'__state_ran__': False,
'__run_num__': self.__run_num,
'__sls__': low['__sls__']}
self.__run_num += 1
@ -2472,6 +2474,7 @@ class State(object):
'duration': duration,
'start_time': start_time,
'comment': 'State was not run because none of the onchanges reqs changed',
'__state_ran__': False,
'__run_num__': self.__run_num,
'__sls__': low['__sls__']}
self.__run_num += 1

View File

@ -0,0 +1,25 @@
a:
cmd.run:
- name: exit 1
b:
cmd.run:
- name: echo b
- onfail:
- cmd: a
c:
cmd.run:
- name: echo c
- onfail:
- cmd: a
- require:
- cmd: b
d:
cmd.run:
- name: echo d
- onfail:
- cmd: a
- require:
- cmd: c

View File

@ -0,0 +1,25 @@
a:
cmd.run:
- name: exit 0
b:
cmd.run:
- name: echo b
- onfail:
- cmd: a
c:
cmd.run:
- name: echo c
- onfail:
- cmd: a
- require:
- cmd: b
d:
cmd.run:
- name: echo d
- onfail:
- cmd: a
- require:
- cmd: c

View File

@ -1095,6 +1095,56 @@ class StateModuleTest(ModuleCase, SaltReturnAssertsMixin):
test_data = state_run['cmd_|-test_non_failing_state_|-echo "Should not run"_|-run']
self.assertIn('duration', test_data)
def test_multiple_onfail_requisite_with_required(self):
'''
test to ensure multiple states are run
when specified as onfails for a single state.
This is a test for the issue:
https://github.com/saltstack/salt/issues/46552
'''
state_run = self.run_function('state.sls', mods='requisites.onfail_multiple_required')
retcode = state_run['cmd_|-b_|-echo b_|-run']['changes']['retcode']
self.assertEqual(retcode, 0)
retcode = state_run['cmd_|-c_|-echo c_|-run']['changes']['retcode']
self.assertEqual(retcode, 0)
retcode = state_run['cmd_|-d_|-echo d_|-run']['changes']['retcode']
self.assertEqual(retcode, 0)
stdout = state_run['cmd_|-b_|-echo b_|-run']['changes']['stdout']
self.assertEqual(stdout, 'b')
stdout = state_run['cmd_|-c_|-echo c_|-run']['changes']['stdout']
self.assertEqual(stdout, 'c')
stdout = state_run['cmd_|-d_|-echo d_|-run']['changes']['stdout']
self.assertEqual(stdout, 'd')
def test_multiple_onfail_requisite_with_required_no_run(self):
'''
test to ensure multiple states are not run
when specified as onfails for a single state
which fails.
This is a test for the issue:
https://github.com/saltstack/salt/issues/46552
'''
state_run = self.run_function('state.sls', mods='requisites.onfail_multiple_required_no_run')
expected = 'State was not run because onfail req did not change'
stdout = state_run['cmd_|-b_|-echo b_|-run']['comment']
self.assertEqual(stdout, expected)
stdout = state_run['cmd_|-c_|-echo c_|-run']['comment']
self.assertEqual(stdout, expected)
stdout = state_run['cmd_|-d_|-echo d_|-run']['comment']
self.assertEqual(stdout, expected)
# listen tests
def test_listen_requisite(self):