Return with proper retcodes in batch mode

Check for the highest retcode received in batch mode and exit with it.

Also, an integration test for the same.

Closes #37492
This commit is contained in:
Mike Place 2016-11-11 14:03:29 +13:00
parent 3079d78332
commit b6031524e5
No known key found for this signature in database
GPG key ID: 9136F4F13705CFD3
3 changed files with 19 additions and 9 deletions

View file

@ -224,14 +224,9 @@ class Batch(object):
wait.append(datetime.now() + timedelta(seconds=bwait))
if self.opts.get('raw'):
yield data
elif self.opts.get('failhard'):
# When failhard is passed, we need to return all data to include
# the retcode to use in salt/cli/salt.py later. See issue #24996.
else:
ret[minion] = data
yield {minion: data}
else:
ret[minion] = data['ret']
yield {minion: data['ret']}
if not self.quiet:
ret[minion] = data['ret']
data[minion] = data.pop('ret')

View file

@ -53,6 +53,10 @@ class SaltCMD(parsers.SaltCMDOptionParser):
return
if self.options.batch or self.options.static:
# _run_batch() will handle all output and
# exit with the appropriate error condition
# Execution will not continue past this point
# in batch mode.
self._run_batch()
else:
if self.options.timeout <= 0:
@ -233,10 +237,14 @@ class SaltCMD(parsers.SaltCMDOptionParser):
# We will print errors to the console further down the stack
sys.exit(1)
# Printing the output is already taken care of in run() itself
retcode = 0
for res in batch.run():
if self.options.failhard:
for ret in six.itervalues(res):
retcode = salt.utils.job.get_retcode(ret)
for ret in six.itervalues(res):
job_retcode = salt.utils.job.get_retcode(ret)
if job_retcode > retcode:
# Exit with the highest retcode we find
retcode = job_retcode
if self.options.failhard:
if retcode != 0:
sys.stderr.write(
'{0}\nERROR: Minions returned with non-zero exit code.\n'.format(
@ -244,6 +252,7 @@ class SaltCMD(parsers.SaltCMDOptionParser):
)
)
sys.exit(retcode)
sys.exit(retcode)
def _print_errors_summary(self, errors):
if errors:

View file

@ -89,6 +89,12 @@ class BatchTest(integration.ShellCase):
cmd = sorted(self.run_salt('-G \'os:{0}\' -b 25% test.ping'.format(os_grain)))
self.assertListEqual(cmd, sorted(ret))
def test_batch_exit_code(self):
'''
Test that a failed state returns a non-zero exit code in batch mode
'''
cmd = self.run_salt(' "*" state.single test.fail_without_changes name=test_me -b 25%', with_retcode=True)
self.assertEqual(cmd[-1], 2)
if __name__ == '__main__':
from integration import run_tests