ansible-core 2.18.7rc1__py3-none-any.whl → 2.19.0__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.

Potentially problematic release.


This version of ansible-core might be problematic. Click here for more details.

Files changed (757) hide show
  1. ansible/_internal/__init__.py +53 -0
  2. ansible/_internal/_ansiballz/__init__.py +0 -0
  3. ansible/_internal/_ansiballz/_builder.py +101 -0
  4. ansible/_internal/_ansiballz/_wrapper.py +262 -0
  5. ansible/_internal/_collection_proxy.py +47 -0
  6. ansible/_internal/_datatag/__init__.py +0 -0
  7. ansible/_internal/_datatag/_tags.py +130 -0
  8. ansible/_internal/_datatag/_utils.py +19 -0
  9. ansible/_internal/_datatag/_wrappers.py +33 -0
  10. ansible/_internal/_errors/__init__.py +0 -0
  11. ansible/_internal/_errors/_alarm_timeout.py +66 -0
  12. ansible/_internal/_errors/_captured.py +123 -0
  13. ansible/_internal/_errors/_error_factory.py +89 -0
  14. ansible/_internal/_errors/_error_utils.py +240 -0
  15. ansible/_internal/_errors/_handler.py +91 -0
  16. ansible/_internal/_errors/_task_timeout.py +28 -0
  17. ansible/_internal/_event_formatting.py +127 -0
  18. ansible/_internal/_json/__init__.py +214 -0
  19. ansible/_internal/_json/_legacy_encoder.py +34 -0
  20. ansible/_internal/_json/_profiles/__init__.py +0 -0
  21. ansible/_internal/_json/_profiles/_cache_persistence.py +57 -0
  22. ansible/_internal/_json/_profiles/_inventory_legacy.py +40 -0
  23. ansible/_internal/_json/_profiles/_legacy.py +189 -0
  24. ansible/_internal/_locking.py +21 -0
  25. ansible/_internal/_plugins/__init__.py +0 -0
  26. ansible/_internal/_plugins/_cache.py +57 -0
  27. ansible/_internal/_ssh/__init__.py +0 -0
  28. ansible/_internal/_ssh/_agent_launch.py +91 -0
  29. ansible/_internal/_ssh/_ssh_agent.py +619 -0
  30. ansible/_internal/_task.py +78 -0
  31. ansible/_internal/_templating/__init__.py +12 -0
  32. ansible/_internal/_templating/_access.py +86 -0
  33. ansible/_internal/_templating/_chain_templar.py +63 -0
  34. ansible/_internal/_templating/_datatag.py +95 -0
  35. ansible/_internal/_templating/_engine.py +592 -0
  36. ansible/_internal/_templating/_errors.py +28 -0
  37. ansible/_internal/_templating/_jinja_bits.py +1106 -0
  38. ansible/_internal/_templating/_jinja_common.py +323 -0
  39. ansible/_internal/_templating/_jinja_patches.py +44 -0
  40. ansible/_internal/_templating/_jinja_plugins.py +375 -0
  41. ansible/_internal/_templating/_lazy_containers.py +633 -0
  42. ansible/_internal/_templating/_marker_behaviors.py +103 -0
  43. ansible/_internal/_templating/_template_vars.py +72 -0
  44. ansible/_internal/_templating/_transform.py +70 -0
  45. ansible/_internal/_templating/_utils.py +108 -0
  46. ansible/_internal/_testing.py +26 -0
  47. ansible/_internal/_wrapt.py +1052 -0
  48. ansible/_internal/_yaml/__init__.py +0 -0
  49. ansible/_internal/_yaml/_constructor.py +240 -0
  50. ansible/_internal/_yaml/_dumper.py +70 -0
  51. ansible/_internal/_yaml/_errors.py +166 -0
  52. ansible/_internal/_yaml/_loader.py +66 -0
  53. ansible/_internal/ansible_collections/ansible/_protomatter/README.md +11 -0
  54. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/debug.py +36 -0
  55. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/apply_trust.py +19 -0
  56. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py +27 -0
  57. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/finalize.py +16 -0
  58. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/origin.py +18 -0
  59. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.py +24 -0
  60. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.yml +33 -0
  61. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/tag_names.py +16 -0
  62. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +17 -0
  63. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +49 -0
  64. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.py +21 -0
  65. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.yml +2 -0
  66. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.py +15 -0
  67. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.yml +19 -0
  68. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.py +18 -0
  69. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.yml +19 -0
  70. ansible/cli/__init__.py +93 -104
  71. ansible/cli/_ssh_askpass.py +54 -0
  72. ansible/cli/adhoc.py +20 -10
  73. ansible/cli/arguments/option_helpers.py +163 -10
  74. ansible/cli/config.py +43 -68
  75. ansible/cli/console.py +13 -11
  76. ansible/cli/doc.py +134 -77
  77. ansible/cli/galaxy.py +27 -20
  78. ansible/cli/inventory.py +28 -28
  79. ansible/cli/playbook.py +4 -12
  80. ansible/cli/pull.py +6 -3
  81. ansible/cli/scripts/ansible_connection_cli_stub.py +7 -7
  82. ansible/cli/vault.py +12 -11
  83. ansible/compat/__init__.py +2 -2
  84. ansible/compat/importlib_resources.py +9 -12
  85. ansible/config/base.yml +218 -133
  86. ansible/config/manager.py +220 -159
  87. ansible/constants.py +2 -65
  88. ansible/errors/__init__.py +350 -256
  89. ansible/executor/interpreter_discovery.py +28 -149
  90. ansible/executor/module_common.py +480 -514
  91. ansible/executor/play_iterator.py +22 -27
  92. ansible/executor/playbook_executor.py +11 -11
  93. ansible/executor/powershell/async_watchdog.ps1 +97 -102
  94. ansible/executor/powershell/async_wrapper.ps1 +204 -153
  95. ansible/executor/powershell/become_wrapper.ps1 +107 -144
  96. ansible/executor/powershell/bootstrap_wrapper.ps1 +46 -9
  97. ansible/executor/powershell/coverage_wrapper.ps1 +91 -135
  98. ansible/executor/powershell/exec_wrapper.ps1 +675 -196
  99. ansible/executor/powershell/module_manifest.py +469 -265
  100. ansible/executor/powershell/module_wrapper.ps1 +195 -186
  101. ansible/executor/powershell/powershell_expand_user.ps1 +20 -0
  102. ansible/executor/powershell/powershell_mkdtemp.ps1 +17 -0
  103. ansible/executor/powershell/psrp_fetch_file.ps1 +41 -0
  104. ansible/executor/powershell/psrp_put_file.ps1 +122 -0
  105. ansible/executor/powershell/winrm_fetch_file.ps1 +46 -0
  106. ansible/executor/powershell/winrm_put_file.ps1 +36 -0
  107. ansible/executor/process/worker.py +139 -149
  108. ansible/executor/stats.py +5 -5
  109. ansible/executor/task_executor.py +270 -297
  110. ansible/executor/task_queue_manager.py +135 -137
  111. ansible/executor/task_result.py +182 -79
  112. ansible/galaxy/__init__.py +2 -2
  113. ansible/galaxy/api.py +26 -25
  114. ansible/galaxy/collection/__init__.py +6 -14
  115. ansible/galaxy/collection/concrete_artifact_manager.py +12 -21
  116. ansible/galaxy/dependency_resolution/dataclasses.py +14 -4
  117. ansible/galaxy/dependency_resolution/providers.py +4 -4
  118. ansible/galaxy/dependency_resolution/reporters.py +81 -0
  119. ansible/galaxy/role.py +6 -10
  120. ansible/galaxy/token.py +28 -21
  121. ansible/inventory/data.py +47 -57
  122. ansible/inventory/group.py +50 -73
  123. ansible/inventory/helpers.py +9 -0
  124. ansible/inventory/host.py +37 -54
  125. ansible/inventory/manager.py +79 -34
  126. ansible/keyword_desc.yml +1 -1
  127. ansible/module_utils/_internal/__init__.py +55 -0
  128. ansible/module_utils/_internal/_ambient_context.py +58 -0
  129. ansible/module_utils/_internal/_ansiballz/__init__.py +0 -0
  130. ansible/module_utils/_internal/_ansiballz/_extensions/__init__.py +0 -0
  131. ansible/module_utils/_internal/_ansiballz/_extensions/_coverage.py +45 -0
  132. ansible/module_utils/_internal/_ansiballz/_extensions/_pydevd.py +62 -0
  133. ansible/module_utils/_internal/_ansiballz/_loader.py +81 -0
  134. ansible/module_utils/_internal/_ansiballz/_respawn.py +32 -0
  135. ansible/module_utils/_internal/_ansiballz/_respawn_wrapper.py +23 -0
  136. ansible/module_utils/_internal/_concurrent/_daemon_threading.py +1 -0
  137. ansible/module_utils/_internal/_dataclass_validation.py +217 -0
  138. ansible/module_utils/_internal/_datatag/__init__.py +961 -0
  139. ansible/module_utils/_internal/_datatag/_tags.py +16 -0
  140. ansible/module_utils/_internal/_debugging.py +31 -0
  141. ansible/module_utils/_internal/_deprecator.py +157 -0
  142. ansible/module_utils/_internal/_errors.py +101 -0
  143. ansible/module_utils/_internal/_event_utils.py +61 -0
  144. ansible/module_utils/_internal/_json/__init__.py +63 -0
  145. ansible/module_utils/_internal/_json/_legacy_encoder.py +26 -0
  146. ansible/module_utils/_internal/_json/_profiles/__init__.py +428 -0
  147. ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py +73 -0
  148. ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +33 -0
  149. ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +37 -0
  150. ansible/module_utils/_internal/_json/_profiles/_module_modern_c2m.py +35 -0
  151. ansible/module_utils/_internal/_json/_profiles/_module_modern_m2c.py +33 -0
  152. ansible/module_utils/_internal/_json/_profiles/_tagless.py +52 -0
  153. ansible/module_utils/_internal/_messages.py +130 -0
  154. ansible/module_utils/_internal/_patches/__init__.py +66 -0
  155. ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +53 -0
  156. ansible/module_utils/_internal/_patches/_socket_patch.py +34 -0
  157. ansible/module_utils/_internal/_patches/_sys_intern_patch.py +34 -0
  158. ansible/module_utils/_internal/_plugin_info.py +38 -0
  159. ansible/module_utils/_internal/_stack.py +22 -0
  160. ansible/module_utils/_internal/_testing.py +0 -0
  161. ansible/module_utils/_internal/_text_utils.py +6 -0
  162. ansible/module_utils/_internal/_traceback.py +92 -0
  163. ansible/module_utils/_internal/_validation.py +14 -0
  164. ansible/module_utils/ansible_release.py +2 -2
  165. ansible/module_utils/api.py +1 -2
  166. ansible/module_utils/basic.py +303 -202
  167. ansible/module_utils/common/_utils.py +24 -28
  168. ansible/module_utils/common/arg_spec.py +8 -3
  169. ansible/module_utils/common/collections.py +7 -2
  170. ansible/module_utils/common/dict_transformations.py +2 -2
  171. ansible/module_utils/common/file.py +2 -2
  172. ansible/module_utils/common/json.py +90 -84
  173. ansible/module_utils/common/locale.py +2 -2
  174. ansible/module_utils/common/parameters.py +27 -24
  175. ansible/module_utils/common/process.py +2 -3
  176. ansible/module_utils/common/respawn.py +11 -33
  177. ansible/module_utils/common/sentinel.py +66 -0
  178. ansible/module_utils/common/sys_info.py +8 -8
  179. ansible/module_utils/common/text/converters.py +16 -37
  180. ansible/module_utils/common/validation.py +35 -24
  181. ansible/module_utils/common/warnings.py +143 -25
  182. ansible/module_utils/common/yaml.py +29 -3
  183. ansible/module_utils/compat/datetime.py +33 -21
  184. ansible/module_utils/compat/paramiko.py +21 -10
  185. ansible/module_utils/compat/typing.py +6 -5
  186. ansible/module_utils/connection.py +10 -13
  187. ansible/module_utils/csharp/Ansible.Basic.cs +15 -12
  188. ansible/module_utils/csharp/Ansible.Become.cs +1 -0
  189. ansible/module_utils/csharp/Ansible.Privilege.cs +2 -2
  190. ansible/module_utils/csharp/Ansible._Async.cs +517 -0
  191. ansible/module_utils/datatag.py +49 -0
  192. ansible/module_utils/distro/__init__.py +2 -2
  193. ansible/module_utils/facts/ansible_collector.py +4 -5
  194. ansible/module_utils/facts/collector.py +13 -14
  195. ansible/module_utils/facts/compat.py +4 -4
  196. ansible/module_utils/facts/default_collectors.py +1 -1
  197. ansible/module_utils/facts/hardware/aix.py +34 -0
  198. ansible/module_utils/facts/hardware/base.py +2 -2
  199. ansible/module_utils/facts/hardware/darwin.py +1 -3
  200. ansible/module_utils/facts/hardware/freebsd.py +2 -2
  201. ansible/module_utils/facts/hardware/linux.py +5 -5
  202. ansible/module_utils/facts/namespace.py +1 -1
  203. ansible/module_utils/facts/network/base.py +1 -1
  204. ansible/module_utils/facts/network/fc_wwn.py +1 -2
  205. ansible/module_utils/facts/network/iscsi.py +1 -2
  206. ansible/module_utils/facts/network/nvme.py +1 -2
  207. ansible/module_utils/facts/other/facter.py +2 -3
  208. ansible/module_utils/facts/other/ohai.py +2 -3
  209. ansible/module_utils/facts/sysctl.py +4 -6
  210. ansible/module_utils/facts/system/apparmor.py +1 -2
  211. ansible/module_utils/facts/system/caps.py +3 -3
  212. ansible/module_utils/facts/system/chroot.py +1 -2
  213. ansible/module_utils/facts/system/cmdline.py +1 -2
  214. ansible/module_utils/facts/system/date_time.py +5 -3
  215. ansible/module_utils/facts/system/distribution.py +27 -13
  216. ansible/module_utils/facts/system/dns.py +1 -1
  217. ansible/module_utils/facts/system/env.py +1 -2
  218. ansible/module_utils/facts/system/fips.py +7 -20
  219. ansible/module_utils/facts/system/loadavg.py +1 -2
  220. ansible/module_utils/facts/system/local.py +2 -3
  221. ansible/module_utils/facts/system/lsb.py +1 -2
  222. ansible/module_utils/facts/system/pkg_mgr.py +1 -2
  223. ansible/module_utils/facts/system/platform.py +1 -2
  224. ansible/module_utils/facts/system/python.py +1 -2
  225. ansible/module_utils/facts/system/selinux.py +1 -1
  226. ansible/module_utils/facts/system/service_mgr.py +1 -2
  227. ansible/module_utils/facts/system/ssh_pub_keys.py +1 -1
  228. ansible/module_utils/facts/system/systemd.py +1 -1
  229. ansible/module_utils/facts/system/user.py +1 -2
  230. ansible/module_utils/facts/utils.py +3 -3
  231. ansible/module_utils/facts/virtual/base.py +1 -1
  232. ansible/module_utils/facts/virtual/linux.py +3 -3
  233. ansible/module_utils/facts/virtual/sunos.py +3 -15
  234. ansible/module_utils/facts/virtual/sysctl.py +3 -16
  235. ansible/module_utils/json_utils.py +2 -2
  236. ansible/module_utils/parsing/convert_bool.py +7 -1
  237. ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 +1 -1
  238. ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 +1 -1
  239. ansible/module_utils/powershell/Ansible.ModuleUtils.CommandUtil.psm1 +1 -1
  240. ansible/module_utils/powershell/Ansible.ModuleUtils.WebRequest.psm1 +1 -1
  241. ansible/module_utils/service.py +21 -31
  242. ansible/module_utils/splitter.py +7 -7
  243. ansible/module_utils/testing.py +31 -0
  244. ansible/module_utils/urls.py +64 -35
  245. ansible/modules/add_host.py +4 -4
  246. ansible/modules/apt.py +69 -49
  247. ansible/modules/apt_key.py +19 -12
  248. ansible/modules/apt_repository.py +32 -51
  249. ansible/modules/assemble.py +16 -14
  250. ansible/modules/assert.py +4 -4
  251. ansible/modules/async_status.py +24 -24
  252. ansible/modules/async_wrapper.py +20 -25
  253. ansible/modules/blockinfile.py +6 -7
  254. ansible/modules/command.py +13 -20
  255. ansible/modules/copy.py +60 -147
  256. ansible/modules/cron.py +24 -21
  257. ansible/modules/deb822_repository.py +8 -9
  258. ansible/modules/debconf.py +5 -5
  259. ansible/modules/debug.py +4 -4
  260. ansible/modules/dnf.py +8 -8
  261. ansible/modules/dnf5.py +39 -13
  262. ansible/modules/dpkg_selections.py +4 -4
  263. ansible/modules/expect.py +13 -15
  264. ansible/modules/fail.py +4 -4
  265. ansible/modules/fetch.py +4 -4
  266. ansible/modules/file.py +184 -144
  267. ansible/modules/find.py +22 -20
  268. ansible/modules/gather_facts.py +3 -3
  269. ansible/modules/get_url.py +77 -54
  270. ansible/modules/getent.py +7 -9
  271. ansible/modules/git.py +38 -38
  272. ansible/modules/group.py +6 -6
  273. ansible/modules/group_by.py +4 -4
  274. ansible/modules/hostname.py +15 -32
  275. ansible/modules/import_playbook.py +6 -6
  276. ansible/modules/import_role.py +6 -6
  277. ansible/modules/import_tasks.py +6 -6
  278. ansible/modules/include_role.py +6 -6
  279. ansible/modules/include_tasks.py +6 -6
  280. ansible/modules/include_vars.py +6 -6
  281. ansible/modules/iptables.py +86 -73
  282. ansible/modules/known_hosts.py +22 -24
  283. ansible/modules/lineinfile.py +5 -5
  284. ansible/modules/meta.py +4 -4
  285. ansible/modules/mount_facts.py +2 -2
  286. ansible/modules/package.py +10 -4
  287. ansible/modules/package_facts.py +22 -10
  288. ansible/modules/pause.py +6 -6
  289. ansible/modules/ping.py +6 -6
  290. ansible/modules/pip.py +21 -26
  291. ansible/modules/raw.py +6 -6
  292. ansible/modules/reboot.py +6 -6
  293. ansible/modules/replace.py +10 -14
  294. ansible/modules/rpm_key.py +7 -8
  295. ansible/modules/script.py +4 -4
  296. ansible/modules/service.py +10 -17
  297. ansible/modules/service_facts.py +87 -10
  298. ansible/modules/set_fact.py +5 -5
  299. ansible/modules/set_stats.py +4 -4
  300. ansible/modules/setup.py +2 -2
  301. ansible/modules/shell.py +6 -6
  302. ansible/modules/slurp.py +16 -19
  303. ansible/modules/stat.py +15 -31
  304. ansible/modules/subversion.py +15 -15
  305. ansible/modules/systemd.py +7 -7
  306. ansible/modules/systemd_service.py +7 -7
  307. ansible/modules/sysvinit.py +9 -9
  308. ansible/modules/tempfile.py +5 -6
  309. ansible/modules/template.py +6 -6
  310. ansible/modules/unarchive.py +38 -17
  311. ansible/modules/uri.py +33 -26
  312. ansible/modules/user.py +45 -32
  313. ansible/modules/validate_argument_spec.py +10 -7
  314. ansible/modules/wait_for.py +70 -60
  315. ansible/modules/wait_for_connection.py +6 -6
  316. ansible/modules/yum_repository.py +10 -9
  317. ansible/parsing/ajson.py +17 -37
  318. ansible/parsing/dataloader.py +99 -54
  319. ansible/parsing/mod_args.py +62 -60
  320. ansible/parsing/plugin_docs.py +21 -86
  321. ansible/parsing/quoting.py +1 -1
  322. ansible/parsing/splitter.py +27 -12
  323. ansible/parsing/utils/addresses.py +24 -24
  324. ansible/parsing/utils/jsonify.py +5 -1
  325. ansible/parsing/utils/yaml.py +32 -61
  326. ansible/parsing/vault/__init__.py +327 -99
  327. ansible/parsing/yaml/__init__.py +0 -18
  328. ansible/parsing/yaml/dumper.py +6 -120
  329. ansible/parsing/yaml/loader.py +6 -39
  330. ansible/parsing/yaml/objects.py +43 -335
  331. ansible/playbook/__init__.py +1 -1
  332. ansible/playbook/attribute.py +8 -3
  333. ansible/playbook/base.py +187 -134
  334. ansible/playbook/block.py +26 -24
  335. ansible/playbook/collectionsearch.py +1 -15
  336. ansible/playbook/conditional.py +3 -77
  337. ansible/playbook/handler.py +8 -2
  338. ansible/playbook/helpers.py +41 -53
  339. ansible/playbook/included_file.py +32 -26
  340. ansible/playbook/loop_control.py +2 -2
  341. ansible/playbook/play.py +85 -44
  342. ansible/playbook/play_context.py +14 -17
  343. ansible/playbook/playbook_include.py +27 -62
  344. ansible/playbook/role/__init__.py +64 -49
  345. ansible/playbook/role/definition.py +15 -17
  346. ansible/playbook/role/include.py +2 -4
  347. ansible/playbook/role/metadata.py +10 -11
  348. ansible/playbook/role_include.py +3 -3
  349. ansible/playbook/taggable.py +28 -12
  350. ansible/playbook/task.py +192 -121
  351. ansible/playbook/task_include.py +5 -5
  352. ansible/plugins/__init__.py +58 -26
  353. ansible/plugins/action/__init__.py +188 -186
  354. ansible/plugins/action/add_host.py +2 -2
  355. ansible/plugins/action/assemble.py +11 -18
  356. ansible/plugins/action/assert.py +55 -67
  357. ansible/plugins/action/async_status.py +7 -2
  358. ansible/plugins/action/copy.py +14 -17
  359. ansible/plugins/action/debug.py +37 -31
  360. ansible/plugins/action/dnf.py +3 -4
  361. ansible/plugins/action/fail.py +1 -1
  362. ansible/plugins/action/fetch.py +7 -8
  363. ansible/plugins/action/gather_facts.py +13 -14
  364. ansible/plugins/action/group_by.py +1 -1
  365. ansible/plugins/action/include_vars.py +10 -11
  366. ansible/plugins/action/package.py +8 -14
  367. ansible/plugins/action/pause.py +2 -2
  368. ansible/plugins/action/script.py +27 -38
  369. ansible/plugins/action/service.py +9 -18
  370. ansible/plugins/action/set_fact.py +3 -12
  371. ansible/plugins/action/set_stats.py +3 -8
  372. ansible/plugins/action/template.py +47 -67
  373. ansible/plugins/action/unarchive.py +6 -16
  374. ansible/plugins/action/uri.py +9 -20
  375. ansible/plugins/action/validate_argument_spec.py +5 -5
  376. ansible/plugins/action/wait_for_connection.py +1 -1
  377. ansible/plugins/become/__init__.py +31 -8
  378. ansible/plugins/become/runas.py +71 -0
  379. ansible/plugins/become/su.py +13 -8
  380. ansible/plugins/become/sudo.py +19 -0
  381. ansible/plugins/cache/__init__.py +52 -63
  382. ansible/plugins/cache/base.py +8 -0
  383. ansible/plugins/cache/jsonfile.py +10 -16
  384. ansible/plugins/cache/memory.py +6 -12
  385. ansible/plugins/callback/__init__.py +294 -201
  386. ansible/plugins/callback/default.py +99 -95
  387. ansible/plugins/callback/junit.py +44 -43
  388. ansible/plugins/callback/minimal.py +28 -25
  389. ansible/plugins/callback/oneline.py +34 -21
  390. ansible/plugins/callback/tree.py +27 -16
  391. ansible/plugins/connection/__init__.py +47 -34
  392. ansible/plugins/connection/local.py +156 -60
  393. ansible/plugins/connection/paramiko_ssh.py +34 -24
  394. ansible/plugins/connection/psrp.py +76 -165
  395. ansible/plugins/connection/ssh.py +326 -86
  396. ansible/plugins/connection/winrm.py +62 -141
  397. ansible/plugins/doc_fragments/action_common_attributes.py +14 -14
  398. ansible/plugins/doc_fragments/action_core.py +6 -6
  399. ansible/plugins/doc_fragments/backup.py +2 -2
  400. ansible/plugins/doc_fragments/checksum_common.py +27 -0
  401. ansible/plugins/doc_fragments/constructed.py +8 -4
  402. ansible/plugins/doc_fragments/decrypt.py +2 -2
  403. ansible/plugins/doc_fragments/default_callback.py +2 -2
  404. ansible/plugins/doc_fragments/files.py +2 -2
  405. ansible/plugins/doc_fragments/inventory_cache.py +2 -2
  406. ansible/plugins/doc_fragments/result_format_callback.py +2 -2
  407. ansible/plugins/doc_fragments/return_common.py +2 -2
  408. ansible/plugins/doc_fragments/template_common.py +4 -4
  409. ansible/plugins/doc_fragments/url.py +17 -1
  410. ansible/plugins/doc_fragments/url_windows.py +2 -2
  411. ansible/plugins/doc_fragments/validate.py +2 -2
  412. ansible/plugins/doc_fragments/vars_plugin_staging.py +2 -2
  413. ansible/plugins/filter/__init__.py +6 -2
  414. ansible/plugins/filter/b64decode.yml +22 -0
  415. ansible/plugins/filter/b64encode.yml +22 -0
  416. ansible/plugins/filter/bool.yml +11 -4
  417. ansible/plugins/filter/core.py +245 -120
  418. ansible/plugins/filter/encryption.py +42 -34
  419. ansible/plugins/filter/flatten.yml +3 -2
  420. ansible/plugins/filter/human_to_bytes.yml +1 -1
  421. ansible/plugins/filter/mathstuff.py +30 -37
  422. ansible/plugins/filter/password_hash.yml +8 -0
  423. ansible/plugins/filter/pow.yml +1 -1
  424. ansible/plugins/filter/regex_search.yml +1 -4
  425. ansible/plugins/filter/root.yml +1 -1
  426. ansible/plugins/filter/split.yml +1 -1
  427. ansible/plugins/filter/strftime.yml +3 -3
  428. ansible/plugins/filter/to_nice_yaml.yml +0 -4
  429. ansible/plugins/filter/to_uuid.yml +1 -1
  430. ansible/plugins/filter/to_yaml.yml +0 -4
  431. ansible/plugins/filter/unvault.yml +1 -1
  432. ansible/plugins/filter/urls.py +1 -1
  433. ansible/plugins/filter/urlsplit.py +8 -9
  434. ansible/plugins/filter/vault.yml +14 -9
  435. ansible/plugins/filter/win_basename.yml +6 -1
  436. ansible/plugins/filter/win_dirname.yml +5 -0
  437. ansible/plugins/inventory/__init__.py +107 -86
  438. ansible/plugins/inventory/advanced_host_list.py +7 -5
  439. ansible/plugins/inventory/auto.py +11 -4
  440. ansible/plugins/inventory/constructed.py +21 -24
  441. ansible/plugins/inventory/generator.py +16 -11
  442. ansible/plugins/inventory/host_list.py +7 -5
  443. ansible/plugins/inventory/ini.py +78 -44
  444. ansible/plugins/inventory/script.py +190 -120
  445. ansible/plugins/inventory/toml.py +16 -126
  446. ansible/plugins/inventory/yaml.py +10 -8
  447. ansible/plugins/list.py +72 -19
  448. ansible/plugins/loader.py +383 -198
  449. ansible/plugins/lookup/__init__.py +21 -4
  450. ansible/plugins/lookup/config.py +21 -35
  451. ansible/plugins/lookup/csvfile.py +19 -73
  452. ansible/plugins/lookup/dict.py +1 -6
  453. ansible/plugins/lookup/env.py +12 -9
  454. ansible/plugins/lookup/file.py +5 -8
  455. ansible/plugins/lookup/first_found.py +87 -55
  456. ansible/plugins/lookup/indexed_items.py +1 -10
  457. ansible/plugins/lookup/ini.py +14 -13
  458. ansible/plugins/lookup/items.py +1 -1
  459. ansible/plugins/lookup/lines.py +8 -1
  460. ansible/plugins/lookup/list.py +1 -1
  461. ansible/plugins/lookup/nested.py +2 -18
  462. ansible/plugins/lookup/password.py +5 -5
  463. ansible/plugins/lookup/pipe.py +5 -7
  464. ansible/plugins/lookup/sequence.py +18 -8
  465. ansible/plugins/lookup/subelements.py +1 -4
  466. ansible/plugins/lookup/template.py +47 -36
  467. ansible/plugins/lookup/together.py +0 -12
  468. ansible/plugins/lookup/unvault.py +1 -5
  469. ansible/plugins/lookup/url.py +4 -10
  470. ansible/plugins/lookup/vars.py +16 -24
  471. ansible/plugins/shell/__init__.py +58 -4
  472. ansible/plugins/shell/cmd.py +2 -2
  473. ansible/plugins/shell/powershell.py +106 -31
  474. ansible/plugins/shell/sh.py +13 -7
  475. ansible/plugins/strategy/__init__.py +168 -193
  476. ansible/plugins/strategy/debug.py +2 -2
  477. ansible/plugins/strategy/free.py +16 -31
  478. ansible/plugins/strategy/host_pinned.py +2 -2
  479. ansible/plugins/strategy/linear.py +41 -41
  480. ansible/plugins/terminal/__init__.py +4 -4
  481. ansible/plugins/test/__init__.py +7 -2
  482. ansible/plugins/test/core.py +75 -35
  483. ansible/plugins/test/files.py +1 -1
  484. ansible/plugins/test/finished.yml +1 -1
  485. ansible/plugins/test/mathstuff.py +3 -3
  486. ansible/plugins/test/uri.py +5 -8
  487. ansible/plugins/vars/host_group_vars.py +7 -14
  488. ansible/release.py +2 -2
  489. ansible/template/__init__.py +353 -943
  490. ansible/utils/__init__.py +0 -18
  491. ansible/utils/collection_loader/__init__.py +54 -5
  492. ansible/utils/collection_loader/_collection_config.py +5 -6
  493. ansible/utils/collection_loader/_collection_finder.py +82 -96
  494. ansible/utils/collection_loader/_collection_meta.py +15 -8
  495. ansible/utils/display.py +485 -73
  496. ansible/utils/encrypt.py +27 -19
  497. ansible/utils/fqcn.py +2 -2
  498. ansible/utils/galaxy.py +2 -2
  499. ansible/utils/hashing.py +8 -10
  500. ansible/utils/helpers.py +2 -2
  501. ansible/utils/listify.py +10 -8
  502. ansible/utils/lock.py +2 -2
  503. ansible/utils/path.py +10 -12
  504. ansible/utils/plugin_docs.py +16 -14
  505. ansible/utils/py3compat.py +2 -7
  506. ansible/utils/sentinel.py +4 -62
  507. ansible/utils/singleton.py +2 -0
  508. ansible/utils/ssh_functions.py +6 -2
  509. ansible/utils/unsafe_proxy.py +23 -332
  510. ansible/utils/vars.py +55 -8
  511. ansible/utils/version.py +2 -2
  512. ansible/vars/clean.py +5 -5
  513. ansible/vars/hostvars.py +60 -90
  514. ansible/vars/manager.py +220 -285
  515. ansible/vars/plugins.py +4 -4
  516. ansible/vars/reserved.py +13 -12
  517. {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/METADATA +4 -3
  518. ansible_core-2.19.0.dist-info/RECORD +1097 -0
  519. ansible_core-2.19.0.dist-info/licenses/licenses/BSD-3-Clause.txt +28 -0
  520. ansible_test/_data/completion/docker.txt +7 -7
  521. ansible_test/_data/completion/remote.txt +6 -6
  522. ansible_test/_data/completion/windows.txt +1 -0
  523. ansible_test/_data/requirements/ansible.txt +2 -2
  524. ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
  525. ansible_test/_data/requirements/sanity.changelog.txt +2 -2
  526. ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
  527. ansible_test/_data/requirements/sanity.pep8.txt +1 -1
  528. ansible_test/_data/requirements/sanity.pylint.txt +5 -5
  529. ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
  530. ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
  531. ansible_test/_data/requirements/units.txt +1 -0
  532. ansible_test/_internal/__init__.py +6 -0
  533. ansible_test/_internal/ansible_util.py +3 -1
  534. ansible_test/_internal/become.py +1 -0
  535. ansible_test/_internal/bootstrap.py +1 -0
  536. ansible_test/_internal/cache.py +1 -0
  537. ansible_test/_internal/cgroup.py +1 -0
  538. ansible_test/_internal/ci/__init__.py +1 -0
  539. ansible_test/_internal/ci/azp.py +1 -0
  540. ansible_test/_internal/ci/local.py +1 -0
  541. ansible_test/_internal/classification/__init__.py +1 -0
  542. ansible_test/_internal/classification/common.py +1 -0
  543. ansible_test/_internal/classification/csharp.py +1 -0
  544. ansible_test/_internal/classification/powershell.py +1 -0
  545. ansible_test/_internal/classification/python.py +1 -0
  546. ansible_test/_internal/cli/__init__.py +1 -0
  547. ansible_test/_internal/cli/actions.py +1 -0
  548. ansible_test/_internal/cli/argparsing/__init__.py +1 -0
  549. ansible_test/_internal/cli/argparsing/actions.py +1 -0
  550. ansible_test/_internal/cli/argparsing/argcompletion.py +1 -0
  551. ansible_test/_internal/cli/argparsing/parsers.py +1 -0
  552. ansible_test/_internal/cli/commands/__init__.py +11 -5
  553. ansible_test/_internal/cli/commands/coverage/__init__.py +1 -0
  554. ansible_test/_internal/cli/commands/coverage/analyze/__init__.py +1 -0
  555. ansible_test/_internal/cli/commands/coverage/analyze/targets/__init__.py +1 -0
  556. ansible_test/_internal/cli/commands/coverage/analyze/targets/combine.py +1 -0
  557. ansible_test/_internal/cli/commands/coverage/analyze/targets/expand.py +1 -0
  558. ansible_test/_internal/cli/commands/coverage/analyze/targets/filter.py +1 -0
  559. ansible_test/_internal/cli/commands/coverage/analyze/targets/generate.py +1 -0
  560. ansible_test/_internal/cli/commands/coverage/analyze/targets/missing.py +1 -0
  561. ansible_test/_internal/cli/commands/coverage/combine.py +1 -0
  562. ansible_test/_internal/cli/commands/coverage/erase.py +1 -0
  563. ansible_test/_internal/cli/commands/coverage/html.py +1 -0
  564. ansible_test/_internal/cli/commands/coverage/report.py +1 -0
  565. ansible_test/_internal/cli/commands/coverage/xml.py +1 -0
  566. ansible_test/_internal/cli/commands/env.py +1 -0
  567. ansible_test/_internal/cli/commands/integration/__init__.py +1 -0
  568. ansible_test/_internal/cli/commands/integration/network.py +1 -0
  569. ansible_test/_internal/cli/commands/integration/posix.py +1 -0
  570. ansible_test/_internal/cli/commands/integration/windows.py +1 -0
  571. ansible_test/_internal/cli/commands/sanity.py +9 -0
  572. ansible_test/_internal/cli/commands/shell.py +1 -0
  573. ansible_test/_internal/cli/commands/units.py +1 -0
  574. ansible_test/_internal/cli/compat.py +1 -0
  575. ansible_test/_internal/cli/completers.py +1 -0
  576. ansible_test/_internal/cli/converters.py +1 -0
  577. ansible_test/_internal/cli/environments.py +52 -5
  578. ansible_test/_internal/cli/epilog.py +1 -0
  579. ansible_test/_internal/cli/parsers/__init__.py +1 -0
  580. ansible_test/_internal/cli/parsers/base_argument_parsers.py +1 -0
  581. ansible_test/_internal/cli/parsers/helpers.py +1 -0
  582. ansible_test/_internal/cli/parsers/host_config_parsers.py +1 -0
  583. ansible_test/_internal/cli/parsers/key_value_parsers.py +1 -0
  584. ansible_test/_internal/cli/parsers/value_parsers.py +1 -0
  585. ansible_test/_internal/commands/__init__.py +1 -0
  586. ansible_test/_internal/commands/coverage/__init__.py +3 -2
  587. ansible_test/_internal/commands/coverage/analyze/__init__.py +1 -0
  588. ansible_test/_internal/commands/coverage/analyze/targets/__init__.py +1 -0
  589. ansible_test/_internal/commands/coverage/analyze/targets/combine.py +1 -0
  590. ansible_test/_internal/commands/coverage/analyze/targets/expand.py +1 -0
  591. ansible_test/_internal/commands/coverage/analyze/targets/filter.py +1 -0
  592. ansible_test/_internal/commands/coverage/analyze/targets/generate.py +1 -0
  593. ansible_test/_internal/commands/coverage/analyze/targets/missing.py +1 -0
  594. ansible_test/_internal/commands/coverage/combine.py +2 -1
  595. ansible_test/_internal/commands/coverage/erase.py +1 -0
  596. ansible_test/_internal/commands/coverage/html.py +1 -0
  597. ansible_test/_internal/commands/coverage/report.py +1 -0
  598. ansible_test/_internal/commands/coverage/xml.py +1 -0
  599. ansible_test/_internal/commands/env/__init__.py +2 -0
  600. ansible_test/_internal/commands/integration/__init__.py +22 -5
  601. ansible_test/_internal/commands/integration/cloud/__init__.py +1 -0
  602. ansible_test/_internal/commands/integration/cloud/acme.py +2 -1
  603. ansible_test/_internal/commands/integration/cloud/aws.py +1 -0
  604. ansible_test/_internal/commands/integration/cloud/azure.py +1 -0
  605. ansible_test/_internal/commands/integration/cloud/cs.py +1 -0
  606. ansible_test/_internal/commands/integration/cloud/digitalocean.py +1 -0
  607. ansible_test/_internal/commands/integration/cloud/galaxy.py +3 -2
  608. ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -0
  609. ansible_test/_internal/commands/integration/cloud/httptester.py +3 -2
  610. ansible_test/_internal/commands/integration/cloud/nios.py +2 -1
  611. ansible_test/_internal/commands/integration/cloud/opennebula.py +1 -0
  612. ansible_test/_internal/commands/integration/cloud/openshift.py +1 -0
  613. ansible_test/_internal/commands/integration/cloud/scaleway.py +1 -0
  614. ansible_test/_internal/commands/integration/cloud/vcenter.py +1 -0
  615. ansible_test/_internal/commands/integration/cloud/vultr.py +1 -0
  616. ansible_test/_internal/commands/integration/coverage.py +8 -2
  617. ansible_test/_internal/commands/integration/filters.py +1 -0
  618. ansible_test/_internal/commands/integration/network.py +1 -0
  619. ansible_test/_internal/commands/integration/posix.py +1 -0
  620. ansible_test/_internal/commands/integration/windows.py +1 -0
  621. ansible_test/_internal/commands/sanity/__init__.py +19 -2
  622. ansible_test/_internal/commands/sanity/ansible_doc.py +1 -0
  623. ansible_test/_internal/commands/sanity/bin_symlinks.py +1 -0
  624. ansible_test/_internal/commands/sanity/compile.py +1 -0
  625. ansible_test/_internal/commands/sanity/ignores.py +1 -0
  626. ansible_test/_internal/commands/sanity/import.py +1 -0
  627. ansible_test/_internal/commands/sanity/integration_aliases.py +12 -0
  628. ansible_test/_internal/commands/sanity/pep8.py +1 -0
  629. ansible_test/_internal/commands/sanity/pslint.py +1 -0
  630. ansible_test/_internal/commands/sanity/pylint.py +25 -26
  631. ansible_test/_internal/commands/sanity/shellcheck.py +1 -0
  632. ansible_test/_internal/commands/sanity/validate_modules.py +1 -0
  633. ansible_test/_internal/commands/sanity/yamllint.py +1 -0
  634. ansible_test/_internal/commands/shell/__init__.py +44 -4
  635. ansible_test/_internal/commands/units/__init__.py +5 -1
  636. ansible_test/_internal/compat/__init__.py +1 -0
  637. ansible_test/_internal/compat/packaging.py +1 -0
  638. ansible_test/_internal/compat/yaml.py +1 -0
  639. ansible_test/_internal/completion.py +1 -0
  640. ansible_test/_internal/config.py +23 -13
  641. ansible_test/_internal/connections.py +1 -0
  642. ansible_test/_internal/constants.py +1 -0
  643. ansible_test/_internal/containers.py +1 -0
  644. ansible_test/_internal/content_config.py +1 -0
  645. ansible_test/_internal/core_ci.py +1 -0
  646. ansible_test/_internal/coverage_util.py +11 -10
  647. ansible_test/_internal/data.py +1 -0
  648. ansible_test/_internal/debugging.py +166 -0
  649. ansible_test/_internal/delegation.py +22 -13
  650. ansible_test/_internal/dev/__init__.py +1 -0
  651. ansible_test/_internal/dev/container_probe.py +1 -0
  652. ansible_test/_internal/diff.py +3 -2
  653. ansible_test/_internal/docker_util.py +2 -1
  654. ansible_test/_internal/encoding.py +1 -0
  655. ansible_test/_internal/executor.py +1 -0
  656. ansible_test/_internal/git.py +1 -0
  657. ansible_test/_internal/host_configs.py +1 -0
  658. ansible_test/_internal/host_profiles.py +260 -16
  659. ansible_test/_internal/http.py +1 -0
  660. ansible_test/_internal/init.py +1 -0
  661. ansible_test/_internal/inventory.py +39 -3
  662. ansible_test/_internal/io.py +1 -0
  663. ansible_test/_internal/metadata.py +95 -4
  664. ansible_test/_internal/payload.py +1 -0
  665. ansible_test/_internal/processes.py +80 -0
  666. ansible_test/_internal/provider/__init__.py +1 -0
  667. ansible_test/_internal/provider/layout/__init__.py +1 -0
  668. ansible_test/_internal/provider/layout/ansible.py +1 -0
  669. ansible_test/_internal/provider/layout/collection.py +1 -0
  670. ansible_test/_internal/provider/layout/unsupported.py +1 -0
  671. ansible_test/_internal/provider/source/__init__.py +1 -0
  672. ansible_test/_internal/provider/source/git.py +1 -0
  673. ansible_test/_internal/provider/source/installed.py +1 -0
  674. ansible_test/_internal/provider/source/unsupported.py +1 -0
  675. ansible_test/_internal/provider/source/unversioned.py +1 -0
  676. ansible_test/_internal/provisioning.py +11 -4
  677. ansible_test/_internal/pypi_proxy.py +6 -5
  678. ansible_test/_internal/python_requirements.py +28 -0
  679. ansible_test/_internal/ssh.py +2 -5
  680. ansible_test/_internal/target.py +9 -0
  681. ansible_test/_internal/test.py +3 -2
  682. ansible_test/_internal/thread.py +3 -1
  683. ansible_test/_internal/timeout.py +2 -1
  684. ansible_test/_internal/util.py +41 -12
  685. ansible_test/_internal/util_common.py +18 -5
  686. ansible_test/_internal/venv.py +1 -0
  687. ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +1 -0
  688. ansible_test/_util/controller/sanity/code-smell/changelog/sphinx.py +1 -0
  689. ansible_test/_util/controller/sanity/code-smell/changelog.py +1 -0
  690. ansible_test/_util/controller/sanity/code-smell/empty-init.py +1 -0
  691. ansible_test/_util/controller/sanity/code-smell/line-endings.py +1 -0
  692. ansible_test/_util/controller/sanity/code-smell/no-assert.py +1 -0
  693. ansible_test/_util/controller/sanity/code-smell/no-get-exception.py +1 -0
  694. ansible_test/_util/controller/sanity/code-smell/no-illegal-filenames.py +1 -0
  695. ansible_test/_util/controller/sanity/code-smell/no-smart-quotes.py +1 -0
  696. ansible_test/_util/controller/sanity/code-smell/replace-urlopen.py +1 -0
  697. ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +28 -1
  698. ansible_test/_util/controller/sanity/code-smell/shebang.py +1 -0
  699. ansible_test/_util/controller/sanity/code-smell/symlinks.py +1 -0
  700. ansible_test/_util/controller/sanity/code-smell/use-argspec-type-path.py +1 -0
  701. ansible_test/_util/controller/sanity/code-smell/use-compat-six.py +1 -0
  702. ansible_test/_util/controller/sanity/integration-aliases/yaml_to_json.py +2 -1
  703. ansible_test/_util/controller/sanity/pep8/current-ignore.txt +4 -0
  704. ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +8 -5
  705. ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +8 -5
  706. ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +8 -5
  707. ansible_test/_util/controller/sanity/pylint/config/collection.cfg +4 -5
  708. ansible_test/_util/controller/sanity/pylint/config/default.cfg +8 -7
  709. ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +541 -0
  710. ansible_test/_util/controller/sanity/pylint/plugins/deprecated_comment.py +137 -0
  711. ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +1 -0
  712. ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +1 -8
  713. ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +1 -8
  714. ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +55 -28
  715. ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +12 -5
  716. ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +13 -2
  717. ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -0
  718. ansible_test/_util/controller/sanity/yamllint/yamllinter.py +35 -17
  719. ansible_test/_util/controller/tools/collection_detail.py +1 -0
  720. ansible_test/_util/controller/tools/yaml_to_json.py +2 -1
  721. ansible_test/_util/target/injector/python.py +8 -0
  722. ansible_test/_util/target/pytest/plugins/ansible_forked.py +6 -1
  723. ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py +2 -1
  724. ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +1 -0
  725. ansible_test/_util/target/sanity/compile/compile.py +1 -0
  726. ansible_test/_util/target/sanity/import/importer.py +15 -16
  727. ansible_test/_util/target/setup/bootstrap.sh +9 -20
  728. ansible_test/_util/target/setup/probe_cgroups.py +1 -0
  729. ansible_test/_util/target/setup/quiet_pip.py +1 -0
  730. ansible_test/_util/target/setup/requirements.py +38 -36
  731. ansible_test/_util/target/tools/virtualenvcheck.py +2 -1
  732. ansible_test/_util/target/tools/yamlcheck.py +2 -1
  733. ansible/compat/selectors.py +0 -32
  734. ansible/errors/yaml_strings.py +0 -138
  735. ansible/executor/action_write_locks.py +0 -44
  736. ansible/executor/discovery/python_target.py +0 -47
  737. ansible/executor/powershell/module_powershell_wrapper.ps1 +0 -86
  738. ansible/executor/powershell/module_script_wrapper.ps1 +0 -22
  739. ansible/module_utils/compat/importlib.py +0 -26
  740. ansible/module_utils/compat/selectors.py +0 -32
  741. ansible/module_utils/pycompat24.py +0 -73
  742. ansible/parsing/yaml/constructor.py +0 -178
  743. ansible/template/native_helpers.py +0 -251
  744. ansible/template/template.py +0 -43
  745. ansible/template/vars.py +0 -77
  746. ansible/utils/native_jinja.py +0 -11
  747. ansible/vars/fact_cache.py +0 -71
  748. ansible_core-2.18.7rc1.dist-info/RECORD +0 -992
  749. ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +0 -411
  750. {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/WHEEL +0 -0
  751. {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/entry_points.txt +0 -0
  752. {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/COPYING +0 -0
  753. {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/Apache-License.txt +0 -0
  754. {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/MIT-license.txt +0 -0
  755. {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/PSF-license.txt +0 -0
  756. {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
  757. {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/top_level.txt +0 -0
@@ -6,6 +6,7 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  import base64
9
+ import contextlib
9
10
  import json
10
11
  import os
11
12
  import re
@@ -13,29 +14,42 @@ import secrets
13
14
  import shlex
14
15
  import stat
15
16
  import tempfile
17
+ import typing as t
16
18
 
17
19
  from abc import ABC, abstractmethod
18
20
  from collections.abc import Sequence
19
21
 
20
22
  from ansible import constants as C
23
+ from ansible._internal._errors import _captured, _error_utils
21
24
  from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleActionSkip, AnsibleActionFail, AnsibleAuthenticationFailure
22
- from ansible.executor.module_common import modify_module
25
+ from ansible.executor.module_common import modify_module, _BuiltModule
23
26
  from ansible.executor.interpreter_discovery import discover_interpreter, InterpreterDiscoveryRequiredError
27
+ from ansible.module_utils._internal import _traceback
24
28
  from ansible.module_utils.common.arg_spec import ArgumentSpecValidator
25
29
  from ansible.module_utils.errors import UnsupportedError
26
30
  from ansible.module_utils.json_utils import _filter_non_json_lines
31
+ from ansible.module_utils.common.json import Direction, get_module_encoder, get_module_decoder
27
32
  from ansible.module_utils.six import binary_type, string_types, text_type
28
33
  from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
29
- from ansible.parsing.utils.jsonify import jsonify
30
34
  from ansible.release import __version__
31
35
  from ansible.utils.collection_loader import resource_from_fqcr
32
36
  from ansible.utils.display import Display
33
- from ansible.utils.unsafe_proxy import wrap_var, AnsibleUnsafeText
34
37
  from ansible.vars.clean import remove_internal_keys
35
38
  from ansible.utils.plugin_docs import get_versioned_doclink
39
+ from ansible import _internal
40
+ from ansible._internal._templating import _engine
41
+
42
+ from .. import _AnsiblePluginInfoMixin
36
43
 
37
44
  display = Display()
38
45
 
46
+ if t.TYPE_CHECKING:
47
+ from ansible.parsing.dataloader import DataLoader
48
+ from ansible.playbook.play_context import PlayContext
49
+ from ansible.playbook.task import Task
50
+ from ansible.plugins.connection import ConnectionBase
51
+ from ansible.template import Templar
52
+
39
53
 
40
54
  def _validate_utf8_json(d):
41
55
  if isinstance(d, text_type):
@@ -49,14 +63,13 @@ def _validate_utf8_json(d):
49
63
  _validate_utf8_json(o)
50
64
 
51
65
 
52
- class ActionBase(ABC):
53
-
54
- '''
66
+ class ActionBase(ABC, _AnsiblePluginInfoMixin):
67
+ """
55
68
  This class is the base class for all action plugins, and defines
56
69
  code common to all actions. The base class handles the connection
57
70
  by putting/getting files and executing commands based on the current
58
71
  action in use.
59
- '''
72
+ """
60
73
 
61
74
  # A set of valid arguments
62
75
  _VALID_ARGS = frozenset([]) # type: frozenset[str]
@@ -67,28 +80,30 @@ class ActionBase(ABC):
67
80
  _requires_connection = True
68
81
  _supports_check_mode = True
69
82
  _supports_async = False
83
+ supports_raw_params = False
70
84
 
71
- def __init__(self, task, connection, play_context, loader, templar, shared_loader_obj):
85
+ def __init__(self, task: Task, connection: ConnectionBase, play_context: PlayContext, loader: DataLoader, templar: Templar, shared_loader_obj=None):
72
86
  self._task = task
73
87
  self._connection = connection
74
88
  self._play_context = play_context
75
89
  self._loader = loader
76
90
  self._templar = templar
77
- self._shared_loader_obj = shared_loader_obj
91
+
92
+ from ansible.plugins import loader as plugin_loaders # avoid circular global import since PluginLoader needs ActionBase
93
+
94
+ self._shared_loader_obj = plugin_loaders # shared_loader_obj was just a ref to `ansible.plugins.loader` anyway; this lets us inherit its type
78
95
  self._cleanup_remote_tmp = False
79
96
 
80
97
  # interpreter discovery state
81
- self._discovered_interpreter_key = None
98
+ self._discovered_interpreter_key: str | None = None
82
99
  self._discovered_interpreter = False
83
- self._discovery_deprecation_warnings = []
84
- self._discovery_warnings = []
85
- self._used_interpreter = None
100
+ self._used_interpreter: str | None = None
86
101
 
87
102
  # Backwards compat: self._display isn't really needed, just import the global display and use that.
88
103
  self._display = display
89
104
 
90
105
  @abstractmethod
91
- def run(self, tmp=None, task_vars=None):
106
+ def run(self, tmp: str | None = None, task_vars: dict[str, t.Any] | None = None) -> dict[str, t.Any]:
92
107
  """ Action Plugins should implement this method to perform their
93
108
  tasks. Everything else in this base class is a helper method for the
94
109
  action plugin to do that.
@@ -104,14 +119,13 @@ class ActionBase(ABC):
104
119
 
105
120
  * Module parameters. These are stored in self._task.args
106
121
  """
107
-
108
- # does not default to {'changed': False, 'failed': False}, as it breaks async
109
- result = {}
122
+ # does not default to {'changed': False, 'failed': False}, as it used to break async
123
+ result: dict[str, t.Any] = {}
110
124
 
111
125
  if tmp is not None:
112
- result['warning'] = ['ActionModule.run() no longer honors the tmp parameter. Action'
113
- ' plugins should set self._connection._shell.tmpdir to share'
114
- ' the tmpdir']
126
+ display.warning('ActionModule.run() no longer honors the tmp parameter. Action'
127
+ ' plugins should set self._connection._shell.tmpdir to share'
128
+ ' the tmpdir.')
115
129
  del tmp
116
130
 
117
131
  if self._task.async_val and not self._supports_async:
@@ -177,7 +191,7 @@ class ActionBase(ABC):
177
191
  if isinstance(error, UnsupportedError):
178
192
  msg = f"Unsupported parameters for ({self._load_name}) module: {msg}"
179
193
 
180
- raise AnsibleActionFail(msg)
194
+ raise AnsibleActionFail(msg, obj=self._task.args)
181
195
 
182
196
  return validation_result, new_module_args
183
197
 
@@ -193,6 +207,28 @@ class ActionBase(ABC):
193
207
  if force or not self._task.async_val:
194
208
  self._remove_tmp_path(self._connection._shell.tmpdir)
195
209
 
210
+ @classmethod
211
+ @contextlib.contextmanager
212
+ @_internal.experimental
213
+ def get_finalize_task_args_context(cls) -> t.Any:
214
+ """
215
+ EXPERIMENTAL: Unstable API subject to change at any time without notice.
216
+ Wraps task arg finalization with (optional) stateful context.
217
+ The context manager is entered during `Task.post_validate_args, and may yield a single value to be passed
218
+ as `context` to Task.finalize_task_arg for each task arg.
219
+ """
220
+ yield None
221
+
222
+ @classmethod
223
+ @_internal.experimental
224
+ def finalize_task_arg(cls, name: str, value: t.Any, templar: _engine.TemplateEngine, context: t.Any) -> t.Any:
225
+ """
226
+ EXPERIMENTAL: Unstable API subject to change at any time without notice.
227
+ Called for each task arg to allow for custom templating.
228
+ The optional `context` value is sourced from `Task.get_finalize_task_args_context`.
229
+ """
230
+ return templar.template(value)
231
+
196
232
  def get_plugin_option(self, plugin, option, default=None):
197
233
  """Helper to get an option from a plugin without having to use
198
234
  the try/except dance everywhere to set a default
@@ -218,11 +254,11 @@ class ActionBase(ABC):
218
254
  return True
219
255
  return False
220
256
 
221
- def _configure_module(self, module_name, module_args, task_vars):
222
- '''
257
+ def _configure_module(self, module_name, module_args, task_vars) -> tuple[_BuiltModule, str]:
258
+ """
223
259
  Handles the loading and templating of the module code through the
224
260
  modify_module() function.
225
- '''
261
+ """
226
262
  if self._task.delegate_to:
227
263
  use_vars = task_vars.get('ansible_delegated_vars')[self._task.delegate_to]
228
264
  else:
@@ -276,38 +312,29 @@ class ActionBase(ABC):
276
312
  raise AnsibleError("The module %s was not found in configured module paths" % (module_name))
277
313
 
278
314
  # insert shared code and arguments into the module
279
- final_environment = dict()
315
+ final_environment: dict[str, t.Any] = {}
280
316
  self._compute_environment_string(final_environment)
281
317
 
282
- become_kwargs = {}
283
- if self._connection.become:
284
- become_kwargs['become'] = True
285
- become_kwargs['become_method'] = self._connection.become.name
286
- become_kwargs['become_user'] = self._connection.become.get_option('become_user',
287
- playcontext=self._play_context)
288
- become_kwargs['become_password'] = self._connection.become.get_option('become_pass',
289
- playcontext=self._play_context)
290
- become_kwargs['become_flags'] = self._connection.become.get_option('become_flags',
291
- playcontext=self._play_context)
292
-
293
318
  # modify_module will exit early if interpreter discovery is required; re-run after if necessary
294
- for dummy in (1, 2):
319
+ for _dummy in (1, 2):
295
320
  try:
296
- (module_data, module_style, module_shebang) = modify_module(module_name, module_path, module_args, self._templar,
297
- task_vars=use_vars,
298
- module_compression=C.config.get_config_value('DEFAULT_MODULE_COMPRESSION',
299
- variables=task_vars),
300
- async_timeout=self._task.async_val,
301
- environment=final_environment,
302
- remote_is_local=bool(getattr(self._connection, '_remote_is_local', False)),
303
- **become_kwargs)
321
+ module_bits = modify_module(
322
+ module_name=module_name,
323
+ module_path=module_path,
324
+ module_args=module_args,
325
+ templar=self._templar,
326
+ task_vars=use_vars,
327
+ module_compression=C.config.get_config_value('DEFAULT_MODULE_COMPRESSION', variables=task_vars),
328
+ async_timeout=self._task.async_val,
329
+ environment=final_environment,
330
+ remote_is_local=bool(getattr(self._connection, '_remote_is_local', False)),
331
+ become_plugin=self._connection.become,
332
+ )
333
+
304
334
  break
305
335
  except InterpreterDiscoveryRequiredError as idre:
306
- self._discovered_interpreter = AnsibleUnsafeText(discover_interpreter(
307
- action=self,
308
- interpreter_name=idre.interpreter_name,
309
- discovery_mode=idre.discovery_mode,
310
- task_vars=use_vars))
336
+ self._discovered_interpreter = discover_interpreter(action=self, interpreter_name=idre.interpreter_name,
337
+ discovery_mode=idre.discovery_mode, task_vars=use_vars)
311
338
 
312
339
  # update the local task_vars with the discovered interpreter (which might be None);
313
340
  # we'll propagate back to the controller in the task result
@@ -327,12 +354,12 @@ class ActionBase(ABC):
327
354
  else:
328
355
  task_vars['ansible_delegated_vars'][self._task.delegate_to]['ansible_facts'][discovered_key] = self._discovered_interpreter
329
356
 
330
- return (module_style, module_shebang, module_data, module_path)
357
+ return module_bits, module_path
331
358
 
332
359
  def _compute_environment_string(self, raw_environment_out=None):
333
- '''
360
+ """
334
361
  Builds the environment string to be used when executing the remote task.
335
- '''
362
+ """
336
363
 
337
364
  final_environment = dict()
338
365
  if self._task.environment is not None:
@@ -363,52 +390,28 @@ class ActionBase(ABC):
363
390
  return self._connection._shell.env_prefix(**final_environment)
364
391
 
365
392
  def _early_needs_tmp_path(self):
366
- '''
393
+ """
367
394
  Determines if a tmp path should be created before the action is executed.
368
- '''
395
+ """
369
396
 
370
397
  return getattr(self, 'TRANSFERS_FILES', False)
371
398
 
372
- def _is_pipelining_enabled(self, module_style, wrap_async=False):
373
- '''
374
- Determines if we are required and can do pipelining
375
- '''
376
-
377
- try:
378
- is_enabled = self._connection.get_option('pipelining')
379
- except (KeyError, AttributeError, ValueError):
380
- is_enabled = self._play_context.pipelining
381
-
382
- # winrm supports async pipeline
383
- # TODO: make other class property 'has_async_pipelining' to separate cases
384
- always_pipeline = self._connection.always_pipeline_modules
385
-
386
- # su does not work with pipelining
387
- # TODO: add has_pipelining class prop to become plugins
388
- become_exception = (self._connection.become.name if self._connection.become else '') != 'su'
389
-
390
- # any of these require a true
391
- conditions = [
392
- self._connection.has_pipelining, # connection class supports it
393
- is_enabled or always_pipeline, # enabled via config or forced via connection (eg winrm)
394
- module_style == "new", # old style modules do not support pipelining
395
- not C.DEFAULT_KEEP_REMOTE_FILES, # user wants remote files
396
- not wrap_async or always_pipeline, # async does not normally support pipelining unless it does (eg winrm)
397
- become_exception,
398
- ]
399
-
400
- return all(conditions)
399
+ def _is_pipelining_enabled(self, module_style: str, wrap_async: bool = False) -> bool:
400
+ """
401
+ Determines if we are required and can do pipelining, only 'new' style modules can support pipelining
402
+ """
403
+ return bool(module_style == 'new' and self._connection.is_pipelining_enabled(wrap_async))
401
404
 
402
405
  def _get_admin_users(self):
403
- '''
406
+ """
404
407
  Returns a list of admin users that are configured for the current shell
405
408
  plugin
406
- '''
409
+ """
407
410
 
408
411
  return self.get_shell_option('admin_users', ['root'])
409
412
 
410
413
  def _get_remote_addr(self, tvars):
411
- ''' consistently get the 'remote_address' for the action plugin '''
414
+ """ consistently get the 'remote_address' for the action plugin """
412
415
  remote_addr = tvars.get('delegated_vars', {}).get('ansible_host', tvars.get('ansible_host', tvars.get('inventory_hostname', None)))
413
416
  for variation in ('remote_addr', 'host'):
414
417
  try:
@@ -422,7 +425,7 @@ class ActionBase(ABC):
422
425
  return remote_addr
423
426
 
424
427
  def _get_remote_user(self):
425
- ''' consistently get the 'remote_user' for the action plugin '''
428
+ """ consistently get the 'remote_user' for the action plugin """
426
429
  # TODO: use 'current user running ansible' as fallback when moving away from play_context
427
430
  # pwd.getpwuid(os.getuid()).pw_name
428
431
  remote_user = None
@@ -437,10 +440,10 @@ class ActionBase(ABC):
437
440
  return remote_user
438
441
 
439
442
  def _is_become_unprivileged(self):
440
- '''
443
+ """
441
444
  The user is not the same as the connection user and is not part of the
442
445
  shell configured admin users
443
- '''
446
+ """
444
447
  # if we don't use become then we know we aren't switching to a
445
448
  # different unprivileged user
446
449
  if not self._connection.become:
@@ -454,9 +457,9 @@ class ActionBase(ABC):
454
457
  return bool(become_user and become_user not in admin_users + [remote_user])
455
458
 
456
459
  def _make_tmp_path(self, remote_user=None):
457
- '''
460
+ """
458
461
  Create and return a temporary path on a remote box.
459
- '''
462
+ """
460
463
 
461
464
  # Network connection plugins (network_cli, netconf, etc.) execute on the controller, rather than the remote host.
462
465
  # As such, we want to avoid using remote_user for paths as remote_user may not line up with the local user
@@ -470,8 +473,8 @@ class ActionBase(ABC):
470
473
 
471
474
  become_unprivileged = self._is_become_unprivileged()
472
475
  basefile = self._connection._shell._generate_temp_dir_name()
473
- cmd = self._connection._shell.mkdtemp(basefile=basefile, system=become_unprivileged, tmpdir=tmpdir)
474
- 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)
475
478
 
476
479
  # error handling on this seems a little aggressive?
477
480
  if result['rc'] != 0:
@@ -517,11 +520,11 @@ class ActionBase(ABC):
517
520
  return rc
518
521
 
519
522
  def _should_remove_tmp_path(self, tmp_path):
520
- '''Determine if temporary path should be deleted or kept by user request/config'''
523
+ """Determine if temporary path should be deleted or kept by user request/config"""
521
524
  return tmp_path and self._cleanup_remote_tmp and not C.DEFAULT_KEEP_REMOTE_FILES and "-tmp-" in tmp_path
522
525
 
523
526
  def _remove_tmp_path(self, tmp_path, force=False):
524
- '''Remove a temporary path we created. '''
527
+ """Remove a temporary path we created. """
525
528
 
526
529
  if tmp_path is None and self._connection._shell.tmpdir:
527
530
  tmp_path = self._connection._shell.tmpdir
@@ -556,18 +559,19 @@ class ActionBase(ABC):
556
559
  self._connection.put_file(local_path, remote_path)
557
560
  return remote_path
558
561
 
559
- def _transfer_data(self, remote_path, data):
560
- '''
562
+ def _transfer_data(self, remote_path: str | bytes, data: str | bytes) -> str | bytes:
563
+ """
561
564
  Copies the module data out to the temporary module path.
562
- '''
565
+ """
563
566
 
564
- if isinstance(data, dict):
565
- data = jsonify(data)
567
+ if isinstance(data, str):
568
+ data = data.encode(errors='surrogateescape')
569
+ elif not isinstance(data, bytes):
570
+ raise TypeError('data must be either a string or bytes')
566
571
 
567
572
  afd, afile = tempfile.mkstemp(dir=C.DEFAULT_LOCAL_TMP)
568
573
  afo = os.fdopen(afd, 'wb')
569
574
  try:
570
- data = to_bytes(data, errors='surrogate_or_strict')
571
575
  afo.write(data)
572
576
  except Exception as e:
573
577
  raise AnsibleError("failure writing module data to temporary file for transfer: %s" % to_native(e))
@@ -802,41 +806,41 @@ class ActionBase(ABC):
802
806
  to_native(res['stderr']), become_link))
803
807
 
804
808
  def _remote_chmod(self, paths, mode, sudoable=False):
805
- '''
809
+ """
806
810
  Issue a remote chmod command
807
- '''
811
+ """
808
812
  cmd = self._connection._shell.chmod(paths, mode)
809
813
  res = self._low_level_execute_command(cmd, sudoable=sudoable)
810
814
  return res
811
815
 
812
816
  def _remote_chown(self, paths, user, sudoable=False):
813
- '''
817
+ """
814
818
  Issue a remote chown command
815
- '''
819
+ """
816
820
  cmd = self._connection._shell.chown(paths, user)
817
821
  res = self._low_level_execute_command(cmd, sudoable=sudoable)
818
822
  return res
819
823
 
820
824
  def _remote_chgrp(self, paths, group, sudoable=False):
821
- '''
825
+ """
822
826
  Issue a remote chgrp command
823
- '''
827
+ """
824
828
  cmd = self._connection._shell.chgrp(paths, group)
825
829
  res = self._low_level_execute_command(cmd, sudoable=sudoable)
826
830
  return res
827
831
 
828
832
  def _remote_set_user_facl(self, paths, user, mode, sudoable=False):
829
- '''
833
+ """
830
834
  Issue a remote call to setfacl
831
- '''
835
+ """
832
836
  cmd = self._connection._shell.set_user_facl(paths, user, mode)
833
837
  res = self._low_level_execute_command(cmd, sudoable=sudoable)
834
838
  return res
835
839
 
836
840
  def _execute_remote_stat(self, path, all_vars, follow, tmp=None, checksum=True):
837
- '''
841
+ """
838
842
  Get information from remote file.
839
- '''
843
+ """
840
844
  if tmp is not None:
841
845
  display.warning('_execute_remote_stat no longer honors the tmp parameter. Action'
842
846
  ' plugins should set self._connection._shell.tmpdir to share'
@@ -876,7 +880,7 @@ class ActionBase(ABC):
876
880
  return mystat['stat']
877
881
 
878
882
  def _remote_expand_user(self, path, sudoable=True, pathsep=None):
879
- ''' takes a remote path and performs tilde/$HOME expansion on the remote host '''
883
+ """ takes a remote path and performs tilde/$HOME expansion on the remote host """
880
884
 
881
885
  # We only expand ~/path and ~username/path
882
886
  if not path.startswith('~'):
@@ -901,8 +905,8 @@ class ActionBase(ABC):
901
905
  expand_path = '~%s' % (self._get_remote_user() or '')
902
906
 
903
907
  # use shell to construct appropriate command and execute
904
- cmd = self._connection._shell.expand_user(expand_path)
905
- 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)
906
910
 
907
911
  try:
908
912
  initial_fragment = data['stdout'].strip().splitlines()[-1]
@@ -930,9 +934,9 @@ class ActionBase(ABC):
930
934
  return expanded
931
935
 
932
936
  def _strip_success_message(self, data):
933
- '''
937
+ """
934
938
  Removes the BECOME-SUCCESS message from the data.
935
- '''
939
+ """
936
940
  if data.strip().startswith('BECOME-SUCCESS-'):
937
941
  data = re.sub(r'^((\r)?\n)?BECOME-SUCCESS.*(\r)?\n', '', data)
938
942
  return data
@@ -972,9 +976,6 @@ class ActionBase(ABC):
972
976
  # let module know about filesystems that selinux treats specially
973
977
  module_args['_ansible_selinux_special_fs'] = C.DEFAULT_SELINUX_SPECIAL_FS
974
978
 
975
- # what to do when parameter values are converted to strings
976
- module_args['_ansible_string_conversion_action'] = C.STRING_CONVERSION_ACTION
977
-
978
979
  # give the module the socket for persistent connections
979
980
  module_args['_ansible_socket'] = getattr(self._connection, 'socket_path')
980
981
  if not module_args['_ansible_socket']:
@@ -998,14 +999,16 @@ class ActionBase(ABC):
998
999
  # tells the module to ignore options that are not in its argspec.
999
1000
  module_args['_ansible_ignore_unknown_opts'] = ignore_unknown_opts
1000
1001
 
1001
- # allow user to insert string to add context to remote loggging
1002
+ # allow user to insert string to add context to remote logging
1002
1003
  module_args['_ansible_target_log_info'] = C.config.get_config_value('TARGET_LOG_INFO', variables=task_vars)
1003
1004
 
1005
+ module_args['_ansible_tracebacks_for'] = _traceback.traceback_for()
1006
+
1004
1007
  def _execute_module(self, module_name=None, module_args=None, tmp=None, task_vars=None, persist_files=False, delete_remote_tmp=None, wrap_async=False,
1005
1008
  ignore_unknown_opts: bool = False):
1006
- '''
1009
+ """
1007
1010
  Transfer and run a module along with its arguments.
1008
- '''
1011
+ """
1009
1012
  if tmp is not None:
1010
1013
  display.warning('_execute_module no longer honors the tmp parameter. Action plugins'
1011
1014
  ' should set self._connection._shell.tmpdir to share the tmpdir')
@@ -1047,7 +1050,8 @@ class ActionBase(ABC):
1047
1050
  self._task.environment.append({"ANSIBLE_ASYNC_DIR": async_dir})
1048
1051
 
1049
1052
  # FUTURE: refactor this along with module build process to better encapsulate "smart wrapper" functionality
1050
- (module_style, shebang, module_data, module_path) = self._configure_module(module_name=module_name, module_args=module_args, task_vars=task_vars)
1053
+ module_bits, module_path = self._configure_module(module_name=module_name, module_args=module_args, task_vars=task_vars)
1054
+ (module_style, shebang, module_data) = (module_bits.module_style, module_bits.shebang, module_bits.b_module_data)
1051
1055
  display.vvv("Using module file %s" % module_path)
1052
1056
  if not shebang and module_style != 'binary':
1053
1057
  raise AnsibleError("module (%s) is missing interpreter line" % module_name)
@@ -1083,7 +1087,8 @@ class ActionBase(ABC):
1083
1087
  args_data += '%s=%s ' % (k, shlex.quote(text_type(v)))
1084
1088
  self._transfer_data(args_file_path, args_data)
1085
1089
  elif module_style in ('non_native_want_json', 'binary'):
1086
- self._transfer_data(args_file_path, json.dumps(module_args))
1090
+ profile_encoder = get_module_encoder(module_bits.serialization_profile, Direction.CONTROLLER_TO_MODULE)
1091
+ self._transfer_data(args_file_path, json.dumps(module_args, cls=profile_encoder))
1087
1092
  display.debug("done transferring module to remote")
1088
1093
 
1089
1094
  environment_string = self._compute_environment_string()
@@ -1106,8 +1111,8 @@ class ActionBase(ABC):
1106
1111
 
1107
1112
  if wrap_async and not self._connection.always_pipeline_modules:
1108
1113
  # configure, upload, and chmod the async_wrapper module
1109
- (async_module_style, shebang, async_module_data, async_module_path) = self._configure_module(
1110
- module_name='ansible.legacy.async_wrapper', module_args=dict(), task_vars=task_vars)
1114
+ (async_module_bits, async_module_path) = self._configure_module(module_name='ansible.legacy.async_wrapper', module_args=dict(), task_vars=task_vars)
1115
+ (shebang, async_module_data) = (async_module_bits.shebang, async_module_bits.b_module_data)
1111
1116
  async_module_remote_filename = self._connection._shell.get_remote_filename(async_module_path)
1112
1117
  remote_async_module_path = self._connection._shell.join_path(tmpdir, async_module_remote_filename)
1113
1118
  self._transfer_data(remote_async_module_path, async_module_data)
@@ -1156,7 +1161,7 @@ class ActionBase(ABC):
1156
1161
  res = self._low_level_execute_command(cmd, sudoable=sudoable, in_data=in_data)
1157
1162
 
1158
1163
  # parse the main result
1159
- data = self._parse_returned_data(res)
1164
+ data = self._parse_returned_data(res, module_bits.serialization_profile)
1160
1165
 
1161
1166
  # NOTE: INTERNAL KEYS ONLY ACCESSIBLE HERE
1162
1167
  # get internal info before cleaning
@@ -1197,74 +1202,71 @@ class ActionBase(ABC):
1197
1202
 
1198
1203
  data['ansible_facts'][self._discovered_interpreter_key] = self._discovered_interpreter
1199
1204
 
1200
- if self._discovery_warnings:
1201
- if data.get('warnings') is None:
1202
- data['warnings'] = []
1203
- data['warnings'].extend(self._discovery_warnings)
1204
-
1205
- if self._discovery_deprecation_warnings:
1206
- if data.get('deprecations') is None:
1207
- data['deprecations'] = []
1208
- data['deprecations'].extend(self._discovery_deprecation_warnings)
1209
-
1210
- # mark the entire module results untrusted as a template right here, since the current action could
1211
- # possibly template one of these values.
1212
- data = wrap_var(data)
1213
-
1214
1205
  display.debug("done with _execute_module (%s, %s)" % (module_name, module_args))
1215
1206
  return data
1216
1207
 
1217
- def _parse_returned_data(self, res):
1208
+ def _parse_returned_data(self, res: dict[str, t.Any], profile: str) -> dict[str, t.Any]:
1218
1209
  try:
1219
- filtered_output, warnings = _filter_non_json_lines(res.get('stdout', u''), objects_only=True)
1210
+ filtered_output, warnings = _filter_non_json_lines(res.get('stdout', ''), objects_only=True)
1211
+
1220
1212
  for w in warnings:
1221
1213
  display.warning(w)
1222
1214
 
1223
- data = json.loads(filtered_output)
1224
-
1225
- if C.MODULE_STRICT_UTF8_RESPONSE and not data.pop('_ansible_trusted_utf8', None):
1226
- try:
1227
- _validate_utf8_json(data)
1228
- except UnicodeEncodeError:
1229
- raise ValueError(
1230
- f'Module "{self._task.resolved_action or self._task.action}" returned non UTF-8 data in '
1231
- 'the JSON response.',
1232
- )
1233
-
1234
- data['_ansible_parsed'] = True
1235
- except ValueError as e:
1236
- # not valid json, lets try to capture error
1237
- data = dict(failed=True, _ansible_parsed=False)
1238
- data['module_stdout'] = res.get('stdout', u'')
1239
- if 'stderr' in res:
1240
- data['module_stderr'] = res['stderr']
1241
- if res['stderr'].startswith(u'Traceback'):
1242
- data['exception'] = res['stderr']
1243
-
1244
- # in some cases a traceback will arrive on stdout instead of stderr, such as when using ssh with -tt
1245
- if 'exception' not in data and data['module_stdout'].startswith(u'Traceback'):
1246
- data['exception'] = data['module_stdout']
1247
-
1248
- # The default
1249
- data['msg'] = f"MODULE FAILURE: {e}"
1250
-
1251
- # try to figure out if we are missing interpreter
1215
+ decoder = get_module_decoder(profile, Direction.MODULE_TO_CONTROLLER)
1216
+
1217
+ data = json.loads(filtered_output, cls=decoder)
1218
+
1219
+ _captured.AnsibleModuleCapturedError.normalize_result_exception(data)
1220
+
1221
+ data.update(_ansible_parsed=True) # this must occur after normalize_result_exception, since it checks the type of data to ensure it's a dict
1222
+ except ValueError as ex:
1223
+ message = "Module result deserialization failed."
1224
+ help_text = ""
1225
+ include_cause_message = True
1226
+
1252
1227
  if self._used_interpreter is not None:
1253
- interpreter = re.escape(self._used_interpreter.lstrip('!#'))
1254
- match = re.compile('%s: (?:No such file or directory|not found)' % interpreter)
1255
- if match.search(data['module_stderr']) or match.search(data['module_stdout']):
1256
- data['msg'] = "The module failed to execute correctly, you probably need to set the interpreter."
1228
+ interpreter = self._used_interpreter.lstrip('!#')
1229
+ # "not found" case is currently not tested; it was once reproducible
1230
+ # see: https://github.com/ansible/ansible/pull/53534
1231
+ not_found_err_re = re.compile(rf'{re.escape(interpreter)}: (?:No such file or directory|not found|command not found)')
1232
+
1233
+ if not_found_err_re.search(res.get('stderr', '')) or not_found_err_re.search(res.get('stdout', '')):
1234
+ message = f"The module interpreter {interpreter!r} was not found."
1235
+ help_text = 'Consider overriding the configured interpreter path for this host. '
1236
+ include_cause_message = False # cause context *might* be useful in the traceback, but the JSON deserialization failure message is not
1237
+
1238
+ try:
1239
+ # Because the underlying action API is built on result dicts instead of exceptions (for all but the most catastrophic failures),
1240
+ # we're using a tweaked version of the module exception handler to get new ErrorDetail-backed errors from this part of the code.
1241
+ # Ideally this would raise immediately on failure, but this would likely break actions that assume `ActionBase._execute_module()`
1242
+ # does not raise on module failure.
1257
1243
 
1258
- # always append hint
1259
- data['msg'] += '\nSee stdout/stderr for the exact error'
1244
+ error = AnsibleError(
1245
+ message=message,
1246
+ help_text=help_text + "See stdout/stderr for the returned output.",
1247
+ )
1248
+
1249
+ error._include_cause_message = include_cause_message
1250
+
1251
+ raise error from ex
1252
+ except AnsibleError as ansible_ex:
1253
+ sentinel = object()
1254
+
1255
+ data = _error_utils.result_dict_from_exception(ansible_ex)
1256
+ data.update(
1257
+ _ansible_parsed=False,
1258
+ module_stdout=res.get('stdout', ''),
1259
+ module_stderr=res.get('stderr', sentinel),
1260
+ rc=res.get('rc', sentinel),
1261
+ )
1262
+
1263
+ data = {k: v for k, v in data.items() if v is not sentinel}
1260
1264
 
1261
- if 'rc' in res:
1262
- data['rc'] = res['rc']
1263
1265
  return data
1264
1266
 
1265
1267
  # FIXME: move to connection base
1266
1268
  def _low_level_execute_command(self, cmd, sudoable=True, in_data=None, executable=None, encoding_errors='surrogate_then_replace', chdir=None):
1267
- '''
1269
+ """
1268
1270
  This is the function which executes the low level shell command, which
1269
1271
  may be commands to create/remove directories for temporary files, or to
1270
1272
  run the module code or python directly when pipelining.
@@ -1277,7 +1279,7 @@ class ActionBase(ABC):
1277
1279
  verbatim, then this won't work. May have to use some sort of
1278
1280
  replacement strategy (python3 could use surrogateescape)
1279
1281
  :kwarg chdir: cd into this directory before executing the command.
1280
- '''
1282
+ """
1281
1283
 
1282
1284
  display.debug("_low_level_execute_command(): starting")
1283
1285
  # if not cmd:
@@ -1373,7 +1375,7 @@ class ActionBase(ABC):
1373
1375
  elif peek_result.get('size') and C.MAX_FILE_SIZE_FOR_DIFF > 0 and peek_result['size'] > C.MAX_FILE_SIZE_FOR_DIFF:
1374
1376
  diff['dst_larger'] = C.MAX_FILE_SIZE_FOR_DIFF
1375
1377
  else:
1376
- display.debug(u"Slurping the file %s" % source)
1378
+ display.debug(u"Slurping the file %s" % destination)
1377
1379
  dest_result = self._execute_module(
1378
1380
  module_name='ansible.legacy.slurp', module_args=dict(path=destination),
1379
1381
  task_vars=task_vars, persist_files=True)
@@ -1420,11 +1422,11 @@ class ActionBase(ABC):
1420
1422
  return diff
1421
1423
 
1422
1424
  def _find_needle(self, dirname, needle):
1423
- '''
1425
+ """
1424
1426
  find a needle in haystack of paths, optionally using 'dirname' as a subdir.
1425
1427
  This will build the ordered list of paths to search and pass them to dwim
1426
1428
  to get back the first existing file found.
1427
- '''
1429
+ """
1428
1430
 
1429
1431
  # dwim already deals with playbook basedirs
1430
1432
  path_stack = self._task.get_search_path()