ansible-core 2.19.0b3__py3-none-any.whl → 2.19.0b5__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/__init__.py +2 -2
- ansible/_internal/_collection_proxy.py +1 -1
- ansible/_internal/_errors/_alarm_timeout.py +66 -0
- ansible/_internal/_errors/_captured.py +25 -30
- ansible/_internal/_errors/_error_factory.py +89 -0
- ansible/_internal/_errors/_error_utils.py +240 -0
- ansible/_internal/_errors/_task_timeout.py +28 -0
- ansible/_internal/_event_formatting.py +127 -0
- ansible/_internal/_json/__init__.py +6 -6
- ansible/_internal/_json/_profiles/_cache_persistence.py +2 -0
- ansible/_internal/_json/_profiles/_inventory_legacy.py +1 -1
- ansible/_internal/_json/_profiles/_legacy.py +3 -11
- ansible/_internal/_ssh/__init__.py +0 -0
- ansible/_internal/_ssh/_agent_launch.py +91 -0
- ansible/{utils → _internal/_ssh}/_ssh_agent.py +55 -93
- ansible/_internal/_templating/__init__.py +5 -3
- ansible/_internal/_templating/_datatag.py +2 -1
- ansible/_internal/_templating/_engine.py +3 -4
- ansible/_internal/_templating/_jinja_bits.py +21 -16
- ansible/_internal/_templating/_jinja_common.py +18 -27
- ansible/_internal/_templating/_jinja_plugins.py +31 -3
- ansible/_internal/_templating/_lazy_containers.py +5 -5
- ansible/_internal/_templating/_transform.py +20 -19
- ansible/_internal/_templating/_utils.py +1 -1
- ansible/_internal/_testing.py +26 -0
- ansible/_internal/_yaml/_dumper.py +1 -1
- ansible/_internal/_yaml/_errors.py +7 -7
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +1 -1
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +1 -1
- ansible/cli/__init__.py +5 -82
- ansible/cli/arguments/option_helpers.py +8 -5
- ansible/cli/doc.py +84 -28
- ansible/cli/inventory.py +1 -1
- ansible/compat/importlib_resources.py +9 -12
- ansible/config/base.yml +27 -23
- ansible/config/manager.py +142 -101
- ansible/constants.py +1 -1
- ansible/errors/__init__.py +96 -49
- ansible/executor/module_common.py +8 -10
- ansible/executor/powershell/async_watchdog.ps1 +2 -2
- ansible/executor/powershell/async_wrapper.ps1 +3 -3
- ansible/executor/powershell/become_wrapper.ps1 +20 -2
- ansible/executor/powershell/bootstrap_wrapper.ps1 +28 -6
- ansible/executor/powershell/coverage_wrapper.ps1 +15 -6
- ansible/executor/powershell/exec_wrapper.ps1 +219 -6
- ansible/executor/powershell/module_manifest.py +52 -0
- ansible/executor/powershell/module_wrapper.ps1 +47 -21
- ansible/executor/powershell/powershell_expand_user.ps1 +20 -0
- ansible/executor/powershell/powershell_mkdtemp.ps1 +17 -0
- ansible/executor/process/worker.py +38 -113
- ansible/executor/task_executor.py +26 -61
- ansible/executor/task_result.py +2 -4
- ansible/galaxy/collection/__init__.py +1 -4
- ansible/inventory/manager.py +1 -0
- ansible/module_utils/_internal/__init__.py +0 -3
- ansible/module_utils/_internal/_ambient_context.py +3 -3
- ansible/module_utils/_internal/_ansiballz.py +4 -2
- ansible/module_utils/_internal/_datatag/__init__.py +20 -14
- ansible/module_utils/_internal/_datatag/_tags.py +2 -2
- ansible/module_utils/_internal/_deprecator.py +66 -48
- ansible/module_utils/_internal/_errors.py +88 -17
- ansible/module_utils/_internal/_event_utils.py +61 -0
- ansible/module_utils/_internal/_json/_profiles/__init__.py +21 -4
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +2 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +2 -0
- ansible/module_utils/_internal/_json/_profiles/_tagless.py +3 -1
- ansible/module_utils/{common/messages.py → _internal/_messages.py} +28 -47
- ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +1 -3
- ansible/module_utils/_internal/_plugin_info.py +1 -1
- ansible/module_utils/_internal/_stack.py +22 -0
- ansible/module_utils/_internal/_text_utils.py +6 -0
- ansible/module_utils/_internal/_traceback.py +11 -8
- ansible/module_utils/ansible_release.py +1 -1
- ansible/module_utils/basic.py +49 -15
- ansible/module_utils/common/arg_spec.py +2 -2
- ansible/module_utils/common/collections.py +6 -0
- ansible/module_utils/common/json.py +2 -2
- ansible/module_utils/common/text/converters.py +3 -3
- ansible/module_utils/common/validation.py +1 -1
- ansible/module_utils/common/warnings.py +80 -23
- ansible/module_utils/common/yaml.py +1 -1
- ansible/module_utils/datatag.py +5 -2
- ansible/module_utils/facts/system/distribution.py +16 -3
- ansible/module_utils/facts/virtual/linux.py +2 -2
- ansible/module_utils/parsing/convert_bool.py +6 -0
- ansible/module_utils/service.py +2 -9
- ansible/modules/apt_repository.py +7 -29
- ansible/modules/assemble.py +4 -4
- ansible/modules/async_status.py +13 -11
- ansible/modules/async_wrapper.py +5 -5
- ansible/modules/cron.py +3 -5
- ansible/modules/dnf5.py +15 -22
- ansible/modules/git.py +1 -6
- ansible/modules/hostname.py +0 -1
- ansible/modules/pip.py +2 -4
- ansible/modules/service.py +3 -9
- ansible/modules/sysvinit.py +3 -3
- ansible/parsing/ajson.py +3 -5
- ansible/parsing/dataloader.py +4 -4
- ansible/parsing/mod_args.py +1 -1
- ansible/parsing/plugin_docs.py +2 -2
- ansible/parsing/utils/yaml.py +3 -3
- ansible/parsing/vault/__init__.py +4 -4
- ansible/playbook/playbook_include.py +1 -1
- ansible/playbook/taggable.py +0 -3
- ansible/plugins/__init__.py +0 -25
- ansible/plugins/action/__init__.py +9 -32
- ansible/plugins/action/add_host.py +1 -1
- ansible/plugins/action/assemble.py +8 -16
- ansible/plugins/action/async_status.py +7 -2
- ansible/plugins/action/copy.py +8 -7
- ansible/plugins/action/gather_facts.py +8 -8
- ansible/plugins/action/package.py +5 -8
- ansible/plugins/action/script.py +8 -15
- ansible/plugins/action/service.py +3 -7
- ansible/plugins/action/template.py +6 -8
- ansible/plugins/action/unarchive.py +5 -15
- ansible/plugins/action/uri.py +9 -20
- ansible/plugins/callback/__init__.py +4 -6
- ansible/plugins/callback/junit.py +4 -2
- ansible/plugins/connection/local.py +2 -2
- ansible/plugins/connection/ssh.py +17 -9
- ansible/plugins/connection/winrm.py +5 -2
- ansible/plugins/doc_fragments/constructed.py +2 -2
- ansible/plugins/filter/core.py +13 -6
- ansible/plugins/filter/encryption.py +4 -4
- ansible/plugins/inventory/__init__.py +11 -10
- ansible/plugins/inventory/script.py +1 -1
- ansible/plugins/list.py +69 -16
- ansible/plugins/loader.py +10 -9
- ansible/plugins/lookup/csvfile.py +16 -71
- ansible/plugins/lookup/first_found.py +2 -1
- ansible/plugins/shell/__init__.py +56 -2
- ansible/plugins/shell/powershell.py +66 -9
- ansible/plugins/shell/sh.py +9 -5
- ansible/plugins/test/core.py +21 -15
- ansible/plugins/test/finished.yml +1 -1
- ansible/plugins/test/uri.py +2 -5
- ansible/release.py +1 -1
- ansible/template/__init__.py +30 -2
- ansible/utils/collection_loader/__init__.py +2 -0
- ansible/utils/display.py +107 -128
- ansible/utils/hashing.py +0 -1
- ansible/utils/listify.py +6 -4
- ansible/utils/plugin_docs.py +2 -1
- ansible/utils/unsafe_proxy.py +1 -1
- ansible/vars/hostvars.py +1 -1
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info}/METADATA +3 -2
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info}/RECORD +173 -161
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info}/WHEEL +1 -1
- ansible_test/_data/completion/docker.txt +3 -3
- ansible_test/_data/completion/remote.txt +1 -0
- ansible_test/_data/requirements/sanity.ansible-doc.txt +1 -1
- ansible_test/_data/requirements/sanity.changelog.txt +2 -2
- ansible_test/_data/requirements/sanity.pep8.txt +1 -1
- ansible_test/_data/requirements/sanity.pylint.txt +4 -4
- ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
- ansible_test/_internal/util.py +20 -0
- ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +1 -0
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +1 -0
- ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +1 -0
- ansible_test/_util/controller/sanity/pylint/config/collection.cfg +1 -0
- ansible_test/_util/controller/sanity/pylint/config/default.cfg +1 -0
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +73 -8
- ansible_test/_util/target/setup/bootstrap.sh +31 -0
- ansible/_internal/_errors/_utils.py +0 -310
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info/licenses}/COPYING +0 -0
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info/licenses/licenses}/Apache-License.txt +0 -0
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info/licenses/licenses}/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info/licenses/licenses}/MIT-license.txt +0 -0
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info/licenses/licenses}/PSF-license.txt +0 -0
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info/licenses/licenses}/simplified_bsd.txt +0 -0
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info}/top_level.txt +0 -0
ansible/playbook/taggable.py
CHANGED
@@ -45,9 +45,6 @@ class Taggable:
|
|
45
45
|
return ds
|
46
46
|
|
47
47
|
if isinstance(ds, str):
|
48
|
-
# DTFIX-RELEASE: this allows each individual tag to be templated, but prevents the use of commas in templates, is that what we want?
|
49
|
-
# DTFIX-RELEASE: this can return empty tags (including a list of nothing but empty tags), is that correct?
|
50
|
-
# DTFIX-RELEASE: the original code seemed to attempt to preserve `ds` if there were no commas, but it never ran, what should it actually do?
|
51
48
|
return [AnsibleTagHelper.tag_copy(ds, item.strip()) for item in ds.split(',')]
|
52
49
|
|
53
50
|
raise AnsibleError('tags must be specified as a list', obj=ds)
|
ansible/plugins/__init__.py
CHANGED
@@ -189,28 +189,3 @@ class AnsibleJinja2Plugin(AnsiblePlugin, metaclass=abc.ABCMeta):
|
|
189
189
|
@property
|
190
190
|
def j2_function(self) -> t.Callable:
|
191
191
|
return self._function
|
192
|
-
|
193
|
-
|
194
|
-
_TCallable = t.TypeVar('_TCallable', bound=t.Callable)
|
195
|
-
|
196
|
-
|
197
|
-
def accept_args_markers(plugin: _TCallable) -> _TCallable:
|
198
|
-
"""
|
199
|
-
A decorator to mark a Jinja plugin as capable of handling `Marker` values for its top-level arguments.
|
200
|
-
Non-decorated plugin invocation is skipped when a top-level argument is a `Marker`, with the first such value substituted as the plugin result.
|
201
|
-
This ensures that only plugins which understand `Marker` instances for top-level arguments will encounter them.
|
202
|
-
"""
|
203
|
-
plugin.accept_args_markers = True
|
204
|
-
|
205
|
-
return plugin
|
206
|
-
|
207
|
-
|
208
|
-
def accept_lazy_markers(plugin: _TCallable) -> _TCallable:
|
209
|
-
"""
|
210
|
-
A decorator to mark a Jinja plugin as capable of handling `Marker` values retrieved from lazy containers.
|
211
|
-
Non-decorated plugins will trigger a `MarkerError` exception when attempting to retrieve a `Marker` from a lazy container.
|
212
|
-
This ensures that only plugins which understand lazy retrieval of `Marker` instances will encounter them.
|
213
|
-
"""
|
214
|
-
plugin.accept_lazy_markers = True
|
215
|
-
|
216
|
-
return plugin
|
@@ -20,9 +20,8 @@ from abc import ABC, abstractmethod
|
|
20
20
|
from collections.abc import Sequence
|
21
21
|
|
22
22
|
from ansible import constants as C
|
23
|
-
from ansible._internal._errors import _captured
|
23
|
+
from ansible._internal._errors import _captured, _error_utils
|
24
24
|
from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleActionSkip, AnsibleActionFail, AnsibleAuthenticationFailure
|
25
|
-
from ansible._internal._errors import _utils
|
26
25
|
from ansible.executor.module_common import modify_module, _BuiltModule
|
27
26
|
from ansible.executor.interpreter_discovery import discover_interpreter, InterpreterDiscoveryRequiredError
|
28
27
|
from ansible.module_utils._internal import _traceback
|
@@ -41,7 +40,6 @@ from ansible import _internal
|
|
41
40
|
from ansible._internal._templating import _engine
|
42
41
|
|
43
42
|
from .. import _AnsiblePluginInfoMixin
|
44
|
-
from ...module_utils.common.messages import PluginInfo
|
45
43
|
|
46
44
|
display = Display()
|
47
45
|
|
@@ -121,8 +119,7 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
121
119
|
|
122
120
|
* Module parameters. These are stored in self._task.args
|
123
121
|
"""
|
124
|
-
|
125
|
-
# does not default to {'changed': False, 'failed': False}, as it breaks async
|
122
|
+
# does not default to {'changed': False, 'failed': False}, as it used to break async
|
126
123
|
result = {}
|
127
124
|
|
128
125
|
if tmp is not None:
|
@@ -476,8 +473,8 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
476
473
|
|
477
474
|
become_unprivileged = self._is_become_unprivileged()
|
478
475
|
basefile = self._connection._shell._generate_temp_dir_name()
|
479
|
-
cmd = self._connection._shell.
|
480
|
-
result = self._low_level_execute_command(cmd, sudoable=False)
|
476
|
+
cmd = self._connection._shell._mkdtemp2(basefile=basefile, system=become_unprivileged, tmpdir=tmpdir)
|
477
|
+
result = self._low_level_execute_command(cmd.command, in_data=cmd.input_data, sudoable=False)
|
481
478
|
|
482
479
|
# error handling on this seems a little aggressive?
|
483
480
|
if result['rc'] != 0:
|
@@ -908,8 +905,8 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
908
905
|
expand_path = '~%s' % (self._get_remote_user() or '')
|
909
906
|
|
910
907
|
# use shell to construct appropriate command and execute
|
911
|
-
cmd = self._connection._shell.
|
912
|
-
data = self._low_level_execute_command(cmd, sudoable=False)
|
908
|
+
cmd = self._connection._shell._expand_user2(expand_path)
|
909
|
+
data = self._low_level_execute_command(cmd.command, in_data=cmd.input_data, sudoable=False)
|
913
910
|
|
914
911
|
try:
|
915
912
|
initial_fragment = data['stdout'].strip().splitlines()[-1]
|
@@ -1002,7 +999,7 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
1002
999
|
# tells the module to ignore options that are not in its argspec.
|
1003
1000
|
module_args['_ansible_ignore_unknown_opts'] = ignore_unknown_opts
|
1004
1001
|
|
1005
|
-
# allow user to insert string to add context to remote
|
1002
|
+
# allow user to insert string to add context to remote logging
|
1006
1003
|
module_args['_ansible_target_log_info'] = C.config.get_config_value('TARGET_LOG_INFO', variables=task_vars)
|
1007
1004
|
|
1008
1005
|
module_args['_ansible_tracebacks_for'] = _traceback.traceback_for()
|
@@ -1115,7 +1112,7 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
1115
1112
|
if wrap_async and not self._connection.always_pipeline_modules:
|
1116
1113
|
# configure, upload, and chmod the async_wrapper module
|
1117
1114
|
(async_module_bits, async_module_path) = self._configure_module(module_name='ansible.legacy.async_wrapper', module_args=dict(), task_vars=task_vars)
|
1118
|
-
(
|
1115
|
+
(shebang, async_module_data) = (async_module_bits.shebang, async_module_bits.b_module_data)
|
1119
1116
|
async_module_remote_filename = self._connection._shell.get_remote_filename(async_module_path)
|
1120
1117
|
remote_async_module_path = self._connection._shell.join_path(tmpdir, async_module_remote_filename)
|
1121
1118
|
self._transfer_data(remote_async_module_path, async_module_data)
|
@@ -1255,7 +1252,7 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
1255
1252
|
except AnsibleError as ansible_ex:
|
1256
1253
|
sentinel = object()
|
1257
1254
|
|
1258
|
-
data =
|
1255
|
+
data = _error_utils.result_dict_from_exception(ansible_ex)
|
1259
1256
|
data.update(
|
1260
1257
|
_ansible_parsed=False,
|
1261
1258
|
module_stdout=res.get('stdout', ''),
|
@@ -1436,23 +1433,3 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
1436
1433
|
|
1437
1434
|
# if missing it will return a file not found exception
|
1438
1435
|
return self._loader.path_dwim_relative_stack(path_stack, dirname, needle)
|
1439
|
-
|
1440
|
-
@staticmethod
|
1441
|
-
def result_dict_from_exception(exception: BaseException) -> dict[str, t.Any]:
|
1442
|
-
"""Return a failed task result dict from the given exception."""
|
1443
|
-
if ansible_remoted_error := _captured.AnsibleResultCapturedError.find_first_remoted_error(exception):
|
1444
|
-
result = ansible_remoted_error._result.copy()
|
1445
|
-
else:
|
1446
|
-
result = {}
|
1447
|
-
|
1448
|
-
error_summary = _utils._create_error_summary(exception, _traceback.TracebackEvent.ERROR)
|
1449
|
-
|
1450
|
-
result.update(
|
1451
|
-
failed=True,
|
1452
|
-
exception=error_summary,
|
1453
|
-
)
|
1454
|
-
|
1455
|
-
if 'msg' not in result:
|
1456
|
-
result.update(msg=_utils._dedupe_and_concat_message_chain([md.msg for md in error_summary.details]))
|
1457
|
-
|
1458
|
-
return result
|
@@ -77,7 +77,7 @@ class ActionModule(ActionBase):
|
|
77
77
|
elif isinstance(groups, string_types):
|
78
78
|
group_list = groups.split(",")
|
79
79
|
else:
|
80
|
-
raise AnsibleActionFail("Groups must be specified as a list.", obj=
|
80
|
+
raise AnsibleActionFail("Groups must be specified as a list.", obj=groups)
|
81
81
|
|
82
82
|
for group_name in group_list:
|
83
83
|
if group_name not in new_groups:
|
@@ -25,8 +25,8 @@ import re
|
|
25
25
|
import tempfile
|
26
26
|
|
27
27
|
from ansible import constants as C
|
28
|
-
from ansible.errors import
|
29
|
-
from ansible.module_utils.common.text.converters import
|
28
|
+
from ansible.errors import AnsibleActionFail
|
29
|
+
from ansible.module_utils.common.text.converters import to_text
|
30
30
|
from ansible.module_utils.parsing.convert_bool import boolean
|
31
31
|
from ansible.plugins.action import ActionBase
|
32
32
|
from ansible.utils.hashing import checksum_s
|
@@ -83,7 +83,7 @@ class ActionModule(ActionBase):
|
|
83
83
|
|
84
84
|
self._supports_check_mode = False
|
85
85
|
|
86
|
-
|
86
|
+
super(ActionModule, self).run(tmp, task_vars)
|
87
87
|
del tmp # tmp no longer has any effect
|
88
88
|
|
89
89
|
if task_vars is None:
|
@@ -104,13 +104,9 @@ class ActionModule(ActionBase):
|
|
104
104
|
|
105
105
|
if boolean(remote_src, strict=False):
|
106
106
|
# call assemble via ansible.legacy to allow library/ overrides of the module without collection search
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
try:
|
111
|
-
src = self._find_needle('files', src)
|
112
|
-
except AnsibleError as e:
|
113
|
-
raise AnsibleActionFail(to_native(e))
|
107
|
+
return self._execute_module(module_name='ansible.legacy.assemble', task_vars=task_vars)
|
108
|
+
|
109
|
+
src = self._find_needle('files', src)
|
114
110
|
|
115
111
|
if not os.path.isdir(src):
|
116
112
|
raise AnsibleActionFail(u"Source (%s) is not a directory" % src)
|
@@ -153,13 +149,9 @@ class ActionModule(ActionBase):
|
|
153
149
|
res = self._execute_module(module_name='ansible.legacy.copy', module_args=new_module_args, task_vars=task_vars)
|
154
150
|
if diff:
|
155
151
|
res['diff'] = diff
|
156
|
-
|
152
|
+
return res
|
157
153
|
else:
|
158
|
-
|
154
|
+
return self._execute_module(module_name='ansible.legacy.file', module_args=new_module_args, task_vars=task_vars)
|
159
155
|
|
160
|
-
except AnsibleAction as e:
|
161
|
-
result.update(e.result)
|
162
156
|
finally:
|
163
157
|
self._remove_tmp_path(self._connection._shell.tmpdir)
|
164
|
-
|
165
|
-
return result
|
@@ -28,7 +28,7 @@ class ActionModule(ActionBase):
|
|
28
28
|
)
|
29
29
|
|
30
30
|
# initialize response
|
31
|
-
results['started'] = results['finished'] =
|
31
|
+
results['started'] = results['finished'] = False
|
32
32
|
results['stdout'] = results['stderr'] = ''
|
33
33
|
results['stdout_lines'] = results['stderr_lines'] = []
|
34
34
|
|
@@ -43,9 +43,14 @@ class ActionModule(ActionBase):
|
|
43
43
|
results['erased'] = log_path
|
44
44
|
else:
|
45
45
|
results['results_file'] = log_path
|
46
|
-
results['started'] =
|
46
|
+
results['started'] = True
|
47
47
|
|
48
48
|
new_module_args['_async_dir'] = async_dir
|
49
49
|
results = merge_hash(results, self._execute_module(module_name='ansible.legacy.async_status', task_vars=task_vars, module_args=new_module_args))
|
50
50
|
|
51
|
+
# Backwards compat shim for when started/finished were ints,
|
52
|
+
# mostly to work with ansible.windows.async_status
|
53
|
+
for convert in ('started', 'finished'):
|
54
|
+
results[convert] = bool(results[convert])
|
55
|
+
|
51
56
|
return results
|
ansible/plugins/action/copy.py
CHANGED
@@ -27,7 +27,7 @@ import tempfile
|
|
27
27
|
from ansible import constants as C
|
28
28
|
from ansible.errors import AnsibleError, AnsibleActionFail, AnsibleFileNotFound
|
29
29
|
from ansible.module_utils.basic import FILE_COMMON_ARGUMENTS
|
30
|
-
from ansible.module_utils.common.text.converters import to_bytes,
|
30
|
+
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
31
31
|
from ansible.module_utils.parsing.convert_bool import boolean
|
32
32
|
from ansible.plugins.action import ActionBase
|
33
33
|
from ansible.utils.hashing import checksum
|
@@ -409,6 +409,7 @@ class ActionModule(ActionBase):
|
|
409
409
|
task_vars = dict()
|
410
410
|
|
411
411
|
result = super(ActionModule, self).run(tmp, task_vars)
|
412
|
+
|
412
413
|
del tmp # tmp no longer has any effect
|
413
414
|
|
414
415
|
# ensure user is not setting internal parameters
|
@@ -450,10 +451,10 @@ class ActionModule(ActionBase):
|
|
450
451
|
else:
|
451
452
|
content_tempfile = self._create_content_tempfile(content)
|
452
453
|
source = content_tempfile
|
453
|
-
except Exception as
|
454
|
-
result
|
455
|
-
|
456
|
-
|
454
|
+
except Exception as ex:
|
455
|
+
self._ensure_invocation(result)
|
456
|
+
|
457
|
+
raise AnsibleActionFail(message="could not write content temp file", result=result) from ex
|
457
458
|
|
458
459
|
# if we have first_available_file in our vars
|
459
460
|
# look up the files and use the first one we find as src
|
@@ -470,9 +471,9 @@ class ActionModule(ActionBase):
|
|
470
471
|
# find in expected paths
|
471
472
|
source = self._find_needle('files', source)
|
472
473
|
except AnsibleError as ex:
|
473
|
-
|
474
|
+
self._ensure_invocation(result)
|
474
475
|
|
475
|
-
|
476
|
+
raise AnsibleActionFail(result=result) from ex
|
476
477
|
|
477
478
|
if trailing_slash != source.endswith(os.path.sep):
|
478
479
|
if source[-1] == os.path.sep:
|
@@ -13,6 +13,7 @@ from ansible.executor.module_common import _apply_action_arg_defaults
|
|
13
13
|
from ansible.module_utils.parsing.convert_bool import boolean
|
14
14
|
from ansible.plugins.action import ActionBase
|
15
15
|
from ansible.utils.vars import merge_hash
|
16
|
+
from ansible._internal._errors import _error_utils
|
16
17
|
|
17
18
|
|
18
19
|
class ActionModule(ActionBase):
|
@@ -127,8 +128,6 @@ class ActionModule(ActionBase):
|
|
127
128
|
# TODO: use gather_timeout to cut module execution if module itself does not support gather_timeout
|
128
129
|
res = self._execute_module(module_name=fact_module, module_args=mod_args, task_vars=task_vars, wrap_async=False)
|
129
130
|
if res.get('failed', False):
|
130
|
-
# DTFIX-RELEASE: this trashes the individual failure details and does not work with the new error handling; need to do something to
|
131
|
-
# invoke per-item error handling- perhaps returning this as a synthetic loop result?
|
132
131
|
failed[fact_module] = res
|
133
132
|
elif res.get('skipped', False):
|
134
133
|
skipped[fact_module] = res
|
@@ -159,10 +158,8 @@ class ActionModule(ActionBase):
|
|
159
158
|
for module in jobs:
|
160
159
|
poll_args = {'jid': jobs[module]['ansible_job_id'], '_async_dir': os.path.dirname(jobs[module]['results_file'])}
|
161
160
|
res = self._execute_module(module_name='ansible.legacy.async_status', module_args=poll_args, task_vars=task_vars, wrap_async=False)
|
162
|
-
if res.get('finished',
|
161
|
+
if res.get('finished', False):
|
163
162
|
if res.get('failed', False):
|
164
|
-
# DTFIX-RELEASE: this trashes the individual failure details and does not work with the new error handling; need to do something to
|
165
|
-
# invoke per-item error handling- perhaps returning this as a synthetic loop result?
|
166
163
|
failed[module] = res
|
167
164
|
elif res.get('skipped', False):
|
168
165
|
skipped[module] = res
|
@@ -180,16 +177,19 @@ class ActionModule(ActionBase):
|
|
180
177
|
self._task.async_val = async_val
|
181
178
|
|
182
179
|
if skipped:
|
183
|
-
result['msg'] = "The following modules were skipped:
|
180
|
+
result['msg'] = f"The following modules were skipped: {', '.join(skipped.keys())}."
|
184
181
|
result['skipped_modules'] = skipped
|
185
182
|
if len(skipped) == len(modules):
|
186
183
|
result['skipped'] = True
|
187
184
|
|
188
185
|
if failed:
|
189
|
-
result['failed'] = True
|
190
|
-
result['msg'] = "The following modules failed to execute: %s\n" % (', '.join(failed.keys()))
|
191
186
|
result['failed_modules'] = failed
|
192
187
|
|
188
|
+
result.update(_error_utils.result_dict_from_captured_errors(
|
189
|
+
msg=f"The following modules failed to execute: {', '.join(failed.keys())}.",
|
190
|
+
errors=[r['exception'] for r in failed.values()],
|
191
|
+
))
|
192
|
+
|
193
193
|
# tell executor facts were gathered
|
194
194
|
result['ansible_facts']['_ansible_facts_gathered'] = True
|
195
195
|
|
@@ -16,7 +16,7 @@
|
|
16
16
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
from __future__ import annotations
|
18
18
|
|
19
|
-
from ansible.errors import
|
19
|
+
from ansible.errors import AnsibleActionFail
|
20
20
|
from ansible.executor.module_common import _apply_action_arg_defaults
|
21
21
|
from ansible.module_utils.facts.system.pkg_mgr import PKG_MGRS
|
22
22
|
from ansible.plugins.action import ActionBase
|
@@ -38,7 +38,7 @@ class ActionModule(ActionBase):
|
|
38
38
|
self._supports_check_mode = True
|
39
39
|
self._supports_async = True
|
40
40
|
|
41
|
-
|
41
|
+
super(ActionModule, self).run(tmp, task_vars)
|
42
42
|
|
43
43
|
module = self._task.args.get('use', 'auto')
|
44
44
|
|
@@ -99,11 +99,8 @@ class ActionModule(ActionBase):
|
|
99
99
|
module = 'ansible.legacy.' + module
|
100
100
|
|
101
101
|
display.vvvv("Running %s" % module)
|
102
|
-
|
102
|
+
return self._execute_module(module_name=module, module_args=new_module_args, task_vars=task_vars, wrap_async=self._task.async_val)
|
103
103
|
else:
|
104
104
|
raise AnsibleActionFail('Could not detect which package manager to use. Try gathering facts or setting the "use" option.')
|
105
|
-
|
106
|
-
|
107
|
-
result.update(e.result)
|
108
|
-
|
109
|
-
return result
|
105
|
+
finally:
|
106
|
+
pass # avoid de-dent all on refactor
|
ansible/plugins/action/script.py
CHANGED
@@ -21,7 +21,7 @@ import pathlib
|
|
21
21
|
import re
|
22
22
|
import shlex
|
23
23
|
|
24
|
-
from ansible.errors import AnsibleError,
|
24
|
+
from ansible.errors import AnsibleError, AnsibleActionFail, AnsibleActionSkip
|
25
25
|
from ansible.executor.powershell import module_manifest as ps_manifest
|
26
26
|
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
|
27
27
|
from ansible.plugins.action import ActionBase
|
@@ -53,7 +53,7 @@ class ActionModule(ActionBase):
|
|
53
53
|
mutually_exclusive=[['_raw_params', 'cmd']],
|
54
54
|
)
|
55
55
|
|
56
|
-
|
56
|
+
super(ActionModule, self).run(tmp, task_vars)
|
57
57
|
del tmp # tmp no longer has any effect
|
58
58
|
|
59
59
|
try:
|
@@ -105,16 +105,11 @@ class ActionModule(ActionBase):
|
|
105
105
|
# check mode is supported if 'creates' or 'removes' are provided
|
106
106
|
# the task has already been skipped if a change would not occur
|
107
107
|
if new_module_args['creates'] or new_module_args['removes']:
|
108
|
-
|
109
|
-
raise _AnsibleActionDone(result=result)
|
108
|
+
return dict(changed=True)
|
110
109
|
# If the script doesn't return changed in the result, it defaults to True,
|
111
110
|
# but since the script may override 'changed', just skip instead of guessing.
|
112
111
|
else:
|
113
|
-
|
114
|
-
raise AnsibleActionSkip('Check mode is not supported for this task.', result=result)
|
115
|
-
|
116
|
-
# now we execute script, always assume changed.
|
117
|
-
result['changed'] = True
|
112
|
+
raise AnsibleActionSkip('Check mode is not supported for this task.', result=dict(changed=False))
|
118
113
|
|
119
114
|
# transfer the file to a remote tmp location
|
120
115
|
tmp_src = self._connection._shell.join_path(self._connection._shell.tmpdir,
|
@@ -168,14 +163,12 @@ class ActionModule(ActionBase):
|
|
168
163
|
# full manual exec of KEEP_REMOTE_FILES
|
169
164
|
script_cmd = self._connection._shell.build_module_command(env_string='', shebang='#!powershell', cmd='')
|
170
165
|
|
171
|
-
|
166
|
+
# 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)
|
172
168
|
|
173
169
|
if 'rc' in result and result['rc'] != 0:
|
174
|
-
raise AnsibleActionFail('non-zero return code')
|
170
|
+
raise AnsibleActionFail('non-zero return code', result=result)
|
175
171
|
|
176
|
-
|
177
|
-
result.update(e.result)
|
172
|
+
return result
|
178
173
|
finally:
|
179
174
|
self._remove_tmp_path(self._connection._shell.tmpdir)
|
180
|
-
|
181
|
-
return result
|
@@ -16,7 +16,7 @@
|
|
16
16
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
from __future__ import annotations
|
18
18
|
|
19
|
-
from ansible.errors import
|
19
|
+
from ansible.errors import AnsibleActionFail
|
20
20
|
from ansible.executor.module_common import _apply_action_arg_defaults
|
21
21
|
from ansible.plugins.action import ActionBase
|
22
22
|
|
@@ -39,7 +39,7 @@ class ActionModule(ActionBase):
|
|
39
39
|
self._supports_check_mode = True
|
40
40
|
self._supports_async = True
|
41
41
|
|
42
|
-
|
42
|
+
super(ActionModule, self).run(tmp, task_vars)
|
43
43
|
del tmp # tmp no longer has any effect
|
44
44
|
|
45
45
|
module = self._task.args.get('use', 'auto').lower()
|
@@ -84,14 +84,10 @@ class ActionModule(ActionBase):
|
|
84
84
|
module = 'ansible.legacy.' + module
|
85
85
|
|
86
86
|
self._display.vvvv("Running %s" % module)
|
87
|
-
|
87
|
+
return self._execute_module(module_name=module, module_args=new_module_args, task_vars=task_vars, wrap_async=self._task.async_val)
|
88
88
|
else:
|
89
89
|
raise AnsibleActionFail('Could not detect which service manager to use. Try gathering facts or setting the "use" option.')
|
90
90
|
|
91
|
-
except AnsibleAction as e:
|
92
|
-
result.update(e.result)
|
93
91
|
finally:
|
94
92
|
if not self._task.async_val:
|
95
93
|
self._remove_tmp_path(self._connection._shell.tmpdir)
|
96
|
-
|
97
|
-
return result
|
@@ -20,7 +20,7 @@ from jinja2.defaults import (
|
|
20
20
|
|
21
21
|
from ansible import constants as C
|
22
22
|
from ansible.config.manager import ensure_type
|
23
|
-
from ansible.errors import AnsibleError,
|
23
|
+
from ansible.errors import AnsibleError, AnsibleActionFail
|
24
24
|
from ansible.module_utils.common.text.converters import to_bytes, to_text, to_native
|
25
25
|
from ansible.module_utils.parsing.convert_bool import boolean
|
26
26
|
from ansible.module_utils.six import string_types
|
@@ -39,7 +39,7 @@ class ActionModule(ActionBase):
|
|
39
39
|
if task_vars is None:
|
40
40
|
task_vars = dict()
|
41
41
|
|
42
|
-
|
42
|
+
super(ActionModule, self).run(tmp, task_vars)
|
43
43
|
del tmp # tmp no longer has any effect
|
44
44
|
|
45
45
|
# Options type validation
|
@@ -132,6 +132,9 @@ class ActionModule(ActionBase):
|
|
132
132
|
data_templar = self._templar.copy_with_new_env(searchpath=searchpath, available_variables=temp_vars)
|
133
133
|
resultant = data_templar.template(template_data, escape_backslashes=False, overrides=overrides)
|
134
134
|
|
135
|
+
if resultant is None:
|
136
|
+
resultant = ''
|
137
|
+
|
135
138
|
new_task = self._task.copy()
|
136
139
|
# mode is either the mode from task.args or the mode of the source file if the task.args
|
137
140
|
# mode == 'preserve'
|
@@ -164,13 +167,8 @@ class ActionModule(ActionBase):
|
|
164
167
|
loader=self._loader,
|
165
168
|
templar=self._templar,
|
166
169
|
shared_loader_obj=self._shared_loader_obj)
|
167
|
-
|
170
|
+
return copy_action.run(task_vars=task_vars)
|
168
171
|
finally:
|
169
172
|
shutil.rmtree(to_bytes(local_tempdir, errors='surrogate_or_strict'))
|
170
|
-
|
171
|
-
except AnsibleAction as e:
|
172
|
-
result.update(e.result)
|
173
173
|
finally:
|
174
174
|
self._remove_tmp_path(self._connection._shell.tmpdir)
|
175
|
-
|
176
|
-
return result
|
@@ -19,8 +19,7 @@ from __future__ import annotations
|
|
19
19
|
|
20
20
|
import os
|
21
21
|
|
22
|
-
from ansible.errors import
|
23
|
-
from ansible.module_utils.common.text.converters import to_text
|
22
|
+
from ansible.errors import AnsibleActionFail, AnsibleActionSkip
|
24
23
|
from ansible.module_utils.parsing.convert_bool import boolean
|
25
24
|
from ansible.plugins.action import ActionBase
|
26
25
|
|
@@ -34,7 +33,7 @@ class ActionModule(ActionBase):
|
|
34
33
|
if task_vars is None:
|
35
34
|
task_vars = dict()
|
36
35
|
|
37
|
-
|
36
|
+
super(ActionModule, self).run(tmp, task_vars)
|
38
37
|
del tmp # tmp no longer has any effect
|
39
38
|
|
40
39
|
source = self._task.args.get('src', None)
|
@@ -68,15 +67,9 @@ class ActionModule(ActionBase):
|
|
68
67
|
source = os.path.expanduser(source)
|
69
68
|
|
70
69
|
if not remote_src:
|
71
|
-
|
72
|
-
source = self._loader.get_real_file(self._find_needle('files', source), decrypt=decrypt)
|
73
|
-
except AnsibleError as e:
|
74
|
-
raise AnsibleActionFail(to_text(e))
|
70
|
+
source = self._loader.get_real_file(self._find_needle('files', source), decrypt=decrypt)
|
75
71
|
|
76
|
-
|
77
|
-
remote_stat = self._execute_remote_stat(dest, all_vars=task_vars, follow=True)
|
78
|
-
except AnsibleError as e:
|
79
|
-
raise AnsibleActionFail(to_text(e))
|
72
|
+
remote_stat = self._execute_remote_stat(dest, all_vars=task_vars, follow=True)
|
80
73
|
|
81
74
|
if not remote_stat['exists'] or not remote_stat['isdir']:
|
82
75
|
raise AnsibleActionFail("dest '%s' must be an existing dir" % dest)
|
@@ -102,9 +95,6 @@ class ActionModule(ActionBase):
|
|
102
95
|
|
103
96
|
# execute the unarchive module now, with the updated args (using ansible.legacy prefix to eliminate collections
|
104
97
|
# collisions with local override
|
105
|
-
|
106
|
-
except AnsibleAction as e:
|
107
|
-
result.update(e.result)
|
98
|
+
return self._execute_module(module_name='ansible.legacy.unarchive', module_args=new_module_args, task_vars=task_vars)
|
108
99
|
finally:
|
109
100
|
self._remove_tmp_path(self._connection._shell.tmpdir)
|
110
|
-
return result
|
ansible/plugins/action/uri.py
CHANGED
@@ -5,11 +5,10 @@
|
|
5
5
|
|
6
6
|
from __future__ import annotations
|
7
7
|
|
8
|
+
import collections.abc as _c
|
8
9
|
import os
|
9
10
|
|
10
|
-
from ansible.errors import
|
11
|
-
from ansible.module_utils.common.text.converters import to_native
|
12
|
-
from ansible.module_utils.common.collections import Mapping, MutableMapping
|
11
|
+
from ansible.errors import AnsibleActionFail
|
13
12
|
from ansible.module_utils.parsing.convert_bool import boolean
|
14
13
|
from ansible.plugins.action import ActionBase
|
15
14
|
|
@@ -25,7 +24,7 @@ class ActionModule(ActionBase):
|
|
25
24
|
if task_vars is None:
|
26
25
|
task_vars = dict()
|
27
26
|
|
28
|
-
|
27
|
+
super(ActionModule, self).run(tmp, task_vars)
|
29
28
|
del tmp # tmp no longer has any effect
|
30
29
|
|
31
30
|
body_format = self._task.args.get('body_format', 'raw')
|
@@ -38,38 +37,31 @@ class ActionModule(ActionBase):
|
|
38
37
|
# everything is remote, so we just execute the module
|
39
38
|
# without changing any of the module arguments
|
40
39
|
# call with ansible.legacy prefix to prevent collections collisions while allowing local override
|
41
|
-
|
42
|
-
task_vars=task_vars, wrap_async=self._task.async_val))
|
40
|
+
return self._execute_module(module_name='ansible.legacy.uri', task_vars=task_vars, wrap_async=self._task.async_val)
|
43
41
|
|
44
42
|
kwargs = {}
|
45
43
|
|
46
44
|
if src:
|
47
|
-
|
48
|
-
src = self._find_needle('files', src)
|
49
|
-
except AnsibleError as e:
|
50
|
-
raise AnsibleActionFail(to_native(e))
|
45
|
+
src = self._find_needle('files', src)
|
51
46
|
|
52
47
|
tmp_src = self._connection._shell.join_path(self._connection._shell.tmpdir, os.path.basename(src))
|
53
48
|
kwargs['src'] = tmp_src
|
54
49
|
self._transfer_file(src, tmp_src)
|
55
50
|
self._fixup_perms2((self._connection._shell.tmpdir, tmp_src))
|
56
51
|
elif body_format == 'form-multipart':
|
57
|
-
if not isinstance(body, Mapping):
|
52
|
+
if not isinstance(body, _c.Mapping):
|
58
53
|
raise AnsibleActionFail(
|
59
54
|
'body must be mapping, cannot be type %s' % body.__class__.__name__
|
60
55
|
)
|
61
56
|
for field, value in body.items():
|
62
|
-
if not isinstance(value, MutableMapping):
|
57
|
+
if not isinstance(value, _c.MutableMapping):
|
63
58
|
continue
|
64
59
|
content = value.get('content')
|
65
60
|
filename = value.get('filename')
|
66
61
|
if not filename or content:
|
67
62
|
continue
|
68
63
|
|
69
|
-
|
70
|
-
filename = self._find_needle('files', filename)
|
71
|
-
except AnsibleError as e:
|
72
|
-
raise AnsibleActionFail(to_native(e))
|
64
|
+
filename = self._find_needle('files', filename)
|
73
65
|
|
74
66
|
tmp_src = self._connection._shell.join_path(
|
75
67
|
self._connection._shell.tmpdir,
|
@@ -83,10 +75,7 @@ class ActionModule(ActionBase):
|
|
83
75
|
new_module_args = self._task.args | kwargs
|
84
76
|
|
85
77
|
# call with ansible.legacy prefix to prevent collections collisions while allowing local override
|
86
|
-
|
87
|
-
except AnsibleAction as e:
|
88
|
-
result.update(e.result)
|
78
|
+
return self._execute_module('ansible.legacy.uri', module_args=new_module_args, task_vars=task_vars, wrap_async=self._task.async_val)
|
89
79
|
finally:
|
90
80
|
if not self._task.async_val:
|
91
81
|
self._remove_tmp_path(self._connection._shell.tmpdir)
|
92
|
-
return result
|