ansible-core 2.19.0b5__py3-none-any.whl → 2.19.0b7__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/__init__.py +0 -0
- ansible/_internal/_ansiballz/_builder.py +101 -0
- ansible/_internal/{_ansiballz.py → _ansiballz/_wrapper.py} +11 -11
- ansible/_internal/_templating/_jinja_bits.py +22 -4
- ansible/_internal/_templating/_jinja_common.py +1 -1
- ansible/_internal/_templating/_jinja_plugins.py +5 -2
- ansible/_internal/_templating/_template_vars.py +72 -0
- ansible/_internal/_templating/_transform.py +6 -0
- ansible/_internal/_yaml/_constructor.py +4 -4
- ansible/_internal/_yaml/_dumper.py +26 -18
- ansible/cli/__init__.py +9 -14
- ansible/cli/adhoc.py +6 -3
- ansible/cli/arguments/option_helpers.py +1 -1
- ansible/cli/console.py +2 -2
- ansible/cli/doc.py +4 -4
- ansible/cli/inventory.py +5 -7
- ansible/config/base.yml +33 -6
- ansible/errors/__init__.py +2 -1
- ansible/executor/module_common.py +75 -44
- ansible/executor/powershell/psrp_put_file.ps1 +1 -1
- ansible/executor/process/worker.py +2 -2
- ansible/executor/task_executor.py +2 -2
- ansible/executor/task_queue_manager.py +34 -70
- ansible/executor/task_result.py +1 -1
- ansible/galaxy/api.py +3 -6
- ansible/galaxy/collection/__init__.py +1 -6
- ansible/galaxy/collection/concrete_artifact_manager.py +4 -10
- ansible/galaxy/dependency_resolution/providers.py +3 -3
- ansible/galaxy/role.py +2 -2
- ansible/inventory/group.py +6 -1
- ansible/inventory/host.py +6 -1
- ansible/module_utils/_internal/__init__.py +7 -4
- ansible/module_utils/_internal/_ansiballz/__init__.py +0 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/__init__.py +0 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/_coverage.py +45 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/_pydevd.py +62 -0
- ansible/module_utils/_internal/{_ansiballz.py → _ansiballz/_loader.py} +10 -38
- ansible/module_utils/_internal/_ansiballz/_respawn.py +32 -0
- ansible/module_utils/_internal/_ansiballz/_respawn_wrapper.py +23 -0
- ansible/module_utils/_internal/_datatag/__init__.py +23 -1
- ansible/module_utils/_internal/_deprecator.py +39 -34
- ansible/module_utils/_internal/_json/_profiles/__init__.py +1 -0
- ansible/module_utils/_internal/_messages.py +26 -2
- ansible/module_utils/_internal/_plugin_info.py +14 -1
- ansible/module_utils/ansible_release.py +1 -1
- ansible/module_utils/basic.py +58 -70
- ansible/module_utils/common/respawn.py +4 -41
- ansible/module_utils/common/yaml.py +1 -1
- ansible/module_utils/connection.py +8 -11
- ansible/module_utils/csharp/Ansible.Basic.cs +1 -1
- ansible/module_utils/csharp/Ansible.Privilege.cs +2 -2
- ansible/module_utils/facts/hardware/base.py +1 -1
- ansible/module_utils/facts/hardware/linux.py +1 -1
- ansible/module_utils/facts/other/facter.py +1 -1
- ansible/module_utils/facts/sysctl.py +4 -6
- ansible/module_utils/facts/system/caps.py +2 -2
- ansible/module_utils/facts/system/distribution.py +2 -2
- ansible/module_utils/facts/system/local.py +1 -1
- ansible/module_utils/facts/virtual/linux.py +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.CommandUtil.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.WebRequest.psm1 +1 -1
- ansible/module_utils/service.py +1 -1
- ansible/module_utils/urls.py +5 -5
- ansible/modules/apt.py +9 -3
- ansible/modules/apt_repository.py +10 -10
- ansible/modules/assemble.py +7 -5
- ansible/modules/async_wrapper.py +7 -17
- ansible/modules/command.py +3 -3
- ansible/modules/copy.py +4 -4
- ansible/modules/cron.py +1 -1
- ansible/modules/expect.py +5 -5
- ansible/modules/file.py +16 -17
- ansible/modules/find.py +3 -3
- ansible/modules/get_url.py +17 -0
- ansible/modules/git.py +9 -7
- ansible/modules/hostname.py +2 -2
- ansible/modules/known_hosts.py +12 -14
- ansible/modules/package.py +6 -0
- ansible/modules/pip.py +9 -11
- ansible/modules/raw.py +2 -2
- ansible/modules/replace.py +2 -2
- ansible/modules/slurp.py +10 -13
- ansible/modules/stat.py +6 -8
- ansible/modules/unarchive.py +6 -6
- ansible/modules/user.py +1 -1
- ansible/modules/wait_for.py +38 -33
- ansible/modules/yum_repository.py +4 -3
- ansible/parsing/dataloader.py +2 -2
- ansible/parsing/mod_args.py +38 -20
- ansible/parsing/vault/__init__.py +9 -13
- ansible/playbook/base.py +7 -4
- ansible/playbook/helpers.py +1 -1
- ansible/playbook/included_file.py +3 -1
- ansible/playbook/play_context.py +2 -0
- ansible/playbook/playbook_include.py +23 -56
- ansible/playbook/role/__init__.py +38 -21
- ansible/playbook/taggable.py +19 -5
- ansible/playbook/task.py +2 -0
- ansible/plugins/action/__init__.py +2 -2
- ansible/plugins/action/assemble.py +2 -1
- ansible/plugins/action/assert.py +2 -2
- ansible/plugins/action/fetch.py +3 -3
- ansible/plugins/action/script.py +5 -4
- ansible/plugins/action/template.py +9 -3
- ansible/plugins/cache/__init__.py +17 -19
- ansible/plugins/callback/__init__.py +77 -87
- ansible/plugins/callback/default.py +0 -3
- ansible/plugins/callback/junit.py +0 -6
- ansible/plugins/callback/tree.py +5 -5
- ansible/plugins/connection/local.py +4 -4
- ansible/plugins/connection/paramiko_ssh.py +5 -5
- ansible/plugins/connection/ssh.py +9 -7
- ansible/plugins/connection/winrm.py +1 -1
- ansible/plugins/filter/core.py +19 -21
- ansible/plugins/filter/encryption.py +10 -2
- ansible/plugins/filter/pow.yml +1 -1
- ansible/plugins/filter/root.yml +1 -1
- ansible/plugins/filter/strftime.yml +3 -3
- ansible/plugins/filter/to_uuid.yml +1 -1
- ansible/plugins/inventory/script.py +1 -1
- ansible/plugins/list.py +5 -4
- ansible/plugins/loader.py +5 -0
- ansible/plugins/lookup/password.py +4 -6
- ansible/plugins/lookup/template.py +9 -4
- ansible/plugins/shell/powershell.py +3 -2
- ansible/plugins/shell/sh.py +3 -2
- ansible/plugins/strategy/__init__.py +3 -3
- ansible/plugins/test/core.py +2 -2
- ansible/release.py +1 -1
- ansible/template/__init__.py +9 -53
- ansible/utils/collection_loader/_collection_finder.py +3 -3
- ansible/utils/display.py +38 -37
- ansible/utils/galaxy.py +2 -2
- ansible/utils/hashing.py +6 -7
- ansible/utils/path.py +6 -8
- ansible/utils/py3compat.py +2 -1
- ansible/utils/ssh_functions.py +3 -2
- ansible/utils/vars.py +4 -1
- ansible/vars/manager.py +6 -3
- ansible/vars/plugins.py +3 -3
- ansible/vars/reserved.py +6 -4
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/METADATA +1 -1
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/RECORD +184 -173
- ansible_test/_internal/__init__.py +5 -0
- ansible_test/_internal/ansible_util.py +1 -1
- ansible_test/_internal/classification/python.py +6 -0
- ansible_test/_internal/cli/commands/__init__.py +0 -5
- ansible_test/_internal/cli/environments.py +51 -5
- ansible_test/_internal/commands/coverage/__init__.py +1 -1
- ansible_test/_internal/commands/integration/__init__.py +18 -5
- ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
- ansible_test/_internal/commands/integration/coverage.py +7 -2
- ansible_test/_internal/commands/sanity/__init__.py +3 -1
- ansible_test/_internal/commands/sanity/integration_aliases.py +11 -0
- ansible_test/_internal/commands/shell/__init__.py +43 -4
- ansible_test/_internal/commands/units/__init__.py +4 -1
- ansible_test/_internal/config.py +21 -13
- ansible_test/_internal/debugging.py +166 -0
- ansible_test/_internal/delegation.py +21 -13
- ansible_test/_internal/host_profiles.py +259 -16
- ansible_test/_internal/inventory.py +4 -0
- ansible_test/_internal/metadata.py +94 -4
- ansible_test/_internal/processes.py +80 -0
- ansible_test/_internal/provisioning.py +10 -4
- ansible_test/_internal/python_requirements.py +27 -0
- ansible_test/_internal/ssh.py +1 -5
- ansible_test/_internal/target.py +8 -0
- ansible_test/_internal/thread.py +2 -1
- ansible_test/_internal/timeout.py +1 -1
- ansible_test/_internal/util.py +20 -12
- ansible_test/_internal/util_common.py +13 -3
- ansible_test/_util/target/injector/python.py +8 -0
- ansible_test/_util/target/setup/requirements.py +3 -9
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/WHEEL +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/top_level.txt +0 -0
@@ -19,6 +19,7 @@ from __future__ import annotations
|
|
19
19
|
|
20
20
|
import difflib
|
21
21
|
import functools
|
22
|
+
import inspect
|
22
23
|
import json
|
23
24
|
import re
|
24
25
|
import sys
|
@@ -39,6 +40,7 @@ from ansible.utils.display import Display
|
|
39
40
|
from ansible.vars.clean import strip_internal_keys, module_response_deepcopy
|
40
41
|
from ansible.module_utils._internal._json._profiles import _fallback_to_str
|
41
42
|
from ansible._internal._templating import _engine
|
43
|
+
from ansible.module_utils._internal import _deprecator
|
42
44
|
|
43
45
|
import yaml
|
44
46
|
|
@@ -61,16 +63,6 @@ _SPACE_BREAK_RE = re.compile(fr' +([{_YAML_BREAK_CHARS}])')
|
|
61
63
|
_T_callable = t.TypeVar("_T_callable", bound=t.Callable)
|
62
64
|
|
63
65
|
|
64
|
-
def _callback_base_impl(wrapped: _T_callable) -> _T_callable:
|
65
|
-
"""
|
66
|
-
Decorator for the no-op methods on the `CallbackBase` base class.
|
67
|
-
Used to avoid unnecessary dispatch overhead to no-op base callback methods.
|
68
|
-
"""
|
69
|
-
wrapped._base_impl = True
|
70
|
-
|
71
|
-
return wrapped
|
72
|
-
|
73
|
-
|
74
66
|
class _AnsibleCallbackDumper(_dumper.AnsibleDumper):
|
75
67
|
def __init__(self, *args, lossy: bool = False, **kwargs):
|
76
68
|
super().__init__(*args, **kwargs)
|
@@ -154,6 +146,9 @@ class CallbackBase(AnsiblePlugin):
|
|
154
146
|
custom actions.
|
155
147
|
"""
|
156
148
|
|
149
|
+
_implemented_callback_methods: frozenset[str] = frozenset()
|
150
|
+
"""Set of callback methods overridden by each subclass; used by TQM to bypass callback dispatch on no-op methods."""
|
151
|
+
|
157
152
|
def __init__(self, display: Display | None = None, options: dict[str, t.Any] | None = None) -> None:
|
158
153
|
super().__init__()
|
159
154
|
|
@@ -189,6 +184,48 @@ class CallbackBase(AnsiblePlugin):
|
|
189
184
|
# helper for callbacks, so they don't all have to include deepcopy
|
190
185
|
_copy_result = deepcopy
|
191
186
|
|
187
|
+
def _init_callback_methods(self) -> None:
|
188
|
+
"""Record analysis of callback methods on each callback instance for dispatch optimization and deprecation warnings."""
|
189
|
+
implemented_callback_methods: set[str] = set()
|
190
|
+
deprecated_v1_method_overrides: set[str] = set()
|
191
|
+
plugin_file = sys.modules[type(self).__module__].__file__
|
192
|
+
|
193
|
+
if plugin_info := _deprecator._path_as_plugininfo(plugin_file):
|
194
|
+
plugin_name = plugin_info.resolved_name
|
195
|
+
else:
|
196
|
+
plugin_name = plugin_file
|
197
|
+
|
198
|
+
for base_v2_method, base_v1_method in CallbackBase._v2_v1_method_map.items():
|
199
|
+
method_name = None
|
200
|
+
|
201
|
+
if not inspect.ismethod(method := getattr(self, (v2_method_name := base_v2_method.__name__))) or method.__func__ is not base_v2_method:
|
202
|
+
implemented_callback_methods.add(v2_method_name) # v2 method directly implemented by subclass
|
203
|
+
method_name = v2_method_name
|
204
|
+
elif base_v1_method is None:
|
205
|
+
pass # no corresponding v1 method
|
206
|
+
elif not inspect.ismethod(method := getattr(self, (v1_method_name := base_v1_method.__name__))) or method.__func__ is not base_v1_method:
|
207
|
+
implemented_callback_methods.add(v2_method_name) # v1 method directly implemented by subclass
|
208
|
+
deprecated_v1_method_overrides.add(v1_method_name)
|
209
|
+
method_name = v1_method_name
|
210
|
+
|
211
|
+
if method_name and v2_method_name == 'v2_on_any':
|
212
|
+
deprecated_v1_method_overrides.discard(method_name) # avoid including v1 on_any in the v1 deprecation below
|
213
|
+
|
214
|
+
global_display.deprecated(
|
215
|
+
msg=f'The {plugin_name!r} callback plugin implements deprecated method {method_name!r}.',
|
216
|
+
version='2.23',
|
217
|
+
help_text='Use event-specific callback methods instead.',
|
218
|
+
)
|
219
|
+
|
220
|
+
self._implemented_callback_methods = frozenset(implemented_callback_methods)
|
221
|
+
|
222
|
+
if deprecated_v1_method_overrides:
|
223
|
+
global_display.deprecated(
|
224
|
+
msg=f'The {plugin_name!r} callback plugin implements the following deprecated method(s): {", ".join(sorted(deprecated_v1_method_overrides))}',
|
225
|
+
version='2.23',
|
226
|
+
help_text='Implement the `v2_*` equivalent callback method(s) instead.',
|
227
|
+
)
|
228
|
+
|
192
229
|
def set_option(self, k, v):
|
193
230
|
self._plugin_options[k] = C.config.get_config_value(k, plugin_type=self.plugin_type, plugin_name=self._load_name, direct={k: v})
|
194
231
|
|
@@ -316,8 +353,7 @@ class CallbackBase(AnsiblePlugin):
|
|
316
353
|
if res.pop('warnings', None) and self._current_task_result and (warnings := self._current_task_result.warnings):
|
317
354
|
# display warnings from the current task result if `warnings` was not removed from `result` (or made falsey)
|
318
355
|
for warning in warnings:
|
319
|
-
|
320
|
-
self._display._warning(warning, wrap_text=False)
|
356
|
+
self._display._warning(warning)
|
321
357
|
|
322
358
|
if res.pop('deprecations', None) and self._current_task_result and (deprecations := self._current_task_result.deprecations):
|
323
359
|
# display deprecations from the current task result if `deprecations` was not removed from `result` (or made falsey)
|
@@ -327,7 +363,7 @@ class CallbackBase(AnsiblePlugin):
|
|
327
363
|
def _handle_exception(self, result: _c.MutableMapping[str, t.Any], use_stderr: bool = False) -> None:
|
328
364
|
if result.pop('exception', None) and self._current_task_result and (exception := self._current_task_result.exception):
|
329
365
|
# display exception from the current task result if `exception` was not removed from `result` (or made falsey)
|
330
|
-
self._display._error(exception,
|
366
|
+
self._display._error(exception, stderr=use_stderr)
|
331
367
|
|
332
368
|
def _handle_warnings_and_exception(self, result: CallbackTaskResult) -> None:
|
333
369
|
"""Standardized handling of warnings/deprecations and exceptions from a task/item result."""
|
@@ -471,96 +507,61 @@ class CallbackBase(AnsiblePlugin):
|
|
471
507
|
def set_play_context(self, play_context):
|
472
508
|
pass
|
473
509
|
|
474
|
-
@_callback_base_impl
|
475
510
|
def on_any(self, *args, **kwargs):
|
476
511
|
pass
|
477
512
|
|
478
|
-
@_callback_base_impl
|
479
513
|
def runner_on_failed(self, host, res, ignore_errors=False):
|
480
514
|
pass
|
481
515
|
|
482
|
-
@_callback_base_impl
|
483
516
|
def runner_on_ok(self, host, res):
|
484
517
|
pass
|
485
518
|
|
486
|
-
@_callback_base_impl
|
487
519
|
def runner_on_skipped(self, host, item=None):
|
488
520
|
pass
|
489
521
|
|
490
|
-
@_callback_base_impl
|
491
522
|
def runner_on_unreachable(self, host, res):
|
492
523
|
pass
|
493
524
|
|
494
|
-
@_callback_base_impl
|
495
|
-
def runner_on_no_hosts(self):
|
496
|
-
pass
|
497
|
-
|
498
|
-
@_callback_base_impl
|
499
525
|
def runner_on_async_poll(self, host, res, jid, clock):
|
500
526
|
pass
|
501
527
|
|
502
|
-
@_callback_base_impl
|
503
528
|
def runner_on_async_ok(self, host, res, jid):
|
504
529
|
pass
|
505
530
|
|
506
|
-
@_callback_base_impl
|
507
531
|
def runner_on_async_failed(self, host, res, jid):
|
508
532
|
pass
|
509
533
|
|
510
|
-
@_callback_base_impl
|
511
534
|
def playbook_on_start(self):
|
512
535
|
pass
|
513
536
|
|
514
|
-
@_callback_base_impl
|
515
537
|
def playbook_on_notify(self, host, handler):
|
516
538
|
pass
|
517
539
|
|
518
|
-
@_callback_base_impl
|
519
540
|
def playbook_on_no_hosts_matched(self):
|
520
541
|
pass
|
521
542
|
|
522
|
-
@_callback_base_impl
|
523
543
|
def playbook_on_no_hosts_remaining(self):
|
524
544
|
pass
|
525
545
|
|
526
|
-
@_callback_base_impl
|
527
546
|
def playbook_on_task_start(self, name, is_conditional):
|
528
547
|
pass
|
529
548
|
|
530
|
-
@_callback_base_impl
|
531
549
|
def playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None, unsafe=None):
|
532
550
|
pass
|
533
551
|
|
534
|
-
@_callback_base_impl
|
535
|
-
def playbook_on_setup(self):
|
536
|
-
pass
|
537
|
-
|
538
|
-
@_callback_base_impl
|
539
|
-
def playbook_on_import_for_host(self, host, imported_file):
|
540
|
-
pass
|
541
|
-
|
542
|
-
@_callback_base_impl
|
543
|
-
def playbook_on_not_import_for_host(self, host, missing_file):
|
544
|
-
pass
|
545
|
-
|
546
|
-
@_callback_base_impl
|
547
552
|
def playbook_on_play_start(self, name):
|
548
553
|
pass
|
549
554
|
|
550
|
-
@_callback_base_impl
|
551
555
|
def playbook_on_stats(self, stats):
|
552
556
|
pass
|
553
557
|
|
554
|
-
@_callback_base_impl
|
555
558
|
def on_file_diff(self, host, diff):
|
556
559
|
pass
|
557
560
|
|
558
561
|
# V2 METHODS, by default they call v1 counterparts if possible
|
559
|
-
@_callback_base_impl
|
560
562
|
def v2_on_any(self, *args, **kwargs):
|
561
563
|
self.on_any(args, kwargs)
|
562
564
|
|
563
|
-
@_callback_base_impl
|
564
565
|
def v2_runner_on_failed(self, result: CallbackTaskResult, ignore_errors: bool = False) -> None:
|
565
566
|
"""Process results of a failed task.
|
566
567
|
|
@@ -583,7 +584,6 @@ class CallbackBase(AnsiblePlugin):
|
|
583
584
|
host = result.host.get_name()
|
584
585
|
self.runner_on_failed(host, result.result, ignore_errors)
|
585
586
|
|
586
|
-
@_callback_base_impl
|
587
587
|
def v2_runner_on_ok(self, result: CallbackTaskResult) -> None:
|
588
588
|
"""Process results of a successful task.
|
589
589
|
|
@@ -596,7 +596,6 @@ class CallbackBase(AnsiblePlugin):
|
|
596
596
|
host = result.host.get_name()
|
597
597
|
self.runner_on_ok(host, result.result)
|
598
598
|
|
599
|
-
@_callback_base_impl
|
600
599
|
def v2_runner_on_skipped(self, result: CallbackTaskResult) -> None:
|
601
600
|
"""Process results of a skipped task.
|
602
601
|
|
@@ -610,7 +609,6 @@ class CallbackBase(AnsiblePlugin):
|
|
610
609
|
host = result.host.get_name()
|
611
610
|
self.runner_on_skipped(host, self._get_item_label(getattr(result.result, 'results', {})))
|
612
611
|
|
613
|
-
@_callback_base_impl
|
614
612
|
def v2_runner_on_unreachable(self, result: CallbackTaskResult) -> None:
|
615
613
|
"""Process results of a task if a target node is unreachable.
|
616
614
|
|
@@ -623,7 +621,6 @@ class CallbackBase(AnsiblePlugin):
|
|
623
621
|
host = result.host.get_name()
|
624
622
|
self.runner_on_unreachable(host, result.result)
|
625
623
|
|
626
|
-
@_callback_base_impl
|
627
624
|
def v2_runner_on_async_poll(self, result: CallbackTaskResult) -> None:
|
628
625
|
"""Get details about an unfinished task running in async mode.
|
629
626
|
|
@@ -642,7 +639,6 @@ class CallbackBase(AnsiblePlugin):
|
|
642
639
|
clock = 0
|
643
640
|
self.runner_on_async_poll(host, result.result, jid, clock)
|
644
641
|
|
645
|
-
@_callback_base_impl
|
646
642
|
def v2_runner_on_async_ok(self, result: CallbackTaskResult) -> None:
|
647
643
|
"""Process results of a successful task that ran in async mode.
|
648
644
|
|
@@ -656,7 +652,6 @@ class CallbackBase(AnsiblePlugin):
|
|
656
652
|
jid = result.result.get('ansible_job_id')
|
657
653
|
self.runner_on_async_ok(host, result.result, jid)
|
658
654
|
|
659
|
-
@_callback_base_impl
|
660
655
|
def v2_runner_on_async_failed(self, result: CallbackTaskResult) -> None:
|
661
656
|
host = result.host.get_name()
|
662
657
|
# Attempt to get the async job ID. If the job does not finish before the
|
@@ -666,89 +661,84 @@ class CallbackBase(AnsiblePlugin):
|
|
666
661
|
jid = result.result['async_result'].get('ansible_job_id')
|
667
662
|
self.runner_on_async_failed(host, result.result, jid)
|
668
663
|
|
669
|
-
@_callback_base_impl
|
670
664
|
def v2_playbook_on_start(self, playbook):
|
671
665
|
self.playbook_on_start()
|
672
666
|
|
673
|
-
@_callback_base_impl
|
674
667
|
def v2_playbook_on_notify(self, handler, host):
|
675
668
|
self.playbook_on_notify(host, handler)
|
676
669
|
|
677
|
-
@_callback_base_impl
|
678
670
|
def v2_playbook_on_no_hosts_matched(self):
|
679
671
|
self.playbook_on_no_hosts_matched()
|
680
672
|
|
681
|
-
@_callback_base_impl
|
682
673
|
def v2_playbook_on_no_hosts_remaining(self):
|
683
674
|
self.playbook_on_no_hosts_remaining()
|
684
675
|
|
685
|
-
@_callback_base_impl
|
686
676
|
def v2_playbook_on_task_start(self, task, is_conditional):
|
687
677
|
self.playbook_on_task_start(task.name, is_conditional)
|
688
678
|
|
689
|
-
# FIXME: not called
|
690
|
-
@_callback_base_impl
|
691
|
-
def v2_playbook_on_cleanup_task_start(self, task):
|
692
|
-
pass # no v1 correspondence
|
693
|
-
|
694
|
-
@_callback_base_impl
|
695
679
|
def v2_playbook_on_handler_task_start(self, task):
|
696
680
|
pass # no v1 correspondence
|
697
681
|
|
698
|
-
@_callback_base_impl
|
699
682
|
def v2_playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None, unsafe=None):
|
700
683
|
self.playbook_on_vars_prompt(varname, private, prompt, encrypt, confirm, salt_size, salt, default, unsafe)
|
701
684
|
|
702
|
-
# FIXME: not called
|
703
|
-
@_callback_base_impl
|
704
|
-
def v2_playbook_on_import_for_host(self, result: CallbackTaskResult, imported_file) -> None:
|
705
|
-
host = result.host.get_name()
|
706
|
-
self.playbook_on_import_for_host(host, imported_file)
|
707
|
-
|
708
|
-
# FIXME: not called
|
709
|
-
@_callback_base_impl
|
710
|
-
def v2_playbook_on_not_import_for_host(self, result: CallbackTaskResult, missing_file) -> None:
|
711
|
-
host = result.host.get_name()
|
712
|
-
self.playbook_on_not_import_for_host(host, missing_file)
|
713
|
-
|
714
|
-
@_callback_base_impl
|
715
685
|
def v2_playbook_on_play_start(self, play):
|
716
686
|
self.playbook_on_play_start(play.name)
|
717
687
|
|
718
|
-
@_callback_base_impl
|
719
688
|
def v2_playbook_on_stats(self, stats):
|
720
689
|
self.playbook_on_stats(stats)
|
721
690
|
|
722
|
-
@_callback_base_impl
|
723
691
|
def v2_on_file_diff(self, result: CallbackTaskResult) -> None:
|
724
692
|
if 'diff' in result.result:
|
725
693
|
host = result.host.get_name()
|
726
694
|
self.on_file_diff(host, result.result['diff'])
|
727
695
|
|
728
|
-
@_callback_base_impl
|
729
696
|
def v2_playbook_on_include(self, included_file):
|
730
697
|
pass # no v1 correspondence
|
731
698
|
|
732
|
-
@_callback_base_impl
|
733
699
|
def v2_runner_item_on_ok(self, result: CallbackTaskResult) -> None:
|
734
700
|
pass
|
735
701
|
|
736
|
-
@_callback_base_impl
|
737
702
|
def v2_runner_item_on_failed(self, result: CallbackTaskResult) -> None:
|
738
703
|
pass
|
739
704
|
|
740
|
-
@_callback_base_impl
|
741
705
|
def v2_runner_item_on_skipped(self, result: CallbackTaskResult) -> None:
|
742
706
|
pass
|
743
707
|
|
744
|
-
@_callback_base_impl
|
745
708
|
def v2_runner_retry(self, result: CallbackTaskResult) -> None:
|
746
709
|
pass
|
747
710
|
|
748
|
-
@_callback_base_impl
|
749
711
|
def v2_runner_on_start(self, host, task):
|
750
712
|
"""Event used when host begins execution of a task
|
751
713
|
|
752
714
|
.. versionadded:: 2.8
|
753
715
|
"""
|
754
716
|
pass
|
717
|
+
|
718
|
+
_v2_v1_method_map = {
|
719
|
+
v2_on_any: on_any,
|
720
|
+
v2_on_file_diff: on_file_diff,
|
721
|
+
v2_playbook_on_handler_task_start: None,
|
722
|
+
v2_playbook_on_include: None,
|
723
|
+
v2_playbook_on_no_hosts_matched: playbook_on_no_hosts_matched,
|
724
|
+
v2_playbook_on_no_hosts_remaining: playbook_on_no_hosts_remaining,
|
725
|
+
v2_playbook_on_notify: playbook_on_notify,
|
726
|
+
v2_playbook_on_play_start: playbook_on_play_start,
|
727
|
+
v2_playbook_on_start: playbook_on_start,
|
728
|
+
v2_playbook_on_stats: playbook_on_stats,
|
729
|
+
v2_playbook_on_task_start: playbook_on_task_start,
|
730
|
+
v2_playbook_on_vars_prompt: playbook_on_vars_prompt,
|
731
|
+
v2_runner_item_on_failed: None,
|
732
|
+
v2_runner_item_on_ok: None,
|
733
|
+
v2_runner_item_on_skipped: None,
|
734
|
+
v2_runner_on_async_failed: runner_on_async_failed,
|
735
|
+
v2_runner_on_async_ok: runner_on_async_ok,
|
736
|
+
v2_runner_on_async_poll: runner_on_async_poll,
|
737
|
+
v2_runner_on_failed: runner_on_failed,
|
738
|
+
v2_runner_on_ok: runner_on_ok,
|
739
|
+
v2_runner_on_skipped: runner_on_skipped,
|
740
|
+
v2_runner_on_start: None,
|
741
|
+
v2_runner_on_unreachable: runner_on_unreachable,
|
742
|
+
v2_runner_retry: None,
|
743
|
+
}
|
744
|
+
"""Internal mapping of v2 callback methods with v1 counterparts; populated after type init for deprecation warnings and bypass calculation."""
|
@@ -197,9 +197,6 @@ class CallbackModule(CallbackBase):
|
|
197
197
|
|
198
198
|
self._last_task_banner = task._uuid
|
199
199
|
|
200
|
-
def v2_playbook_on_cleanup_task_start(self, task):
|
201
|
-
self._task_start(task, prefix='CLEANUP TASK')
|
202
|
-
|
203
200
|
def v2_playbook_on_handler_task_start(self, task):
|
204
201
|
self._task_start(task, prefix='RUNNING HANDLER')
|
205
202
|
|
@@ -300,15 +300,9 @@ class CallbackModule(CallbackBase):
|
|
300
300
|
def v2_playbook_on_play_start(self, play):
|
301
301
|
self._play_name = play.get_name()
|
302
302
|
|
303
|
-
def v2_runner_on_no_hosts(self, task: Task) -> None:
|
304
|
-
self._start_task(task)
|
305
|
-
|
306
303
|
def v2_playbook_on_task_start(self, task: Task, is_conditional: bool) -> None:
|
307
304
|
self._start_task(task)
|
308
305
|
|
309
|
-
def v2_playbook_on_cleanup_task_start(self, task: Task) -> None:
|
310
|
-
self._start_task(task)
|
311
|
-
|
312
306
|
def v2_playbook_on_handler_task_start(self, task: Task) -> None:
|
313
307
|
self._start_task(task)
|
314
308
|
|
ansible/plugins/callback/tree.py
CHANGED
@@ -31,7 +31,7 @@ import os
|
|
31
31
|
|
32
32
|
from ansible.constants import TREE_DIR
|
33
33
|
from ansible.executor.task_result import CallbackTaskResult
|
34
|
-
from ansible.module_utils.common.text.converters import to_bytes
|
34
|
+
from ansible.module_utils.common.text.converters import to_bytes
|
35
35
|
from ansible.plugins.callback import CallbackBase
|
36
36
|
from ansible.utils.path import makedirs_safe, unfrackpath
|
37
37
|
from ansible.module_utils._internal import _deprecator
|
@@ -73,15 +73,15 @@ class CallbackModule(CallbackBase):
|
|
73
73
|
buf = to_bytes(buf)
|
74
74
|
try:
|
75
75
|
makedirs_safe(self.tree)
|
76
|
-
except
|
77
|
-
self._display.
|
76
|
+
except OSError as ex:
|
77
|
+
self._display.error_as_warning(f"Unable to access or create the configured directory {self.tree!r}.", exception=ex)
|
78
78
|
|
79
79
|
try:
|
80
80
|
path = to_bytes(os.path.join(self.tree, hostname))
|
81
81
|
with open(path, 'wb+') as fd:
|
82
82
|
fd.write(buf)
|
83
|
-
except
|
84
|
-
self._display.
|
83
|
+
except OSError as ex:
|
84
|
+
self._display.error_as_warning(f"Unable to write to {hostname!r}'s file.", exception=ex)
|
85
85
|
|
86
86
|
def result_to_tree(self, result: CallbackTaskResult) -> None:
|
87
87
|
self.write_tree_file(result.host.get_name(), self._dump_results(result.result))
|
@@ -114,8 +114,8 @@ class Connection(ConnectionBase):
|
|
114
114
|
# privileges or the command otherwise needs a pty.
|
115
115
|
try:
|
116
116
|
pty_primary, stdin = pty.openpty()
|
117
|
-
except
|
118
|
-
display.debug("Unable to open pty:
|
117
|
+
except OSError as ex:
|
118
|
+
display.debug(f"Unable to open pty: {ex}")
|
119
119
|
|
120
120
|
p = subprocess.Popen(
|
121
121
|
cmd,
|
@@ -271,8 +271,8 @@ class Connection(ConnectionBase):
|
|
271
271
|
shutil.copyfile(to_bytes(in_path, errors='surrogate_or_strict'), to_bytes(out_path, errors='surrogate_or_strict'))
|
272
272
|
except shutil.Error:
|
273
273
|
raise AnsibleError("failed to copy: {0} and {1} are the same".format(to_native(in_path), to_native(out_path)))
|
274
|
-
except
|
275
|
-
raise AnsibleError("
|
274
|
+
except OSError as ex:
|
275
|
+
raise AnsibleError(f"Failed to transfer file to {out_path!r}.") from ex
|
276
276
|
|
277
277
|
def fetch_file(self, in_path: str, out_path: str) -> None:
|
278
278
|
""" fetch a file from local to local -- for compatibility """
|
@@ -413,7 +413,7 @@ class Connection(ConnectionBase):
|
|
413
413
|
# TODO: check if we need to look at several possible locations, possible for loop
|
414
414
|
ssh.load_system_host_keys(ssh_known_hosts)
|
415
415
|
break
|
416
|
-
except
|
416
|
+
except OSError:
|
417
417
|
pass # file was not found, but not required to function
|
418
418
|
ssh.load_system_host_keys()
|
419
419
|
|
@@ -567,8 +567,8 @@ class Connection(ConnectionBase):
|
|
567
567
|
|
568
568
|
try:
|
569
569
|
self.sftp.put(to_bytes(in_path, errors='surrogate_or_strict'), to_bytes(out_path, errors='surrogate_or_strict'))
|
570
|
-
except
|
571
|
-
raise AnsibleError("
|
570
|
+
except OSError as ex:
|
571
|
+
raise AnsibleError(f"Failed to transfer file to {out_path!r}.") from ex
|
572
572
|
|
573
573
|
def _connect_sftp(self) -> paramiko.sftp_client.SFTPClient:
|
574
574
|
|
@@ -593,8 +593,8 @@ class Connection(ConnectionBase):
|
|
593
593
|
|
594
594
|
try:
|
595
595
|
self.sftp.get(to_bytes(in_path, errors='surrogate_or_strict'), to_bytes(out_path, errors='surrogate_or_strict'))
|
596
|
-
except
|
597
|
-
raise AnsibleError("
|
596
|
+
except OSError as ex:
|
597
|
+
raise AnsibleError(f"Failed to transfer file from {in_path!r}.") from ex
|
598
598
|
|
599
599
|
def _any_keys_added(self) -> bool:
|
600
600
|
|
@@ -332,7 +332,9 @@ DOCUMENTATION = """
|
|
332
332
|
version_added: '2.7'
|
333
333
|
sftp_batch_mode:
|
334
334
|
default: true
|
335
|
-
description:
|
335
|
+
description:
|
336
|
+
- When set to C(True), sftp will be run in batch mode, allowing detection of transfer errors.
|
337
|
+
- When set to C(False), sftp will not be run in batch mode, preventing detection of transfer errors.
|
336
338
|
env: [{name: ANSIBLE_SFTP_BATCH_MODE}]
|
337
339
|
ini:
|
338
340
|
- {key: sftp_batch_mode, section: ssh_connection}
|
@@ -977,7 +979,7 @@ class Connection(ConnectionBase):
|
|
977
979
|
try:
|
978
980
|
fh.write(to_bytes(in_data))
|
979
981
|
fh.close()
|
980
|
-
except
|
982
|
+
except OSError as ex:
|
981
983
|
# The ssh connection may have already terminated at this point, with a more useful error
|
982
984
|
# Only raise AnsibleConnectionFailure if the ssh process is still alive
|
983
985
|
time.sleep(0.001)
|
@@ -993,7 +995,7 @@ class Connection(ConnectionBase):
|
|
993
995
|
""" Terminate a process, ignoring errors """
|
994
996
|
try:
|
995
997
|
p.terminate()
|
996
|
-
except
|
998
|
+
except OSError:
|
997
999
|
pass
|
998
1000
|
|
999
1001
|
# This is separate from _run() because we need to do the same thing for stdout
|
@@ -1134,7 +1136,7 @@ class Connection(ConnectionBase):
|
|
1134
1136
|
p = subprocess.Popen(cmd, stdin=slave, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **popen_kwargs)
|
1135
1137
|
stdin = os.fdopen(master, 'wb', 0)
|
1136
1138
|
os.close(slave)
|
1137
|
-
except
|
1139
|
+
except OSError:
|
1138
1140
|
p = None
|
1139
1141
|
|
1140
1142
|
if not p:
|
@@ -1142,8 +1144,8 @@ class Connection(ConnectionBase):
|
|
1142
1144
|
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
1143
1145
|
stderr=subprocess.PIPE, **popen_kwargs)
|
1144
1146
|
stdin = p.stdin # type: ignore[assignment] # stdin will be set and not None due to the calls above
|
1145
|
-
except
|
1146
|
-
raise AnsibleError('Unable to execute ssh command line on a controller
|
1147
|
+
except OSError as ex:
|
1148
|
+
raise AnsibleError('Unable to execute ssh command line on a controller.') from ex
|
1147
1149
|
|
1148
1150
|
if password_mechanism == 'sshpass' and conn_password:
|
1149
1151
|
os.close(self.sshpass_pipe[0])
|
@@ -1169,7 +1171,7 @@ class Connection(ConnectionBase):
|
|
1169
1171
|
|
1170
1172
|
# Are we requesting privilege escalation? Right now, we may be invoked
|
1171
1173
|
# to execute sftp/scp with sudoable=True, but we can request escalation
|
1172
|
-
# only when using ssh. Otherwise we can send initial data
|
1174
|
+
# only when using ssh. Otherwise, we can send initial data straight away.
|
1173
1175
|
|
1174
1176
|
state = states.index('ready_to_send')
|
1175
1177
|
if to_bytes(self.get_option('ssh_executable')) in cmd and sudoable:
|
ansible/plugins/filter/core.py
CHANGED
@@ -32,10 +32,10 @@ from ansible.module_utils.common.json import get_encoder, get_decoder
|
|
32
32
|
from ansible.module_utils.six import string_types, integer_types, text_type
|
33
33
|
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
|
34
34
|
from ansible.module_utils.common.collections import is_sequence
|
35
|
-
from ansible.module_utils.common.yaml import yaml_load, yaml_load_all
|
36
35
|
from ansible.parsing.yaml.dumper import AnsibleDumper
|
37
36
|
from ansible.template import accept_args_markers, accept_lazy_markers
|
38
37
|
from ansible._internal._templating._jinja_common import MarkerError, UndefinedMarker, validate_arg_type
|
38
|
+
from ansible._internal._yaml import _loader as _yaml_loader
|
39
39
|
from ansible.utils.display import Display
|
40
40
|
from ansible.utils.encrypt import do_encrypt, PASSLIB_AVAILABLE
|
41
41
|
from ansible.utils.hashing import md5s, checksum_s
|
@@ -47,13 +47,13 @@ display = Display()
|
|
47
47
|
UUID_NAMESPACE_ANSIBLE = uuid.UUID('361E6D51-FAEC-444A-9079-341386DA8E2E')
|
48
48
|
|
49
49
|
|
50
|
-
|
50
|
+
@accept_lazy_markers
|
51
|
+
def to_yaml(a, *_args, default_flow_style: bool | None = None, **kwargs) -> str:
|
51
52
|
"""Serialize input as terse flow-style YAML."""
|
52
|
-
|
53
|
-
|
54
|
-
return yaml.dump(a, Dumper=dumper, allow_unicode=True, default_flow_style=default_flow_style, **kwargs)
|
53
|
+
return yaml.dump(a, Dumper=AnsibleDumper, allow_unicode=True, default_flow_style=default_flow_style, **kwargs)
|
55
54
|
|
56
55
|
|
56
|
+
@accept_lazy_markers
|
57
57
|
def to_nice_yaml(a, indent=4, *_args, default_flow_style=False, **kwargs) -> str:
|
58
58
|
"""Serialize input as verbose multi-line YAML."""
|
59
59
|
return to_yaml(a, indent=indent, default_flow_style=default_flow_style, **kwargs)
|
@@ -98,6 +98,7 @@ _valid_bool_false = {'no', 'off', 'false', '0'}
|
|
98
98
|
def to_bool(value: object) -> bool:
|
99
99
|
"""Convert well-known input values to a boolean value."""
|
100
100
|
value_to_check: object
|
101
|
+
|
101
102
|
if isinstance(value, str):
|
102
103
|
value_to_check = value.lower() # accept mixed case variants
|
103
104
|
elif isinstance(value, int): # bool is also an int
|
@@ -105,14 +106,17 @@ def to_bool(value: object) -> bool:
|
|
105
106
|
else:
|
106
107
|
value_to_check = value
|
107
108
|
|
108
|
-
|
109
|
-
|
109
|
+
try:
|
110
|
+
if value_to_check in _valid_bool_true:
|
111
|
+
return True
|
110
112
|
|
111
|
-
|
112
|
-
|
113
|
+
if value_to_check in _valid_bool_false:
|
114
|
+
return False
|
113
115
|
|
114
|
-
|
115
|
-
|
116
|
+
# if we're still here, the value is unsupported- always fire a deprecation warning
|
117
|
+
result = value_to_check == 1 # backwards compatibility with the old code which checked: value in ('yes', 'on', '1', 'true', 1)
|
118
|
+
except TypeError:
|
119
|
+
result = False
|
116
120
|
|
117
121
|
# NB: update the doc string to reflect reality once this fallback is removed
|
118
122
|
display.deprecated(
|
@@ -250,11 +254,8 @@ def from_yaml(data):
|
|
250
254
|
if data is None:
|
251
255
|
return None
|
252
256
|
|
253
|
-
if isinstance(data,
|
254
|
-
|
255
|
-
# string wrapper class, so that CSafeLoader can
|
256
|
-
# read the data
|
257
|
-
return yaml_load(text_type(to_text(data, errors='surrogate_or_strict')))
|
257
|
+
if isinstance(data, str):
|
258
|
+
return yaml.load(data, Loader=_yaml_loader.AnsibleInstrumentedLoader) # type: ignore[arg-type]
|
258
259
|
|
259
260
|
display.deprecated(f"The from_yaml filter ignored non-string input of type {native_type_name(data)!r}.", version='2.23', obj=data)
|
260
261
|
return data
|
@@ -264,11 +265,8 @@ def from_yaml_all(data):
|
|
264
265
|
if data is None:
|
265
266
|
return [] # backward compatibility; ensure consistent result between classic/native Jinja for None/empty string input
|
266
267
|
|
267
|
-
if isinstance(data,
|
268
|
-
|
269
|
-
# string wrapper class, so that CSafeLoader can
|
270
|
-
# read the data
|
271
|
-
return yaml_load_all(text_type(to_text(data, errors='surrogate_or_strict')))
|
268
|
+
if isinstance(data, str):
|
269
|
+
return yaml.load_all(data, Loader=_yaml_loader.AnsibleInstrumentedLoader) # type: ignore[arg-type]
|
272
270
|
|
273
271
|
display.deprecated(f"The from_yaml_all filter ignored non-string input of type {native_type_name(data)!r}.", version='2.23', obj=data)
|
274
272
|
return data
|
@@ -21,7 +21,11 @@ def do_vault(data, secret, salt=None, vault_id='filter_default', wrap_object=Fal
|
|
21
21
|
raise TypeError(f"Can only vault strings, instead we got {type(data)}.")
|
22
22
|
|
23
23
|
if vaultid is not None:
|
24
|
-
display.deprecated(
|
24
|
+
display.deprecated(
|
25
|
+
msg="Use of undocumented `vaultid`.",
|
26
|
+
version="2.20",
|
27
|
+
help_text="Use `vault_id` instead.",
|
28
|
+
)
|
25
29
|
|
26
30
|
if vault_id == 'filter_default':
|
27
31
|
vault_id = vaultid
|
@@ -58,7 +62,11 @@ def do_unvault(vault, secret, vault_id='filter_default', vaultid=None):
|
|
58
62
|
raise TypeError(f"Vault should be in the form of a string, instead we got {type(vault)}.")
|
59
63
|
|
60
64
|
if vaultid is not None:
|
61
|
-
display.deprecated(
|
65
|
+
display.deprecated(
|
66
|
+
msg="Use of undocumented `vaultid`.",
|
67
|
+
version="2.20",
|
68
|
+
help_text="Use `vault_id` instead.",
|
69
|
+
)
|
62
70
|
|
63
71
|
if vault_id == 'filter_default':
|
64
72
|
vault_id = vaultid
|
ansible/plugins/filter/pow.yml
CHANGED
@@ -3,7 +3,7 @@ DOCUMENTATION:
|
|
3
3
|
version_added: "1.9"
|
4
4
|
short_description: power of (math operation)
|
5
5
|
description:
|
6
|
-
- Math operation that returns the Nth power of
|
6
|
+
- Math operation that returns the Nth power of inputted number, C(X ^ N).
|
7
7
|
notes:
|
8
8
|
- This is a passthrough to Python's C(math.pow).
|
9
9
|
positional: _input, _power
|