mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-04-24 03:11:24 -07:00
So I thought I fixed it before, but there's still one location where the `rc` value is influential to decide whether a task failed or not. We already established in #24867 that it is up to the module to decide what the return code actually means, not the task executor. We modified the existing modules to move that logic into the module (eg. for command, shell, etc.) This relates to the integration tests of win_robocopy, where different return codes have different meanings: - 0 -- No files copied. - 1 -- Files copied successfully! (changed) - 2 -- Some Extra files or directories were detected. No files were copied. (warning) - 3 -- (2+1) Some files were copied. Additional files were present. (changed) - 4 -- Some mismatched files or directories were detected. Housekeeping might be required! (changed + warning) - 5 -- (4+1) Some files were copied. Some files were mismatched. (changed + warning) - 6 -- (4+2) Additional files and mismatched files exist. No files were copied. (warning) - 7 -- (4+1+2) Files were copied, a file mismatch was present, and additional files were present. (changed + warning) - 8 -- Some files or directories could not be copied! (changed + failed) - 9 - 15 -- Fatal error. Check log message! (failed) - 16 -- Serious Error! No files were copied! Do you have permissions to access $src and $dest? (failed) This also fixes #24652
85 lines
3 KiB
Python
85 lines
3 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 interpreting 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, task_fields=None):
|
|
self._host = host
|
|
self._task = task
|
|
|
|
if isinstance(return_data, dict):
|
|
self._result = return_data.copy()
|
|
else:
|
|
self._result = DataLoader().load(return_data)
|
|
|
|
if task_fields is None:
|
|
self._task_fields = dict()
|
|
else:
|
|
self._task_fields = task_fields
|
|
|
|
@property
|
|
def task_name(self):
|
|
return self._task_fields.get('name', None) or self._task.get_name()
|
|
|
|
def is_changed(self):
|
|
return self._check_key('changed')
|
|
|
|
def is_skipped(self):
|
|
# loop results
|
|
if 'results' in self._result:
|
|
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')
|
|
|
|
def is_unreachable(self):
|
|
return self._check_key('unreachable')
|
|
|
|
def _check_key(self, key):
|
|
'''get a specific key from the result or it's items'''
|
|
|
|
if isinstance(self._result, dict) and key in self._result:
|
|
return self._result.get(key, False)
|
|
else:
|
|
flag = False
|
|
for res in self._result.get('results', []):
|
|
if isinstance(res, dict):
|
|
flag |= res.get(key, False)
|
|
return flag
|