mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-04-24 11:21:25 -07:00
When a task result has an empty results list, the list should be ignored when determining the results of `_check_key`. Here the empty list is treated the same as a non-existent list. This fixes a bug that manifests itself with squashed items - namely the task result contains the correct value for the key, but an empty results list. The empty results list was treated as zero failures when deciding which handler to call - so the task show as a success in the output, but is deemed to have failed when deciding whether to continue. This also demonstrates a mismatch between task result processing and play iteration. A test is also added for this case, but it would not have caught the bug - because the bug is really in the display, and not the success/failure of the task (visually the test is more accurate). Fixes ansible/ansible-modules-core#4214
72 lines
2.7 KiB
Python
72 lines
2.7 KiB
Python
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
|
|
#
|
|
# This file is part of Ansible
|
|
#
|
|
# Ansible is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Ansible is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
# Make coding more python3-ish
|
|
from __future__ import (absolute_import, division, print_function)
|
|
__metaclass__ = type
|
|
|
|
from ansible.parsing.dataloader import DataLoader
|
|
|
|
class TaskResult:
|
|
'''
|
|
This class is responsible for interpretting the resulting data
|
|
from an executed task, and provides helper methods for determining
|
|
the result of a given task.
|
|
'''
|
|
|
|
def __init__(self, host, task, return_data):
|
|
self._host = host
|
|
self._task = task
|
|
if isinstance(return_data, dict):
|
|
self._result = return_data.copy()
|
|
else:
|
|
self._result = DataLoader().load(return_data)
|
|
|
|
def is_changed(self):
|
|
return self._check_key('changed')
|
|
|
|
def is_skipped(self):
|
|
# loop results
|
|
if 'results' in self._result and self._task.loop:
|
|
results = self._result['results']
|
|
# Loop tasks are only considered skipped if all items were skipped.
|
|
# some squashed results (eg, yum) are not dicts and can't be skipped individually
|
|
if results and all(isinstance(res, dict) and res.get('skipped', False) for res in results):
|
|
return True
|
|
|
|
# regular tasks and squashed non-dict results
|
|
return self._result.get('skipped', False)
|
|
|
|
def is_failed(self):
|
|
if 'failed_when_result' in self._result or \
|
|
'results' in self._result and True in [True for x in self._result['results'] if 'failed_when_result' in x]:
|
|
return self._check_key('failed_when_result')
|
|
else:
|
|
return self._check_key('failed') or self._result.get('rc', 0) != 0
|
|
|
|
def is_unreachable(self):
|
|
return self._check_key('unreachable')
|
|
|
|
def _check_key(self, key):
|
|
if self._result.get('results', []) and self._task.loop:
|
|
flag = False
|
|
for res in self._result.get('results', []):
|
|
if isinstance(res, dict):
|
|
flag |= res.get(key, False)
|
|
return flag
|
|
else:
|
|
return self._result.get(key, False)
|