ansible-core 2.19.0b6__py3-none-any.whl → 2.19.0rc1__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/_json/__init__.py +31 -20
- ansible/_internal/_json/_profiles/_legacy.py +1 -1
- ansible/_internal/_templating/_jinja_bits.py +46 -14
- ansible/_internal/_templating/_jinja_common.py +1 -1
- ansible/_internal/_templating/_jinja_plugins.py +5 -2
- ansible/_internal/_templating/_utils.py +2 -1
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py +9 -0
- ansible/cli/__init__.py +2 -2
- ansible/cli/_ssh_askpass.py +37 -30
- ansible/cli/adhoc.py +6 -3
- ansible/cli/console.py +2 -2
- ansible/cli/doc.py +2 -2
- ansible/config/base.yml +9 -6
- ansible/executor/module_common.py +9 -6
- ansible/executor/powershell/psrp_put_file.ps1 +1 -1
- 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 +2 -2
- ansible/galaxy/collection/concrete_artifact_manager.py +2 -2
- ansible/galaxy/dependency_resolution/providers.py +3 -3
- ansible/inventory/group.py +6 -1
- ansible/inventory/host.py +6 -1
- ansible/module_utils/_internal/_datatag/__init__.py +6 -1
- ansible/module_utils/_internal/_deprecator.py +12 -1
- ansible/module_utils/ansible_release.py +1 -1
- ansible/module_utils/basic.py +14 -16
- ansible/module_utils/common/yaml.py +1 -1
- 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/other/facter.py +1 -1
- ansible/module_utils/facts/system/distribution.py +2 -2
- 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/urls.py +1 -1
- ansible/modules/apt.py +9 -3
- ansible/modules/assemble.py +5 -3
- ansible/modules/expect.py +5 -5
- ansible/modules/hostname.py +2 -2
- ansible/modules/pip.py +9 -11
- ansible/modules/raw.py +2 -2
- ansible/modules/stat.py +1 -1
- ansible/modules/systemd.py +1 -1
- ansible/modules/systemd_service.py +1 -1
- ansible/modules/wait_for.py +10 -3
- ansible/parsing/mod_args.py +38 -20
- ansible/parsing/vault/__init__.py +3 -3
- ansible/playbook/base.py +0 -2
- ansible/playbook/helpers.py +1 -1
- ansible/playbook/playbook_include.py +23 -57
- ansible/playbook/role/__init__.py +40 -23
- ansible/plugins/action/__init__.py +2 -2
- ansible/plugins/action/assemble.py +2 -1
- ansible/plugins/action/assert.py +2 -2
- ansible/plugins/action/script.py +5 -4
- ansible/plugins/action/template.py +1 -1
- ansible/plugins/callback/__init__.py +77 -87
- ansible/plugins/callback/default.py +0 -3
- ansible/plugins/callback/junit.py +0 -6
- ansible/plugins/connection/ssh.py +13 -6
- 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/loader.py +5 -0
- ansible/plugins/lookup/password.py +4 -6
- ansible/release.py +1 -1
- ansible/utils/display.py +16 -26
- ansible/utils/path.py +1 -1
- ansible/utils/vars.py +6 -2
- ansible/vars/manager.py +6 -3
- ansible/vars/reserved.py +6 -4
- {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0rc1.dist-info}/METADATA +1 -1
- {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0rc1.dist-info}/RECORD +111 -109
- 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/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 +197 -6
- ansible_test/_internal/inventory.py +4 -0
- ansible_test/_internal/metadata.py +94 -4
- ansible_test/_internal/processes.py +80 -0
- ansible_test/_internal/python_requirements.py +27 -0
- ansible_test/_internal/target.py +8 -0
- ansible_test/_internal/util_common.py +13 -3
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +2 -1
- ansible_test/_util/target/injector/python.py +8 -0
- {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0rc1.dist-info}/WHEEL +0 -0
- {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0rc1.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0rc1.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0rc1.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0rc1.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0rc1.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0rc1.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0rc1.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.19.0b6.dist-info → ansible_core-2.19.0rc1.dist-info}/top_level.txt +0 -0
@@ -81,9 +81,10 @@ class ActionModule(ActionBase):
|
|
81
81
|
|
82
82
|
def run(self, tmp=None, task_vars=None):
|
83
83
|
|
84
|
-
self._supports_check_mode =
|
84
|
+
self._supports_check_mode = True
|
85
85
|
|
86
86
|
super(ActionModule, self).run(tmp, task_vars)
|
87
|
+
|
87
88
|
del tmp # tmp no longer has any effect
|
88
89
|
|
89
90
|
if task_vars is None:
|
ansible/plugins/action/assert.py
CHANGED
@@ -72,12 +72,12 @@ class ActionModule(ActionBase):
|
|
72
72
|
fail_msg = new_module_args['fail_msg']
|
73
73
|
success_msg = new_module_args['success_msg']
|
74
74
|
quiet = new_module_args['quiet']
|
75
|
-
|
75
|
+
that_list = new_module_args['that']
|
76
76
|
|
77
77
|
if not quiet:
|
78
78
|
result['_ansible_verbose_always'] = True
|
79
79
|
|
80
|
-
for that in
|
80
|
+
for that in that_list:
|
81
81
|
test_result = self._templar.evaluate_conditional(conditional=that)
|
82
82
|
if not test_result:
|
83
83
|
result['failed'] = True
|
ansible/plugins/action/script.py
CHANGED
@@ -20,6 +20,7 @@ import os
|
|
20
20
|
import pathlib
|
21
21
|
import re
|
22
22
|
import shlex
|
23
|
+
import typing as _t
|
23
24
|
|
24
25
|
from ansible.errors import AnsibleError, AnsibleActionFail, AnsibleActionSkip
|
25
26
|
from ansible.executor.powershell import module_manifest as ps_manifest
|
@@ -35,7 +36,7 @@ class ActionModule(ActionBase):
|
|
35
36
|
# after chopping off a potential drive letter.
|
36
37
|
windows_absolute_path_detection = re.compile(r'^(?:[a-zA-Z]\:)?(\\|\/)')
|
37
38
|
|
38
|
-
def run(self, tmp=None, task_vars=None):
|
39
|
+
def run(self, tmp: str | None = None, task_vars: dict[str, _t.Any] | None = None) -> dict[str, _t.Any]:
|
39
40
|
""" handler for file transfer operations """
|
40
41
|
if task_vars is None:
|
41
42
|
task_vars = dict()
|
@@ -130,7 +131,7 @@ class ActionModule(ActionBase):
|
|
130
131
|
self._fixup_perms2((self._connection._shell.tmpdir, tmp_src), execute=True)
|
131
132
|
|
132
133
|
# add preparation steps to one ssh roundtrip executing the script
|
133
|
-
env_dict =
|
134
|
+
env_dict: dict[str, _t.Any] = {}
|
134
135
|
env_string = self._compute_environment_string(env_dict)
|
135
136
|
|
136
137
|
if executable:
|
@@ -164,10 +165,10 @@ class ActionModule(ActionBase):
|
|
164
165
|
script_cmd = self._connection._shell.build_module_command(env_string='', shebang='#!powershell', cmd='')
|
165
166
|
|
166
167
|
# now we execute script, always assume changed.
|
167
|
-
result = dict(self._low_level_execute_command(cmd=script_cmd, in_data=exec_data, sudoable=True, chdir=chdir), changed=True)
|
168
|
+
result: dict[str, object] = dict(self._low_level_execute_command(cmd=script_cmd, in_data=exec_data, sudoable=True, chdir=chdir), changed=True)
|
168
169
|
|
169
170
|
if 'rc' in result and result['rc'] != 0:
|
170
|
-
|
171
|
+
result.update(msg='non-zero return code', failed=True)
|
171
172
|
|
172
173
|
return result
|
173
174
|
finally:
|
@@ -44,7 +44,7 @@ class ActionModule(ActionBase):
|
|
44
44
|
del tmp # tmp no longer has any effect
|
45
45
|
|
46
46
|
# Options type validation
|
47
|
-
#
|
47
|
+
# strings
|
48
48
|
for s_type in ('src', 'dest', 'state', 'newline_sequence', 'variable_start_string', 'variable_end_string', 'block_start_string',
|
49
49
|
'block_end_string', 'comment_start_string', 'comment_end_string'):
|
50
50
|
if s_type in self._task.args:
|
@@ -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
|
|
@@ -640,11 +640,11 @@ def _clean_shm(func):
|
|
640
640
|
self.shm.close()
|
641
641
|
with contextlib.suppress(FileNotFoundError):
|
642
642
|
self.shm.unlink()
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
643
|
+
if not _HAS_RESOURCE_TRACK:
|
644
|
+
# deprecated: description='unneeded due to track argument for SharedMemory' python_version='3.12'
|
645
|
+
# There is a resource tracking issue where the resource is deleted, but tracking still has a record
|
646
|
+
# This will effectively overwrite the record and remove it
|
647
|
+
SharedMemory(name=self.shm.name, create=True, size=1).unlink()
|
648
648
|
return ret
|
649
649
|
return inner
|
650
650
|
|
@@ -961,6 +961,13 @@ class Connection(ConnectionBase):
|
|
961
961
|
b_args = (b"-o", b'ControlPath="%s"' % to_bytes(self.control_path % dict(directory=cpdir), errors='surrogate_or_strict'))
|
962
962
|
self._add_args(b_command, b_args, u"found only ControlPersist; added ControlPath")
|
963
963
|
|
964
|
+
if password_mechanism == "ssh_askpass":
|
965
|
+
self._add_args(
|
966
|
+
b_command,
|
967
|
+
(b"-o", b"NumberOfPasswordPrompts=1"),
|
968
|
+
"Restrict number of password prompts in case incorrect password is provided.",
|
969
|
+
)
|
970
|
+
|
964
971
|
# Finally, we add any caller-supplied extras.
|
965
972
|
if other_args:
|
966
973
|
b_command += [to_bytes(a) for a in other_args]
|
@@ -1171,7 +1178,7 @@ class Connection(ConnectionBase):
|
|
1171
1178
|
|
1172
1179
|
# Are we requesting privilege escalation? Right now, we may be invoked
|
1173
1180
|
# to execute sftp/scp with sudoable=True, but we can request escalation
|
1174
|
-
# only when using ssh. Otherwise we can send initial data
|
1181
|
+
# only when using ssh. Otherwise, we can send initial data straight away.
|
1175
1182
|
|
1176
1183
|
state = states.index('ready_to_send')
|
1177
1184
|
if to_bytes(self.get_option('ssh_executable')) in cmd and sudoable:
|
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
|
ansible/plugins/filter/root.yml
CHANGED
@@ -3,7 +3,7 @@ DOCUMENTATION:
|
|
3
3
|
version_added: "1.9"
|
4
4
|
short_description: root of (math operation)
|
5
5
|
description:
|
6
|
-
- Math operation that returns the Nth root of
|
6
|
+
- Math operation that returns the Nth root of inputted number C(X ^^ N).
|
7
7
|
positional: _input, base
|
8
8
|
options:
|
9
9
|
_input:
|
@@ -1,16 +1,16 @@
|
|
1
1
|
DOCUMENTATION:
|
2
2
|
name: strftime
|
3
3
|
version_added: "2.4"
|
4
|
-
short_description: date
|
4
|
+
short_description: date formatting
|
5
5
|
description:
|
6
|
-
- Using Python's C(strftime) function, take a data
|
6
|
+
- Using Python's C(strftime) function, take a data formatting string and a date/time to create a formatted date.
|
7
7
|
notes:
|
8
8
|
- This is a passthrough to Python's C(stftime), for a complete set of formatting options go to https://strftime.org/.
|
9
9
|
positional: _input, second, utc
|
10
10
|
options:
|
11
11
|
_input:
|
12
12
|
description:
|
13
|
-
- A
|
13
|
+
- A formatting string following C(stftime) conventions.
|
14
14
|
- See L(the Python documentation, https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior) for a reference.
|
15
15
|
type: str
|
16
16
|
required: true
|
@@ -98,7 +98,7 @@ EXAMPLES = r'''# fmt: code
|
|
98
98
|
def get_api_data(namespace: str, pretty=False) -> str:
|
99
99
|
"""
|
100
100
|
:param namespace: parameter for our custom api
|
101
|
-
:param pretty: Human
|
101
|
+
:param pretty: Human readable JSON vs machine readable
|
102
102
|
:return: JSON string
|
103
103
|
"""
|
104
104
|
found_data = list(MyInventoryAPI(namespace))
|
ansible/plugins/loader.py
CHANGED
@@ -989,6 +989,9 @@ class PluginLoader:
|
|
989
989
|
def get_with_context(self, name, *args, **kwargs) -> get_with_context_result:
|
990
990
|
""" instantiates a plugin of the given name using arguments """
|
991
991
|
|
992
|
+
if not name:
|
993
|
+
raise ValueError('A non-empty plugin name is required.')
|
994
|
+
|
992
995
|
found_in_cache = True
|
993
996
|
class_only = kwargs.pop('class_only', False)
|
994
997
|
collection_list = kwargs.pop('collection_list', None)
|
@@ -1034,6 +1037,7 @@ class PluginLoader:
|
|
1034
1037
|
except AttributeError:
|
1035
1038
|
return get_with_context_result(None, plugin_load_context)
|
1036
1039
|
if not issubclass(obj, plugin_class):
|
1040
|
+
display.warning(f"Ignoring {self.type} plugin {resolved_type_name!r} due to missing base class {self.base_class!r}.")
|
1037
1041
|
return get_with_context_result(None, plugin_load_context)
|
1038
1042
|
|
1039
1043
|
# FIXME: update this to use the load context
|
@@ -1721,6 +1725,7 @@ callback_loader = PluginLoader(
|
|
1721
1725
|
'ansible.plugins.callback',
|
1722
1726
|
C.DEFAULT_CALLBACK_PLUGIN_PATH,
|
1723
1727
|
'callback_plugins',
|
1728
|
+
required_base_class='CallbackBase',
|
1724
1729
|
)
|
1725
1730
|
|
1726
1731
|
connection_loader = PluginLoader(
|
@@ -126,6 +126,7 @@ _raw:
|
|
126
126
|
elements: str
|
127
127
|
"""
|
128
128
|
|
129
|
+
import contextlib
|
129
130
|
import os
|
130
131
|
import string
|
131
132
|
import time
|
@@ -269,15 +270,12 @@ def _get_lock(b_path):
|
|
269
270
|
b_pathdir = os.path.dirname(b_path)
|
270
271
|
lockfile_name = to_bytes("%s.ansible_lockfile" % hashlib.sha1(b_path).hexdigest())
|
271
272
|
lockfile = os.path.join(b_pathdir, lockfile_name)
|
272
|
-
if
|
273
|
-
|
274
|
-
|
273
|
+
if b_path != b'/dev/null':
|
274
|
+
makedirs_safe(b_pathdir, mode=0o700)
|
275
|
+
with contextlib.suppress(FileExistsError):
|
275
276
|
fd = os.open(lockfile, os.O_CREAT | os.O_EXCL)
|
276
277
|
os.close(fd)
|
277
278
|
first_process = True
|
278
|
-
except OSError as e:
|
279
|
-
if e.strerror != 'File exists':
|
280
|
-
raise
|
281
279
|
|
282
280
|
counter = 0
|
283
281
|
# if the lock is got by other process, wait until it's released
|