ansible-core 2.19.0b1__py3-none-any.whl → 2.19.0b3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ansible/_internal/_ansiballz.py +1 -4
- ansible/_internal/_collection_proxy.py +47 -0
- ansible/_internal/_errors/_handler.py +4 -4
- ansible/_internal/_json/__init__.py +47 -4
- ansible/_internal/_json/_profiles/_legacy.py +2 -3
- ansible/_internal/_templating/_datatag.py +3 -4
- ansible/_internal/_templating/_engine.py +6 -1
- ansible/_internal/_templating/_jinja_bits.py +4 -4
- ansible/_internal/_templating/_jinja_plugins.py +7 -17
- ansible/cli/__init__.py +12 -5
- ansible/cli/arguments/option_helpers.py +4 -1
- ansible/cli/doc.py +14 -8
- ansible/config/base.yml +17 -20
- ansible/config/manager.py +2 -2
- ansible/constants.py +0 -62
- ansible/errors/__init__.py +6 -2
- ansible/executor/module_common.py +11 -7
- ansible/executor/process/worker.py +31 -26
- ansible/executor/task_executor.py +38 -31
- ansible/executor/task_queue_manager.py +62 -52
- ansible/executor/task_result.py +168 -72
- ansible/galaxy/api.py +1 -1
- ansible/galaxy/collection/__init__.py +3 -3
- ansible/inventory/manager.py +2 -1
- ansible/module_utils/_internal/_ansiballz.py +4 -30
- ansible/module_utils/_internal/_datatag/_tags.py +3 -25
- ansible/module_utils/_internal/_deprecator.py +134 -0
- ansible/module_utils/_internal/_plugin_info.py +25 -0
- ansible/module_utils/_internal/_validation.py +14 -0
- ansible/module_utils/ansible_release.py +1 -1
- ansible/module_utils/basic.py +68 -23
- ansible/module_utils/common/arg_spec.py +8 -3
- ansible/module_utils/common/messages.py +40 -23
- ansible/module_utils/common/process.py +0 -1
- ansible/module_utils/common/respawn.py +0 -7
- ansible/module_utils/common/warnings.py +13 -13
- ansible/module_utils/datatag.py +13 -13
- ansible/modules/async_status.py +1 -1
- ansible/modules/dnf5.py +1 -1
- ansible/modules/get_url.py +1 -1
- ansible/parsing/utils/jsonify.py +40 -0
- ansible/parsing/yaml/objects.py +16 -5
- ansible/playbook/included_file.py +25 -12
- ansible/playbook/task.py +0 -2
- ansible/plugins/__init__.py +18 -8
- ansible/plugins/action/__init__.py +6 -14
- ansible/plugins/action/gather_facts.py +2 -4
- ansible/plugins/callback/__init__.py +173 -86
- ansible/plugins/callback/default.py +79 -79
- ansible/plugins/callback/junit.py +20 -19
- ansible/plugins/callback/minimal.py +17 -17
- ansible/plugins/callback/oneline.py +23 -16
- ansible/plugins/callback/tree.py +13 -6
- ansible/plugins/connection/local.py +1 -1
- ansible/plugins/connection/paramiko_ssh.py +9 -2
- ansible/plugins/doc_fragments/action_core.py +1 -1
- ansible/plugins/filter/core.py +12 -2
- ansible/plugins/inventory/__init__.py +2 -2
- ansible/plugins/loader.py +194 -130
- ansible/plugins/lookup/url.py +2 -2
- ansible/plugins/strategy/__init__.py +76 -82
- ansible/plugins/strategy/free.py +4 -4
- ansible/plugins/strategy/linear.py +11 -9
- ansible/plugins/test/core.py +1 -1
- ansible/release.py +1 -1
- ansible/template/__init__.py +8 -6
- ansible/utils/collection_loader/_collection_meta.py +5 -3
- ansible/utils/display.py +141 -79
- ansible/utils/py3compat.py +1 -7
- ansible/utils/ssh_functions.py +4 -1
- ansible/utils/vars.py +23 -0
- ansible/vars/clean.py +1 -1
- ansible/vars/manager.py +18 -27
- ansible/vars/plugins.py +4 -4
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/METADATA +1 -1
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/RECORD +89 -85
- ansible_test/_internal/commands/sanity/pylint.py +1 -0
- ansible_test/_internal/docker_util.py +4 -3
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +475 -0
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_comment.py +137 -0
- ansible/module_utils/_internal/_dataclass_annotation_patch.py +0 -64
- ansible/module_utils/_internal/_plugin_exec_context.py +0 -49
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +0 -399
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/Apache-License.txt +0 -0
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/COPYING +0 -0
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/MIT-license.txt +0 -0
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/PSF-license.txt +0 -0
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/WHEEL +0 -0
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/simplified_bsd.txt +0 -0
- {ansible_core-2.19.0b1.dist-info → ansible_core-2.19.0b3.dist-info}/top_level.txt +0 -0
@@ -26,6 +26,7 @@ import sys
|
|
26
26
|
import threading
|
27
27
|
import time
|
28
28
|
import typing as t
|
29
|
+
import collections.abc as _c
|
29
30
|
|
30
31
|
from collections import deque
|
31
32
|
|
@@ -35,13 +36,13 @@ from ansible import context
|
|
35
36
|
from ansible.errors import AnsibleError, AnsibleFileNotFound, AnsibleParserError, AnsibleTemplateError
|
36
37
|
from ansible.executor.play_iterator import IteratingStates, PlayIterator
|
37
38
|
from ansible.executor.process.worker import WorkerProcess
|
38
|
-
from ansible.executor.task_result import
|
39
|
+
from ansible.executor.task_result import _RawTaskResult, _WireTaskResult
|
39
40
|
from ansible.executor.task_queue_manager import CallbackSend, DisplaySend, PromptSend, TaskQueueManager
|
40
|
-
from ansible.module_utils.six import string_types
|
41
41
|
from ansible.module_utils.common.text.converters import to_text
|
42
42
|
from ansible.module_utils.connection import Connection, ConnectionError
|
43
43
|
from ansible.playbook.handler import Handler
|
44
44
|
from ansible.playbook.helpers import load_list_of_blocks
|
45
|
+
from ansible.playbook.included_file import IncludedFile
|
45
46
|
from ansible.playbook.task import Task
|
46
47
|
from ansible.playbook.task_include import TaskInclude
|
47
48
|
from ansible.plugins import loader as plugin_loader
|
@@ -89,7 +90,9 @@ def _get_item_vars(result, task):
|
|
89
90
|
return item_vars
|
90
91
|
|
91
92
|
|
92
|
-
def results_thread_main(strategy):
|
93
|
+
def results_thread_main(strategy: StrategyBase) -> None:
|
94
|
+
value: object
|
95
|
+
|
93
96
|
while True:
|
94
97
|
try:
|
95
98
|
result = strategy._final_q.get()
|
@@ -99,13 +102,10 @@ def results_thread_main(strategy):
|
|
99
102
|
dmethod = getattr(display, result.method)
|
100
103
|
dmethod(*result.args, **result.kwargs)
|
101
104
|
elif isinstance(result, CallbackSend):
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
strategy._tqm.send_callback(result.method_name, *result.args, **result.kwargs)
|
107
|
-
elif isinstance(result, TaskResult):
|
108
|
-
strategy.normalize_task_result(result)
|
105
|
+
task_result = strategy._convert_wire_task_result_to_raw(result.wire_task_result)
|
106
|
+
strategy._tqm.send_callback(result.method_name, task_result)
|
107
|
+
elif isinstance(result, _WireTaskResult):
|
108
|
+
result = strategy._convert_wire_task_result_to_raw(result)
|
109
109
|
with strategy._results_lock:
|
110
110
|
strategy._results.append(result)
|
111
111
|
elif isinstance(result, PromptSend):
|
@@ -137,7 +137,7 @@ def results_thread_main(strategy):
|
|
137
137
|
def debug_closure(func):
|
138
138
|
"""Closure to wrap ``StrategyBase._process_pending_results`` and invoke the task debugger"""
|
139
139
|
@functools.wraps(func)
|
140
|
-
def inner(self, iterator, one_pass=False, max_passes=None):
|
140
|
+
def inner(self, iterator: PlayIterator, one_pass: bool = False, max_passes: int | None = None) -> list[_RawTaskResult]:
|
141
141
|
status_to_stats_map = (
|
142
142
|
('is_failed', 'failures'),
|
143
143
|
('is_unreachable', 'dark'),
|
@@ -148,12 +148,12 @@ def debug_closure(func):
|
|
148
148
|
# We don't know the host yet, copy the previous states, for lookup after we process new results
|
149
149
|
prev_host_states = iterator.host_states.copy()
|
150
150
|
|
151
|
-
results = func(self, iterator, one_pass=one_pass, max_passes=max_passes)
|
152
|
-
_processed_results = []
|
151
|
+
results: list[_RawTaskResult] = func(self, iterator, one_pass=one_pass, max_passes=max_passes)
|
152
|
+
_processed_results: list[_RawTaskResult] = []
|
153
153
|
|
154
154
|
for result in results:
|
155
|
-
task = result.
|
156
|
-
host = result.
|
155
|
+
task = result.task
|
156
|
+
host = result.host
|
157
157
|
_queued_task_args = self._queued_task_cache.pop((host.name, task._uuid), None)
|
158
158
|
task_vars = _queued_task_args['task_vars']
|
159
159
|
play_context = _queued_task_args['play_context']
|
@@ -239,7 +239,7 @@ class StrategyBase:
|
|
239
239
|
# outstanding tasks still in queue
|
240
240
|
self._blocked_hosts: dict[str, bool] = dict()
|
241
241
|
|
242
|
-
self._results: deque[
|
242
|
+
self._results: deque[_RawTaskResult] = deque()
|
243
243
|
self._results_lock = threading.Condition(threading.Lock())
|
244
244
|
|
245
245
|
# create the result processing thread for reading results in the background
|
@@ -249,7 +249,7 @@ class StrategyBase:
|
|
249
249
|
|
250
250
|
# holds the list of active (persistent) connections to be shutdown at
|
251
251
|
# play completion
|
252
|
-
self._active_connections: dict[
|
252
|
+
self._active_connections: dict[Host, str] = dict()
|
253
253
|
|
254
254
|
# Caches for get_host calls, to avoid calling excessively
|
255
255
|
# These values should be set at the top of the ``run`` method of each
|
@@ -447,39 +447,33 @@ class StrategyBase:
|
|
447
447
|
for target_host in host_list:
|
448
448
|
_set_host_facts(target_host, always_facts)
|
449
449
|
|
450
|
-
def
|
451
|
-
"""
|
452
|
-
|
453
|
-
|
454
|
-
Only the ``Host.name`` and ``Task._uuid`` are commonly sent back from
|
455
|
-
the ``TaskExecutor`` or ``WorkerProcess`` due to performance concerns
|
450
|
+
def _convert_wire_task_result_to_raw(self, wire_task_result: _WireTaskResult) -> _RawTaskResult:
|
451
|
+
"""Return a `_RawTaskResult` created from a `_WireTaskResult`."""
|
452
|
+
host = self._inventory.get_host(wire_task_result.host_name)
|
453
|
+
queue_cache_entry = (host.name, wire_task_result.task_uuid)
|
456
454
|
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
#
|
462
|
-
|
455
|
+
try:
|
456
|
+
found_task = self._queued_task_cache[queue_cache_entry]['task']
|
457
|
+
except KeyError:
|
458
|
+
# This should only happen due to an implicit task created by the
|
459
|
+
# TaskExecutor, restrict this behavior to the explicit use case
|
460
|
+
# of an implicit async_status task
|
461
|
+
if wire_task_result.task_fields.get('action') != 'async_status':
|
462
|
+
raise
|
463
|
+
|
464
|
+
task = Task()
|
465
|
+
else:
|
466
|
+
task = found_task.copy(exclude_parent=True, exclude_tasks=True)
|
467
|
+
task._parent = found_task._parent
|
463
468
|
|
464
|
-
|
465
|
-
# If the value is a string, it is ``Task._uuid``
|
466
|
-
queue_cache_entry = (task_result._host.name, task_result._task)
|
467
|
-
try:
|
468
|
-
found_task = self._queued_task_cache[queue_cache_entry]['task']
|
469
|
-
except KeyError:
|
470
|
-
# This should only happen due to an implicit task created by the
|
471
|
-
# TaskExecutor, restrict this behavior to the explicit use case
|
472
|
-
# of an implicit async_status task
|
473
|
-
if task_result._task_fields.get('action') != 'async_status':
|
474
|
-
raise
|
475
|
-
original_task = Task()
|
476
|
-
else:
|
477
|
-
original_task = found_task.copy(exclude_parent=True, exclude_tasks=True)
|
478
|
-
original_task._parent = found_task._parent
|
479
|
-
original_task.from_attrs(task_result._task_fields)
|
480
|
-
task_result._task = original_task
|
469
|
+
task.from_attrs(wire_task_result.task_fields)
|
481
470
|
|
482
|
-
return
|
471
|
+
return _RawTaskResult(
|
472
|
+
host=host,
|
473
|
+
task=task,
|
474
|
+
return_data=wire_task_result.return_data,
|
475
|
+
task_fields=wire_task_result.task_fields,
|
476
|
+
)
|
483
477
|
|
484
478
|
def search_handlers_by_notification(self, notification: str, iterator: PlayIterator) -> t.Generator[Handler, None, None]:
|
485
479
|
handlers = [h for b in reversed(iterator._play.handlers) for h in b.block]
|
@@ -537,7 +531,7 @@ class StrategyBase:
|
|
537
531
|
yield handler
|
538
532
|
|
539
533
|
@debug_closure
|
540
|
-
def _process_pending_results(self, iterator: PlayIterator, one_pass: bool = False, max_passes: int | None = None) -> list[
|
534
|
+
def _process_pending_results(self, iterator: PlayIterator, one_pass: bool = False, max_passes: int | None = None) -> list[_RawTaskResult]:
|
541
535
|
"""
|
542
536
|
Reads results off the final queue and takes appropriate action
|
543
537
|
based on the result (executing callbacks, updating state, etc.).
|
@@ -553,8 +547,8 @@ class StrategyBase:
|
|
553
547
|
finally:
|
554
548
|
self._results_lock.release()
|
555
549
|
|
556
|
-
original_host = task_result.
|
557
|
-
original_task: Task = task_result.
|
550
|
+
original_host = task_result.host
|
551
|
+
original_task: Task = task_result.task
|
558
552
|
|
559
553
|
# all host status messages contain 2 entries: (msg, task_result)
|
560
554
|
role_ran = False
|
@@ -588,7 +582,7 @@ class StrategyBase:
|
|
588
582
|
original_host.name,
|
589
583
|
dict(
|
590
584
|
ansible_failed_task=original_task.serialize(),
|
591
|
-
ansible_failed_result=task_result.
|
585
|
+
ansible_failed_result=task_result._return_data,
|
592
586
|
),
|
593
587
|
)
|
594
588
|
else:
|
@@ -596,7 +590,7 @@ class StrategyBase:
|
|
596
590
|
else:
|
597
591
|
self._tqm._stats.increment('ok', original_host.name)
|
598
592
|
self._tqm._stats.increment('ignored', original_host.name)
|
599
|
-
if
|
593
|
+
if task_result.is_changed():
|
600
594
|
self._tqm._stats.increment('changed', original_host.name)
|
601
595
|
self._tqm.send_callback('v2_runner_on_failed', task_result, ignore_errors=ignore_errors)
|
602
596
|
elif task_result.is_unreachable():
|
@@ -618,9 +612,9 @@ class StrategyBase:
|
|
618
612
|
if original_task.loop:
|
619
613
|
# this task had a loop, and has more than one result, so
|
620
614
|
# loop over all of them instead of a single result
|
621
|
-
result_items = task_result.
|
615
|
+
result_items = task_result._loop_results
|
622
616
|
else:
|
623
|
-
result_items = [task_result.
|
617
|
+
result_items = [task_result._return_data]
|
624
618
|
|
625
619
|
for result_item in result_items:
|
626
620
|
if '_ansible_notify' in result_item and task_result.is_changed():
|
@@ -665,7 +659,7 @@ class StrategyBase:
|
|
665
659
|
|
666
660
|
if 'add_host' in result_item or 'add_group' in result_item:
|
667
661
|
item_vars = _get_item_vars(result_item, original_task)
|
668
|
-
found_task_vars = self._queued_task_cache.get((original_host.name, task_result.
|
662
|
+
found_task_vars = self._queued_task_cache.get((original_host.name, task_result.task._uuid))['task_vars']
|
669
663
|
if item_vars:
|
670
664
|
all_task_vars = combine_vars(found_task_vars, item_vars)
|
671
665
|
else:
|
@@ -680,17 +674,17 @@ class StrategyBase:
|
|
680
674
|
original_task._resolve_conditional(original_task.failed_when, all_task_vars))
|
681
675
|
|
682
676
|
if original_task.loop or original_task.loop_with:
|
683
|
-
new_item_result =
|
684
|
-
task_result.
|
685
|
-
task_result.
|
677
|
+
new_item_result = _RawTaskResult(
|
678
|
+
task_result.host,
|
679
|
+
task_result.task,
|
686
680
|
result_item,
|
687
|
-
task_result.
|
681
|
+
task_result.task_fields,
|
688
682
|
)
|
689
683
|
self._tqm.send_callback('v2_runner_item_on_ok', new_item_result)
|
690
684
|
if result_item.get('changed', False):
|
691
|
-
task_result.
|
685
|
+
task_result._return_data['changed'] = True
|
692
686
|
if result_item.get('failed', False):
|
693
|
-
task_result.
|
687
|
+
task_result._return_data['failed'] = True
|
694
688
|
|
695
689
|
if 'ansible_facts' in result_item and original_task.action not in C._ACTION_DEBUG:
|
696
690
|
# if delegated fact and we are delegating facts, we need to change target host for them
|
@@ -738,13 +732,13 @@ class StrategyBase:
|
|
738
732
|
else:
|
739
733
|
self._tqm._stats.set_custom_stats(k, data[k], myhost)
|
740
734
|
|
741
|
-
if 'diff' in task_result.
|
735
|
+
if 'diff' in task_result._return_data:
|
742
736
|
if self._diff or getattr(original_task, 'diff', False):
|
743
737
|
self._tqm.send_callback('v2_on_file_diff', task_result)
|
744
738
|
|
745
739
|
if not isinstance(original_task, TaskInclude):
|
746
740
|
self._tqm._stats.increment('ok', original_host.name)
|
747
|
-
if
|
741
|
+
if task_result.is_changed():
|
748
742
|
self._tqm._stats.increment('changed', original_host.name)
|
749
743
|
|
750
744
|
# finally, send the ok for this task
|
@@ -754,7 +748,7 @@ class StrategyBase:
|
|
754
748
|
if original_task.register:
|
755
749
|
host_list = self.get_task_hosts(iterator, original_host, original_task)
|
756
750
|
|
757
|
-
clean_copy = strip_internal_keys(module_response_deepcopy(task_result.
|
751
|
+
clean_copy = strip_internal_keys(module_response_deepcopy(task_result._return_data))
|
758
752
|
if 'invocation' in clean_copy:
|
759
753
|
del clean_copy['invocation']
|
760
754
|
|
@@ -805,7 +799,7 @@ class StrategyBase:
|
|
805
799
|
|
806
800
|
return ret_results
|
807
801
|
|
808
|
-
def _copy_included_file(self, included_file):
|
802
|
+
def _copy_included_file(self, included_file: IncludedFile) -> IncludedFile:
|
809
803
|
"""
|
810
804
|
A proven safe and performant way to create a copy of an included file
|
811
805
|
"""
|
@@ -818,7 +812,7 @@ class StrategyBase:
|
|
818
812
|
|
819
813
|
return ti_copy
|
820
814
|
|
821
|
-
def _load_included_file(self, included_file, iterator, is_handler=False, handle_stats_and_callbacks=True):
|
815
|
+
def _load_included_file(self, included_file: IncludedFile, iterator, is_handler=False, handle_stats_and_callbacks=True):
|
822
816
|
"""
|
823
817
|
Loads an included YAML file of tasks, applying the optional set of variables.
|
824
818
|
|
@@ -828,12 +822,12 @@ class StrategyBase:
|
|
828
822
|
"""
|
829
823
|
if handle_stats_and_callbacks:
|
830
824
|
display.deprecated(
|
831
|
-
"Reporting play recap stats and running callbacks functionality for "
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
version="2.21"
|
825
|
+
msg="Reporting play recap stats and running callbacks functionality for "
|
826
|
+
"``include_tasks`` in ``StrategyBase._load_included_file`` is deprecated. "
|
827
|
+
"See ``https://github.com/ansible/ansible/pull/79260`` for guidance on how to "
|
828
|
+
"move the reporting into specific strategy plugins to account for "
|
829
|
+
"``include_role`` tasks as well.",
|
830
|
+
version="2.21",
|
837
831
|
)
|
838
832
|
display.debug("loading included file: %s" % included_file._filename)
|
839
833
|
try:
|
@@ -865,11 +859,11 @@ class StrategyBase:
|
|
865
859
|
else:
|
866
860
|
reason = to_text(e)
|
867
861
|
if handle_stats_and_callbacks:
|
868
|
-
for
|
869
|
-
|
862
|
+
for tr in included_file._results:
|
863
|
+
tr._return_data['failed'] = True
|
870
864
|
|
871
865
|
for host in included_file._hosts:
|
872
|
-
tr =
|
866
|
+
tr = _RawTaskResult(host=host, task=included_file._task, return_data=dict(failed=True, reason=reason), task_fields={})
|
873
867
|
self._tqm._stats.increment('failures', host.name)
|
874
868
|
self._tqm.send_callback('v2_runner_on_failed', tr)
|
875
869
|
raise AnsibleError(reason) from e
|
@@ -905,7 +899,7 @@ class StrategyBase:
|
|
905
899
|
def _cond_not_supported_warn(self, task_name):
|
906
900
|
display.warning("%s task does not support when conditional" % task_name)
|
907
901
|
|
908
|
-
def _execute_meta(self, task: Task, play_context, iterator, target_host):
|
902
|
+
def _execute_meta(self, task: Task, play_context, iterator, target_host: Host):
|
909
903
|
task.resolved_action = 'ansible.builtin.meta' # _post_validate_args is never called for meta actions, so resolved_action hasn't been set
|
910
904
|
|
911
905
|
# meta tasks store their args in the _raw_params field of args,
|
@@ -1083,7 +1077,7 @@ class StrategyBase:
|
|
1083
1077
|
else:
|
1084
1078
|
display.vv(f"META: {header}")
|
1085
1079
|
|
1086
|
-
res =
|
1080
|
+
res = _RawTaskResult(target_host, task, result, {})
|
1087
1081
|
if skipped:
|
1088
1082
|
self._tqm.send_callback('v2_runner_on_skipped', res)
|
1089
1083
|
return [res]
|
@@ -1103,14 +1097,14 @@ class StrategyBase:
|
|
1103
1097
|
hosts_left.append(self._inventory.get_host(host))
|
1104
1098
|
return hosts_left
|
1105
1099
|
|
1106
|
-
def update_active_connections(self, results):
|
1100
|
+
def update_active_connections(self, results: _c.Iterable[_RawTaskResult]) -> None:
|
1107
1101
|
""" updates the current active persistent connections """
|
1108
1102
|
for r in results:
|
1109
|
-
if 'args' in r.
|
1110
|
-
socket_path = r.
|
1103
|
+
if 'args' in r.task_fields:
|
1104
|
+
socket_path = r.task_fields['args'].get('_ansible_socket')
|
1111
1105
|
if socket_path:
|
1112
|
-
if r.
|
1113
|
-
self._active_connections[r.
|
1106
|
+
if r.host not in self._active_connections:
|
1107
|
+
self._active_connections[r.host] = socket_path
|
1114
1108
|
|
1115
1109
|
|
1116
1110
|
class NextAction(object):
|
ansible/plugins/strategy/free.py
CHANGED
@@ -252,11 +252,11 @@ class StrategyModule(StrategyBase):
|
|
252
252
|
# FIXME: send the error to the callback; don't directly write to display here
|
253
253
|
display.error(ex)
|
254
254
|
for r in included_file._results:
|
255
|
-
r.
|
256
|
-
r.
|
257
|
-
self._tqm._stats.increment('failures', r.
|
255
|
+
r._return_data['failed'] = True
|
256
|
+
r._return_data['reason'] = str(ex)
|
257
|
+
self._tqm._stats.increment('failures', r.host.name)
|
258
258
|
self._tqm.send_callback('v2_runner_on_failed', r)
|
259
|
-
failed_includes_hosts.add(r.
|
259
|
+
failed_includes_hosts.add(r.host)
|
260
260
|
continue
|
261
261
|
else:
|
262
262
|
# since we skip incrementing the stats when the task result is
|
@@ -40,6 +40,8 @@ from ansible.utils.display import Display
|
|
40
40
|
from ansible.inventory.host import Host
|
41
41
|
from ansible.playbook.task import Task
|
42
42
|
from ansible.executor.play_iterator import PlayIterator
|
43
|
+
from ansible.playbook.play_context import PlayContext
|
44
|
+
from ansible.executor import task_result as _task_result
|
43
45
|
|
44
46
|
display = Display()
|
45
47
|
|
@@ -92,7 +94,7 @@ class StrategyModule(StrategyBase):
|
|
92
94
|
|
93
95
|
return host_tasks
|
94
96
|
|
95
|
-
def run(self, iterator, play_context):
|
97
|
+
def run(self, iterator, play_context: PlayContext): # type: ignore[override]
|
96
98
|
"""
|
97
99
|
The linear strategy is simple - get the next task and queue
|
98
100
|
it for all hosts, then wait for the queue to drain before
|
@@ -100,7 +102,7 @@ class StrategyModule(StrategyBase):
|
|
100
102
|
"""
|
101
103
|
|
102
104
|
# iterate over each task, while there is one left to run
|
103
|
-
result = self._tqm.RUN_OK
|
105
|
+
result = int(self._tqm.RUN_OK)
|
104
106
|
work_to_do = True
|
105
107
|
|
106
108
|
self._set_hosts_cache(iterator._play)
|
@@ -125,7 +127,7 @@ class StrategyModule(StrategyBase):
|
|
125
127
|
# flag set if task is set to any_errors_fatal
|
126
128
|
any_errors_fatal = False
|
127
129
|
|
128
|
-
results = []
|
130
|
+
results: list[_task_result._RawTaskResult] = []
|
129
131
|
for (host, task) in host_tasks:
|
130
132
|
if self._tqm._terminated:
|
131
133
|
break
|
@@ -285,11 +287,11 @@ class StrategyModule(StrategyBase):
|
|
285
287
|
# FIXME: send the error to the callback; don't directly write to display here
|
286
288
|
display.error(ex)
|
287
289
|
for r in included_file._results:
|
288
|
-
r.
|
289
|
-
r.
|
290
|
-
self._tqm._stats.increment('failures', r.
|
290
|
+
r._return_data['failed'] = True
|
291
|
+
r._return_data['reason'] = str(ex)
|
292
|
+
self._tqm._stats.increment('failures', r.host.name)
|
291
293
|
self._tqm.send_callback('v2_runner_on_failed', r)
|
292
|
-
failed_includes_hosts.add(r.
|
294
|
+
failed_includes_hosts.add(r.host)
|
293
295
|
else:
|
294
296
|
# since we skip incrementing the stats when the task result is
|
295
297
|
# first processed, we do so now for each host in the list
|
@@ -320,9 +322,9 @@ class StrategyModule(StrategyBase):
|
|
320
322
|
unreachable_hosts = []
|
321
323
|
for res in results:
|
322
324
|
if res.is_failed():
|
323
|
-
failed_hosts.append(res.
|
325
|
+
failed_hosts.append(res.host.name)
|
324
326
|
elif res.is_unreachable():
|
325
|
-
unreachable_hosts.append(res.
|
327
|
+
unreachable_hosts.append(res.host.name)
|
326
328
|
|
327
329
|
if any_errors_fatal and (failed_hosts or unreachable_hosts):
|
328
330
|
for host in hosts_left:
|
ansible/plugins/test/core.py
CHANGED
@@ -49,7 +49,7 @@ def timedout(result):
|
|
49
49
|
""" Test if task result yields a time out"""
|
50
50
|
if not isinstance(result, MutableMapping):
|
51
51
|
raise errors.AnsibleFilterError("The 'timedout' test expects a dictionary")
|
52
|
-
return result.get('timedout', False) and result['timedout'].get('period', False)
|
52
|
+
return result.get('timedout', False) and bool(result['timedout'].get('period', False))
|
53
53
|
|
54
54
|
|
55
55
|
def failed(result):
|
ansible/release.py
CHANGED
ansible/template/__init__.py
CHANGED
@@ -28,7 +28,7 @@ if _t.TYPE_CHECKING: # pragma: nocover
|
|
28
28
|
|
29
29
|
|
30
30
|
_display: _t.Final[_Display] = _Display()
|
31
|
-
_UNSET = _t.cast(_t.Any,
|
31
|
+
_UNSET = _t.cast(_t.Any, object())
|
32
32
|
_TTrustable = _t.TypeVar('_TTrustable', bound=str | _io.IOBase | _t.TextIO | _t.BinaryIO)
|
33
33
|
_TRUSTABLE_TYPES = (str, _io.IOBase)
|
34
34
|
|
@@ -171,7 +171,8 @@ class Templar:
|
|
171
171
|
variables=self._engine._variables if available_variables is None else available_variables,
|
172
172
|
)
|
173
173
|
|
174
|
-
|
174
|
+
# backward compatibility: filter out None values from overrides, even though it is a valid value for some of them
|
175
|
+
templar._overrides = self._overrides.merge({key: value for key, value in context_overrides.items() if value is not None})
|
175
176
|
|
176
177
|
if searchpath is not None:
|
177
178
|
templar._engine.environment.loader.searchpath = searchpath
|
@@ -198,7 +199,7 @@ class Templar:
|
|
198
199
|
available_variables=self._engine,
|
199
200
|
)
|
200
201
|
|
201
|
-
|
202
|
+
target_args = dict(
|
202
203
|
searchpath=searchpath,
|
203
204
|
available_variables=available_variables,
|
204
205
|
)
|
@@ -207,13 +208,14 @@ class Templar:
|
|
207
208
|
previous_overrides = self._overrides
|
208
209
|
|
209
210
|
try:
|
210
|
-
for key, value in
|
211
|
+
for key, value in target_args.items():
|
211
212
|
if value is not None:
|
212
213
|
target = targets[key]
|
213
214
|
original[key] = getattr(target, key)
|
214
215
|
setattr(target, key, value)
|
215
216
|
|
216
|
-
|
217
|
+
# backward compatibility: filter out None values from overrides, even though it is a valid value for some of them
|
218
|
+
self._overrides = self._overrides.merge({key: value for key, value in context_overrides.items() if value is not None})
|
217
219
|
|
218
220
|
yield
|
219
221
|
finally:
|
@@ -386,7 +388,7 @@ def generate_ansible_template_vars(path: str, fullpath: str | None = None, dest_
|
|
386
388
|
value=ansible_managed,
|
387
389
|
msg="The `ansible_managed` variable is deprecated.",
|
388
390
|
help_text="Define and use a custom variable instead.",
|
389
|
-
|
391
|
+
version='2.23',
|
390
392
|
)
|
391
393
|
|
392
394
|
temp_vars = dict(
|
@@ -24,11 +24,13 @@ def _meta_yml_to_dict(yaml_string_data: bytes | str, content_id):
|
|
24
24
|
import yaml
|
25
25
|
|
26
26
|
try:
|
27
|
-
from yaml import
|
27
|
+
from yaml import CBaseLoader as BaseLoader
|
28
28
|
except (ImportError, AttributeError):
|
29
|
-
from yaml import
|
29
|
+
from yaml import BaseLoader # type: ignore[assignment]
|
30
30
|
|
31
|
-
|
31
|
+
# Using BaseLoader ensures that all scalars are strings.
|
32
|
+
# Doing so avoids parsing unquoted versions as floats, dates as datetime.date, etc.
|
33
|
+
routing_dict = yaml.load(yaml_string_data, Loader=BaseLoader)
|
32
34
|
if not routing_dict:
|
33
35
|
routing_dict = {}
|
34
36
|
if not isinstance(routing_dict, Mapping):
|