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
@@ -7,32 +7,42 @@ import os
7
7
  import time
8
8
  import json
9
9
  import pathlib
10
- import signal
11
10
  import subprocess
12
11
  import sys
12
+
13
13
  import traceback
14
+ import typing as t
14
15
 
15
16
  from ansible import constants as C
16
17
  from ansible.cli import scripts
17
- from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleConnectionFailure, AnsibleActionFail, AnsibleActionSkip
18
- from ansible.executor.task_result import TaskResult
19
- from ansible.executor.module_common import get_action_args_with_defaults
18
+ from ansible.errors import (
19
+ AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleTaskError,
20
+ AnsibleValueOmittedError,
21
+ )
22
+ from ansible.executor.task_result import _RawTaskResult
23
+ from ansible._internal._datatag import _utils
24
+ from ansible.module_utils._internal import _messages
25
+ from ansible.module_utils.datatag import native_type_name, deprecator_from_collection_name
26
+ from ansible._internal._datatag._tags import TrustedAsTemplate
20
27
  from ansible.module_utils.parsing.convert_bool import boolean
21
- from ansible.module_utils.six import binary_type
22
28
  from ansible.module_utils.common.text.converters import to_text, to_native
23
29
  from ansible.module_utils.connection import write_to_stream
24
30
  from ansible.module_utils.six import string_types
25
- from ansible.playbook.conditional import Conditional
26
31
  from ansible.playbook.task import Task
27
32
  from ansible.plugins import get_plugin_class
28
33
  from ansible.plugins.loader import become_loader, cliconf_loader, connection_loader, httpapi_loader, netconf_loader, terminal_loader
34
+ from ansible._internal._templating._jinja_plugins import _invoke_lookup, _DirectCall
35
+ from ansible._internal._templating._engine import TemplateEngine
29
36
  from ansible.template import Templar
30
37
  from ansible.utils.collection_loader import AnsibleCollectionConfig
31
- from ansible.utils.listify import listify_lookup_plugin_terms
32
- from ansible.utils.unsafe_proxy import to_unsafe_text, wrap_var
33
- from ansible.vars.clean import namespace_facts, clean_facts
34
- from ansible.utils.display import Display
38
+ from ansible.utils.display import Display, _DeferredWarningContext
35
39
  from ansible.utils.vars import combine_vars
40
+ from ansible.vars.clean import namespace_facts, clean_facts
41
+ from ansible.vars.manager import _deprecate_top_level_fact
42
+ from ansible._internal._errors import _captured, _task_timeout, _error_utils
43
+
44
+ if t.TYPE_CHECKING:
45
+ from ansible.executor.task_queue_manager import FinalQueue
36
46
 
37
47
  display = Display()
38
48
 
@@ -42,78 +52,37 @@ RETURN_VARS = [x for x in C.MAGIC_VARIABLE_MAPPING.items() if 'become' not in x
42
52
  __all__ = ['TaskExecutor']
43
53
 
44
54
 
45
- class TaskTimeoutError(BaseException):
46
- def __init__(self, message="", frame=None):
47
-
48
- if frame is not None:
49
- orig = frame
50
- root = pathlib.Path(__file__).parent
51
- while not pathlib.Path(frame.f_code.co_filename).is_relative_to(root):
52
- frame = frame.f_back
53
-
54
- self.frame = 'Interrupted at %s called from %s' % (orig, frame)
55
-
56
- super(TaskTimeoutError, self).__init__(message)
57
-
58
-
59
- def task_timeout(signum, frame):
60
- raise TaskTimeoutError(frame=frame)
61
-
62
-
63
- def remove_omit(task_args, omit_token):
64
- '''
65
- Remove args with a value equal to the ``omit_token`` recursively
66
- to align with now having suboptions in the argument_spec
67
- '''
68
-
69
- if not isinstance(task_args, dict):
70
- return task_args
71
-
72
- new_args = {}
73
- for i in task_args.items():
74
- if i[1] == omit_token:
75
- continue
76
- elif isinstance(i[1], dict):
77
- new_args[i[0]] = remove_omit(i[1], omit_token)
78
- elif isinstance(i[1], list):
79
- new_args[i[0]] = [remove_omit(v, omit_token) for v in i[1]]
80
- else:
81
- new_args[i[0]] = i[1]
82
-
83
- return new_args
84
-
85
-
86
55
  class TaskExecutor:
87
56
 
88
- '''
57
+ """
89
58
  This is the main worker class for the executor pipeline, which
90
59
  handles loading an action plugin to actually dispatch the task to
91
60
  a given host. This class roughly corresponds to the old Runner()
92
61
  class.
93
- '''
62
+ """
94
63
 
95
- def __init__(self, host, task, job_vars, play_context, new_stdin, loader, shared_loader_obj, final_q, variable_manager):
64
+ def __init__(self, host, task: Task, job_vars, play_context, loader, shared_loader_obj, final_q: FinalQueue, variable_manager):
96
65
  self._host = host
97
66
  self._task = task
98
67
  self._job_vars = job_vars
99
68
  self._play_context = play_context
100
- self._new_stdin = new_stdin
101
69
  self._loader = loader
102
70
  self._shared_loader_obj = shared_loader_obj
103
71
  self._connection = None
104
72
  self._final_q = final_q
105
73
  self._variable_manager = variable_manager
106
74
  self._loop_eval_error = None
75
+ self._task_templar = TemplateEngine(loader=self._loader, variables=self._job_vars)
107
76
 
108
77
  self._task.squash()
109
78
 
110
79
  def run(self):
111
- '''
80
+ """
112
81
  The main executor entrypoint, where we determine if the specified
113
82
  task requires looping and either runs the task with self._run_loop()
114
83
  or self._execute(). After that, the returned results are parsed and
115
84
  returned as a dict.
116
- '''
85
+ """
117
86
 
118
87
  display.debug("in run() - task %s" % self._task._uuid)
119
88
 
@@ -135,10 +104,14 @@ class TaskExecutor:
135
104
  # loop through the item results and set the global changed/failed/skipped result flags based on any item.
136
105
  res['skipped'] = True
137
106
  for item in item_results:
107
+ if item.get('_ansible_no_log'):
108
+ res.update(_ansible_no_log=True) # ensure no_log processing recognizes at least one item needs to be censored
109
+
138
110
  if 'changed' in item and item['changed'] and not res.get('changed'):
139
111
  res['changed'] = True
140
112
  if res['skipped'] and ('skipped' not in item or ('skipped' in item and not item['skipped'])):
141
113
  res['skipped'] = False
114
+ # FIXME: normalize `failed` to a bool, warn if the action/module used non-bool
142
115
  if 'failed' in item and item['failed']:
143
116
  item_ignore = item.pop('_ansible_ignore_errors')
144
117
  if not res.get('failed'):
@@ -165,6 +138,7 @@ class TaskExecutor:
165
138
  res[array] = res[array] + item[array]
166
139
  del item[array]
167
140
 
141
+ # FIXME: normalize `failed` to a bool, warn if the action/module used non-bool
168
142
  if not res.get('failed', False):
169
143
  res['msg'] = 'All items completed'
170
144
  if res['skipped']:
@@ -173,43 +147,23 @@ class TaskExecutor:
173
147
  res = dict(changed=False, skipped=True, skipped_reason='No items in the list', results=[])
174
148
  else:
175
149
  display.debug("calling self._execute()")
176
- res = self._execute()
150
+ res = self._execute(self._task_templar, self._job_vars)
177
151
  display.debug("_execute() done")
178
152
 
179
153
  # make sure changed is set in the result, if it's not present
180
154
  if 'changed' not in res:
181
155
  res['changed'] = False
182
156
 
183
- def _clean_res(res, errors='surrogate_or_strict'):
184
- if isinstance(res, binary_type):
185
- return to_unsafe_text(res, errors=errors)
186
- elif isinstance(res, dict):
187
- for k in res:
188
- try:
189
- res[k] = _clean_res(res[k], errors=errors)
190
- except UnicodeError:
191
- if k == 'diff':
192
- # If this is a diff, substitute a replacement character if the value
193
- # is undecodable as utf8. (Fix #21804)
194
- display.warning("We were unable to decode all characters in the module return data."
195
- " Replaced some in an effort to return as much as possible")
196
- res[k] = _clean_res(res[k], errors='surrogate_then_replace')
197
- else:
198
- raise
199
- elif isinstance(res, list):
200
- for idx, item in enumerate(res):
201
- res[idx] = _clean_res(item, errors=errors)
202
- return res
203
-
204
- display.debug("dumping result to json")
205
- res = _clean_res(res)
206
- display.debug("done dumping result, returning")
207
157
  return res
208
- except AnsibleError as e:
209
- return dict(failed=True, msg=wrap_var(to_text(e, nonstring='simplerepr')), _ansible_no_log=self._play_context.no_log)
210
- except Exception as e:
211
- return dict(failed=True, msg=wrap_var('Unexpected failure during module execution: %s' % (to_native(e, nonstring='simplerepr'))),
212
- exception=to_text(traceback.format_exc()), stdout='', _ansible_no_log=self._play_context.no_log)
158
+ except Exception as ex:
159
+ result = _error_utils.result_dict_from_exception(ex)
160
+
161
+ self._task.update_result_no_log(self._task_templar, result)
162
+
163
+ if not isinstance(ex, AnsibleError):
164
+ result.update(msg=f'Unexpected failure during task execution: {result["msg"]}')
165
+
166
+ return result
213
167
  finally:
214
168
  try:
215
169
  self._connection.close()
@@ -218,11 +172,11 @@ class TaskExecutor:
218
172
  except Exception as e:
219
173
  display.debug(u"error closing connection: %s" % to_text(e))
220
174
 
221
- def _get_loop_items(self):
222
- '''
175
+ def _get_loop_items(self) -> list[t.Any] | None:
176
+ """
223
177
  Loads a lookup plugin to handle the with_* portion of a task (if specified),
224
178
  and returns the items result.
225
- '''
179
+ """
226
180
 
227
181
  # get search path for this task to pass to lookup plugins
228
182
  self._job_vars['ansible_search_path'] = self._task.get_search_path()
@@ -231,49 +185,51 @@ class TaskExecutor:
231
185
  if self._loader.get_basedir() not in self._job_vars['ansible_search_path']:
232
186
  self._job_vars['ansible_search_path'].append(self._loader.get_basedir())
233
187
 
234
- templar = Templar(loader=self._loader, variables=self._job_vars)
235
188
  items = None
236
189
  if self._task.loop_with:
237
- if self._task.loop_with in self._shared_loader_obj.lookup_loader:
238
-
239
- # TODO: hardcoded so it fails for non first_found lookups, but this should be generalized for those that don't do their own templating
240
- # lookup prop/attribute?
241
- fail = bool(self._task.loop_with != 'first_found')
242
- loop_terms = listify_lookup_plugin_terms(terms=self._task.loop, templar=templar, fail_on_undefined=fail, convert_bare=False)
243
-
244
- # get lookup
245
- mylookup = self._shared_loader_obj.lookup_loader.get(self._task.loop_with, loader=self._loader, templar=templar)
190
+ templar = self._task_templar
191
+ terms = self._task.loop
192
+
193
+ if isinstance(terms, str):
194
+ terms = templar.resolve_to_container(_utils.str_problematic_strip(terms))
195
+
196
+ if not isinstance(terms, list):
197
+ terms = [terms]
198
+
199
+ @_DirectCall.mark
200
+ def invoke_lookup() -> t.Any:
201
+ """Scope-capturing wrapper around _invoke_lookup to avoid functools.partial obscuring its usage from type-checking tools."""
202
+ return _invoke_lookup(
203
+ plugin_name=self._task.loop_with,
204
+ lookup_terms=terms,
205
+ lookup_kwargs=dict(wantlist=True),
206
+ invoked_as_with=True,
207
+ )
246
208
 
247
- # give lookup task 'context' for subdir (mostly needed for first_found)
248
- for subdir in ['template', 'var', 'file']: # TODO: move this to constants?
249
- if subdir in self._task.action:
250
- break
251
- setattr(mylookup, '_subdir', subdir + 's')
252
-
253
- # run lookup
254
- items = wrap_var(mylookup.run(terms=loop_terms, variables=self._job_vars, wantlist=True))
255
- else:
256
- raise AnsibleError("Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % self._task.loop_with)
209
+ # Smuggle a special wrapped lookup invocation in as a local variable for its exclusive use when being evaluated as `with_(lookup)`.
210
+ # This value will not be visible to other users of this templar or its `available_variables`.
211
+ items = templar.evaluate_expression(expression=TrustedAsTemplate().tag("invoke_lookup()"), local_variables=dict(invoke_lookup=invoke_lookup))
257
212
 
258
213
  elif self._task.loop is not None:
259
- items = templar.template(self._task.loop)
214
+ items = self._task_templar.template(self._task.loop)
215
+
260
216
  if not isinstance(items, list):
261
217
  raise AnsibleError(
262
- "Invalid data passed to 'loop', it requires a list, got this instead: %s."
263
- " Hint: If you passed a list/dict of just one element,"
264
- " try adding wantlist=True to your lookup invocation or use q/query instead of lookup." % items
218
+ f"The `loop` value must resolve to a 'list', not {native_type_name(items)!r}.",
219
+ help_text="Provide a list of items/templates, or a template resolving to a list.",
220
+ obj=self._task.loop,
265
221
  )
266
222
 
267
223
  return items
268
224
 
269
- def _run_loop(self, items):
270
- '''
225
+ def _run_loop(self, items: list[t.Any]) -> list[dict[str, t.Any]]:
226
+ """
271
227
  Runs the task with the loop items specified and collates the result
272
228
  into an array named 'results' which is inserted into the final result
273
229
  along with the item for which the loop ran.
274
- '''
230
+ """
275
231
  task_vars = self._job_vars
276
- templar = Templar(loader=self._loader, variables=task_vars)
232
+ templar = TemplateEngine(loader=self._loader, variables=task_vars)
277
233
 
278
234
  self._task.loop_control.post_validate(templar=templar)
279
235
 
@@ -282,17 +238,20 @@ class TaskExecutor:
282
238
  loop_pause = self._task.loop_control.pause
283
239
  extended = self._task.loop_control.extended
284
240
  extended_allitems = self._task.loop_control.extended_allitems
241
+
285
242
  # ensure we always have a label
286
- label = self._task.loop_control.label or '{{' + loop_var + '}}'
243
+ label = self._task.loop_control.label or templar.variable_name_as_template(loop_var)
287
244
 
288
245
  if loop_var in task_vars:
289
- display.warning(u"%s: The loop variable '%s' is already in use. "
290
- u"You should set the `loop_var` value in the `loop_control` option for the task"
291
- u" to something else to avoid variable collisions and unexpected behavior." % (self._task, loop_var))
246
+ display.warning(
247
+ msg=f"The loop variable {loop_var!r} is already in use.",
248
+ help_text="You should set the `loop_var` value in the `loop_control` option for the task "
249
+ "to something else to avoid variable collisions and unexpected behavior.",
250
+ obj=loop_var,
251
+ )
292
252
 
293
253
  ran_once = False
294
254
  task_fields = None
295
- no_log = False
296
255
  items_len = len(items)
297
256
  results = []
298
257
  for item_index, item in enumerate(items):
@@ -332,7 +291,7 @@ class TaskExecutor:
332
291
  ran_once = True
333
292
 
334
293
  try:
335
- tmp_task = self._task.copy(exclude_parent=True, exclude_tasks=True)
294
+ tmp_task: Task = self._task.copy(exclude_parent=True, exclude_tasks=True)
336
295
  tmp_task._parent = self._task._parent
337
296
  tmp_play_context = self._play_context.copy()
338
297
  except AnsibleParserError as e:
@@ -341,9 +300,11 @@ class TaskExecutor:
341
300
 
342
301
  # now we swap the internal task and play context with their copies,
343
302
  # execute, and swap them back so we can do the next iteration cleanly
303
+ # NB: this swap-a-dee-doo confuses some type checkers about the type of tmp_task/self._task
344
304
  (self._task, tmp_task) = (tmp_task, self._task)
345
305
  (self._play_context, tmp_play_context) = (tmp_play_context, self._play_context)
346
- res = self._execute(variables=task_vars)
306
+
307
+ res = self._execute(templar=templar, variables=task_vars)
347
308
 
348
309
  if self._task.register:
349
310
  # Ensure per loop iteration results are registered in case `_execute()`
@@ -355,9 +316,6 @@ class TaskExecutor:
355
316
  (self._task, tmp_task) = (tmp_task, self._task)
356
317
  (self._play_context, tmp_play_context) = (tmp_play_context, self._play_context)
357
318
 
358
- # update 'general no_log' based on specific no_log
359
- no_log = no_log or tmp_task.no_log
360
-
361
319
  # now update the result with the item info, and append the result
362
320
  # to the list of results
363
321
  res[loop_var] = item
@@ -385,13 +343,14 @@ class TaskExecutor:
385
343
  if self._connection and not isinstance(self._connection, string_types):
386
344
  task_fields['connection'] = getattr(self._connection, 'ansible_name')
387
345
 
388
- tr = TaskResult(
389
- self._host.name,
390
- self._task._uuid,
391
- res,
346
+ tr = _RawTaskResult(
347
+ host=self._host,
348
+ task=self._task,
349
+ return_data=res,
392
350
  task_fields=task_fields,
393
351
  )
394
352
 
353
+ # FIXME: normalize `failed` to a bool, warn if the action/module used non-bool
395
354
  if tr.is_failed() or tr.is_unreachable():
396
355
  self._final_q.send_callback('v2_runner_item_on_failed', tr)
397
356
  elif tr.is_skipped():
@@ -406,11 +365,14 @@ class TaskExecutor:
406
365
 
407
366
  # break loop if break_when conditions are met
408
367
  if self._task.loop_control and self._task.loop_control.break_when:
409
- cond = Conditional(loader=self._loader)
410
- cond.when = self._task.loop_control.get_validated_value(
411
- 'break_when', self._task.loop_control.fattributes.get('break_when'), self._task.loop_control.break_when, templar
368
+ break_when = self._task.loop_control.get_validated_value(
369
+ 'break_when',
370
+ self._task.loop_control.fattributes.get('break_when'),
371
+ self._task.loop_control.break_when,
372
+ templar,
412
373
  )
413
- if cond.evaluate_conditional(templar, task_vars):
374
+
375
+ if self._task._resolve_conditional(break_when, task_vars):
414
376
  # delete loop vars before exiting loop
415
377
  del task_vars[loop_var]
416
378
  break
@@ -432,7 +394,6 @@ class TaskExecutor:
432
394
  if var in task_vars and var not in self._job_vars:
433
395
  del task_vars[var]
434
396
 
435
- self._task.no_log = no_log
436
397
  # NOTE: run_once cannot contain loop vars because it's templated earlier also
437
398
  # This is saving the post-validated field from the last loop so the strategy can use the templated value post task execution
438
399
  self._task.run_once = task_fields.get('run_once')
@@ -448,21 +409,49 @@ class TaskExecutor:
448
409
  # At the point this is executed it is safe to mutate self._task,
449
410
  # since `self._task` is either a copy referred to by `tmp_task` in `_run_loop`
450
411
  # or just a singular non-looped task
451
- if delegated_host_name:
452
- self._task.delegate_to = delegated_host_name
453
- variables.update(delegated_vars)
454
412
 
455
- def _execute(self, variables=None):
456
- '''
413
+ self._task.delegate_to = delegated_host_name # always override, since a templated result could be an omit (-> None)
414
+ variables.update(delegated_vars)
415
+
416
+ def _execute(self, templar: TemplateEngine, variables: dict[str, t.Any]) -> dict[str, t.Any]:
417
+ result: dict[str, t.Any]
418
+
419
+ with _DeferredWarningContext(variables=variables) as warning_ctx:
420
+ try:
421
+ # DTFIX-FUTURE: improve error handling to prioritize the earliest exception, turning the remaining ones into warnings
422
+ result = self._execute_internal(templar, variables)
423
+ self._apply_task_result_compat(result, warning_ctx)
424
+ _captured.AnsibleActionCapturedError.maybe_raise_on_result(result)
425
+ except (Exception, _task_timeout.TaskTimeoutError) as ex: # TaskTimeoutError is BaseException
426
+ try:
427
+ raise AnsibleTaskError(obj=self._task.get_ds()) from ex
428
+ except AnsibleTaskError as atex:
429
+ result = _error_utils.result_dict_from_exception(atex, accept_result_contribution=True)
430
+ result.setdefault('changed', False)
431
+
432
+ self._task.update_result_no_log(templar, result)
433
+
434
+ # The warnings/deprecations in the result have already been captured in the _DeferredWarningContext by _apply_task_result_compat.
435
+ # The captured warnings/deprecations are a superset of the ones from the result, and may have been converted from a dict to a dataclass.
436
+ # These are then used to supersede the entries in the result.
437
+
438
+ result.pop('warnings', None)
439
+ result.pop('deprecations', None)
440
+
441
+ if warnings := warning_ctx.get_warnings():
442
+ result.update(warnings=warnings)
443
+
444
+ if deprecation_warnings := warning_ctx.get_deprecation_warnings():
445
+ result.update(deprecations=deprecation_warnings)
446
+
447
+ return result
448
+
449
+ def _execute_internal(self, templar: TemplateEngine, variables: dict[str, t.Any]) -> dict[str, t.Any]:
450
+ """
457
451
  The primary workhorse of the executor system, this runs the task
458
452
  on the specified host (which may be the delegated_to host) and handles
459
453
  the retry/until and block rescue/always execution
460
- '''
461
-
462
- if variables is None:
463
- variables = self._job_vars
464
-
465
- templar = Templar(loader=self._loader, variables=variables)
454
+ """
466
455
 
467
456
  self._calculate_delegate_to(templar, variables)
468
457
 
@@ -498,18 +487,13 @@ class TaskExecutor:
498
487
  # skipping this task during the conditional evaluation step
499
488
  context_validation_error = e
500
489
 
501
- no_log = self._play_context.no_log
502
-
503
490
  # Evaluate the conditional (if any) for this task, which we do before running
504
491
  # the final task post-validation. We do this before the post validation due to
505
492
  # the fact that the conditional may specify that the task be skipped due to a
506
493
  # variable not being present which would otherwise cause validation to fail
507
494
  try:
508
- conditional_result, false_condition = self._task.evaluate_conditional_with_result(templar, tempvars)
509
- if not conditional_result:
510
- display.debug("when evaluation is False, skipping this task")
511
- return dict(changed=False, skipped=True, skip_reason='Conditional result was False',
512
- false_condition=false_condition, _ansible_no_log=no_log)
495
+ if not self._task._resolve_conditional(self._task.when, tempvars, result_context=(rc := t.cast(dict[str, t.Any], {}))):
496
+ return dict(changed=False, skipped=True, skip_reason='Conditional result was False') | rc
513
497
  except AnsibleError as e:
514
498
  # loop error takes precedence
515
499
  if self._loop_eval_error is not None:
@@ -525,22 +509,27 @@ class TaskExecutor:
525
509
 
526
510
  # if we ran into an error while setting up the PlayContext, raise it now, unless is known issue with delegation
527
511
  # and undefined vars (correct values are in cvars later on and connection plugins, if still error, blows up there)
512
+
513
+ # DTFIX-FUTURE: this should probably be declaratively handled in post_validate (or better, get rid of play_context)
528
514
  if context_validation_error is not None:
529
515
  raiseit = True
530
516
  if self._task.delegate_to:
531
- if isinstance(context_validation_error, AnsibleUndefinedVariable):
532
- raiseit = False
533
- elif isinstance(context_validation_error, AnsibleParserError):
517
+ if isinstance(context_validation_error, AnsibleParserError):
534
518
  # parser error, might be cause by undef too
535
- orig_exc = getattr(context_validation_error, 'orig_exc', None)
536
- if isinstance(orig_exc, AnsibleUndefinedVariable):
519
+ if isinstance(context_validation_error.__cause__, AnsibleUndefinedVariable):
537
520
  raiseit = False
521
+ elif isinstance(context_validation_error, AnsibleUndefinedVariable):
522
+ # DTFIX-FUTURE: should not be possible to hit this now (all are AnsibleFieldAttributeError)?
523
+ raiseit = False
538
524
  if raiseit:
539
525
  raise context_validation_error # pylint: disable=raising-bad-type
540
526
 
541
527
  # set templar to use temp variables until loop is evaluated
542
528
  templar.available_variables = tempvars
543
529
 
530
+ # Now we do final validation on the task, which sets all fields to their final values.
531
+ self._task.post_validate(templar=templar)
532
+
544
533
  # if this task is a TaskInclude, we just return now with a success code so the
545
534
  # main thread can expand the task list for the given host
546
535
  if self._task.action in C._ACTION_INCLUDE_TASKS:
@@ -549,7 +538,6 @@ class TaskExecutor:
549
538
  if not include_file:
550
539
  return dict(failed=True, msg="No include file was specified to the include")
551
540
 
552
- include_file = templar.template(include_file)
553
541
  return dict(include=include_file, include_args=include_args)
554
542
 
555
543
  # if this task is a IncludeRole, we just return now with a success code so the main thread can expand the task list for the given host
@@ -557,32 +545,9 @@ class TaskExecutor:
557
545
  include_args = self._task.args.copy()
558
546
  return dict(include_args=include_args)
559
547
 
560
- # Now we do final validation on the task, which sets all fields to their final values.
561
- try:
562
- self._task.post_validate(templar=templar)
563
- except AnsibleError:
564
- raise
565
- except Exception:
566
- return dict(changed=False, failed=True, _ansible_no_log=no_log, exception=to_text(traceback.format_exc()))
567
- if '_variable_params' in self._task.args:
568
- variable_params = self._task.args.pop('_variable_params')
569
- if isinstance(variable_params, dict):
570
- if C.INJECT_FACTS_AS_VARS:
571
- display.warning("Using a variable for a task's 'args' is unsafe in some situations "
572
- "(see https://docs.ansible.com/ansible/devel/reference_appendices/faq.html#argsplat-unsafe)")
573
- variable_params.update(self._task.args)
574
- self._task.args = variable_params
575
- else:
576
- # if we didn't get a dict, it means there's garbage remaining after k=v parsing, just give up
577
- # see https://github.com/ansible/ansible/issues/79862
578
- raise AnsibleError(f"invalid or malformed argument: '{variable_params}'")
579
-
580
- # update no_log to task value, now that we have it templated
581
- no_log = self._task.no_log
582
-
583
548
  # free tempvars up, not used anymore, cvars and vars_copy should be mainly used after this point
584
549
  # updating the original 'variables' at the end
585
- tempvars = {}
550
+ del tempvars
586
551
 
587
552
  # setup cvars copy, used for all connection related templating
588
553
  if self._task.delegate_to:
@@ -634,23 +599,7 @@ class TaskExecutor:
634
599
  cvars['ansible_python_interpreter'] = sys.executable
635
600
 
636
601
  # get handler
637
- self._handler, module_context = self._get_action_handler_with_module_context(templar=templar)
638
-
639
- if module_context is not None:
640
- module_defaults_fqcn = module_context.resolved_fqcn
641
- else:
642
- module_defaults_fqcn = self._task.resolved_action
643
-
644
- # Apply default params for action/module, if present
645
- self._task.args = get_action_args_with_defaults(
646
- module_defaults_fqcn, self._task.args, self._task.module_defaults, templar,
647
- action_groups=self._task._parent._play._action_groups
648
- )
649
-
650
- # And filter out any fields which were set to default(omit), and got the omit token value
651
- omit_token = variables.get('omit')
652
- if omit_token is not None:
653
- self._task.args = remove_omit(self._task.args, omit_token)
602
+ self._handler, _module_context = self._get_action_handler_with_module_context(templar=templar)
654
603
 
655
604
  retries = 1 # includes the default actual run + retries set by user/default
656
605
  if self._task.retries is not None:
@@ -667,30 +616,12 @@ class TaskExecutor:
667
616
  for attempt in range(1, retries + 1):
668
617
  display.debug("running the handler")
669
618
  try:
670
- if self._task.timeout:
671
- old_sig = signal.signal(signal.SIGALRM, task_timeout)
672
- signal.alarm(self._task.timeout)
673
- result = self._handler.run(task_vars=vars_copy)
674
- except (AnsibleActionFail, AnsibleActionSkip) as e:
675
- return e.result
676
- except AnsibleConnectionFailure as e:
677
- return dict(unreachable=True, msg=to_text(e))
678
- except TaskTimeoutError as e:
679
- msg = 'The %s action failed to execute in the expected time frame (%d) and was terminated' % (self._task.action, self._task.timeout)
680
- return dict(failed=True, msg=msg, timedout={'frame': e.frame, 'period': self._task.timeout})
619
+ with _task_timeout.TaskTimeoutError.alarm_timeout(self._task.timeout):
620
+ result = self._handler.run(task_vars=vars_copy)
681
621
  finally:
682
- if self._task.timeout:
683
- signal.alarm(0)
684
- old_sig = signal.signal(signal.SIGALRM, old_sig)
685
622
  self._handler.cleanup()
686
623
  display.debug("handler run complete")
687
624
 
688
- # propagate no log to result- the action can set this, so only overwrite it with the task's value if missing or falsey
689
- result["_ansible_no_log"] = bool(no_log or result.get('_ansible_no_log', False))
690
-
691
- if self._task.action not in C._ACTION_WITH_CLEAN_FACTS:
692
- result = wrap_var(result)
693
-
694
625
  # update the local copy of vars with the registered value, if specified,
695
626
  # or any facts which may have been generated by the module execution
696
627
  if self._task.register:
@@ -702,37 +633,23 @@ class TaskExecutor:
702
633
  if result.get('failed'):
703
634
  self._final_q.send_callback(
704
635
  'v2_runner_on_async_failed',
705
- TaskResult(self._host.name,
706
- self._task._uuid,
707
- result,
708
- task_fields=self._task.dump_attrs()))
636
+ _RawTaskResult(
637
+ host=self._host,
638
+ task=self._task,
639
+ return_data=result,
640
+ task_fields=self._task.dump_attrs(),
641
+ ),
642
+ )
709
643
  else:
710
644
  self._final_q.send_callback(
711
645
  'v2_runner_on_async_ok',
712
- TaskResult(self._host.name,
713
- self._task._uuid,
714
- result,
715
- task_fields=self._task.dump_attrs()))
716
-
717
- # ensure no log is preserved
718
- result["_ansible_no_log"] = no_log
719
-
720
- # helper methods for use below in evaluating changed/failed_when
721
- def _evaluate_changed_when_result(result):
722
- if self._task.changed_when is not None and self._task.changed_when:
723
- cond = Conditional(loader=self._loader)
724
- cond.when = self._task.changed_when
725
- result['changed'] = cond.evaluate_conditional(templar, vars_copy)
726
-
727
- def _evaluate_failed_when_result(result):
728
- if self._task.failed_when:
729
- cond = Conditional(loader=self._loader)
730
- cond.when = self._task.failed_when
731
- failed_when_result = cond.evaluate_conditional(templar, vars_copy)
732
- result['failed_when_result'] = result['failed'] = failed_when_result
733
- else:
734
- failed_when_result = False
735
- return failed_when_result
646
+ _RawTaskResult(
647
+ host=self._host,
648
+ task=self._task,
649
+ return_data=result,
650
+ task_fields=self._task.dump_attrs(),
651
+ ),
652
+ )
736
653
 
737
654
  if 'ansible_facts' in result and self._task.action not in C._ACTION_DEBUG:
738
655
  if self._task.action in C._ACTION_WITH_CLEAN_FACTS:
@@ -745,10 +662,11 @@ class TaskExecutor:
745
662
  vars_copy.update(result['ansible_facts'])
746
663
  else:
747
664
  # TODO: cleaning of facts should eventually become part of taskresults instead of vars
748
- af = wrap_var(result['ansible_facts'])
665
+ af = result['ansible_facts']
749
666
  vars_copy['ansible_facts'] = combine_vars(vars_copy.get('ansible_facts', {}), namespace_facts(af))
750
667
  if C.INJECT_FACTS_AS_VARS:
751
- vars_copy.update(clean_facts(af))
668
+ cleaned_toplevel = {k: _deprecate_top_level_fact(v) for k, v in clean_facts(af).items()}
669
+ vars_copy.update(cleaned_toplevel)
752
670
 
753
671
  # set the failed property if it was missing.
754
672
  if 'failed' not in result:
@@ -766,9 +684,6 @@ class TaskExecutor:
766
684
  if 'changed' not in result:
767
685
  result['changed'] = False
768
686
 
769
- if self._task.action not in C._ACTION_WITH_CLEAN_FACTS:
770
- result = wrap_var(result)
771
-
772
687
  # re-update the local copy of vars with the registered value, if specified,
773
688
  # or any facts which may have been generated by the module execution
774
689
  # This gives changed/failed_when access to additional recently modified
@@ -781,18 +696,30 @@ class TaskExecutor:
781
696
  if 'skipped' not in result:
782
697
  condname = 'changed'
783
698
 
699
+ # DTFIX-FUTURE: error normalization has not yet occurred; this means that the expressions used for until/failed_when/changed_when/break_when
700
+ # and when (for loops on the second and later iterations) cannot see the normalized error shapes. This, and the current impl of the expression
701
+ # handling here causes a number of problems:
702
+ # * any error in one of the post-task exec expressions is silently ignored and detail lost (eg: `failed_when: syntax ERROR @$123`)
703
+ # * they cannot reliably access error/warning details, since many of those details are inaccessible until the error normalization occurs
704
+ # * error normalization includes `msg` if present, and supplies `unknown error` if not; this leads to screwy results on True failed_when if
705
+ # `msg` is present, eg: `{debug: {}, failed_when: True` -> "Task failed: Action failed: Hello world!"
706
+ # * detail about failed_when is lost; any error details from the task could potentially be grafted in/preserved if error normalization was done
707
+
784
708
  try:
785
- _evaluate_changed_when_result(result)
709
+ if self._task.changed_when is not None and self._task.changed_when:
710
+ result['changed'] = self._task._resolve_conditional(self._task.changed_when, vars_copy)
711
+
786
712
  condname = 'failed'
787
- _evaluate_failed_when_result(result)
713
+
714
+ if self._task.failed_when:
715
+ result['failed_when_result'] = result['failed'] = self._task._resolve_conditional(self._task.failed_when, vars_copy)
716
+
788
717
  except AnsibleError as e:
789
718
  result['failed'] = True
790
719
  result['%s_when_result' % condname] = to_text(e)
791
720
 
792
721
  if retries > 1:
793
- cond = Conditional(loader=self._loader)
794
- cond.when = self._task.until or [not result['failed']]
795
- if cond.evaluate_conditional(templar, vars_copy):
722
+ if self._task._resolve_conditional(self._task.until or [not result['failed']], vars_copy):
796
723
  break
797
724
  else:
798
725
  # no conditional check, or it failed, so sleep for the specified time
@@ -802,12 +729,12 @@ class TaskExecutor:
802
729
  display.debug('Retrying task, attempt %d of %d' % (attempt, retries))
803
730
  self._final_q.send_callback(
804
731
  'v2_runner_retry',
805
- TaskResult(
806
- self._host.name,
807
- self._task._uuid,
808
- result,
732
+ _RawTaskResult(
733
+ host=self._host,
734
+ task=self._task,
735
+ return_data=result,
809
736
  task_fields=self._task.dump_attrs()
810
- )
737
+ ),
811
738
  )
812
739
  time.sleep(delay)
813
740
  self._handler = self._get_action_handler(templar=templar)
@@ -817,9 +744,6 @@ class TaskExecutor:
817
744
  result['attempts'] = retries - 1
818
745
  result['failed'] = True
819
746
 
820
- if self._task.action not in C._ACTION_WITH_CLEAN_FACTS:
821
- result = wrap_var(result)
822
-
823
747
  # do the final update of the local variables here, for both registered
824
748
  # values and any facts which may have been created
825
749
  if self._task.register:
@@ -830,10 +754,12 @@ class TaskExecutor:
830
754
  variables.update(result['ansible_facts'])
831
755
  else:
832
756
  # TODO: cleaning of facts should eventually become part of taskresults instead of vars
833
- af = wrap_var(result['ansible_facts'])
757
+ af = result['ansible_facts']
834
758
  variables['ansible_facts'] = combine_vars(variables.get('ansible_facts', {}), namespace_facts(af))
835
759
  if C.INJECT_FACTS_AS_VARS:
836
- variables.update(clean_facts(af))
760
+ # DTFIX-FUTURE: why is this happening twice, esp since we're post-fork and these will be discarded?
761
+ cleaned_toplevel = {k: _deprecate_top_level_fact(v) for k, v in clean_facts(af).items()}
762
+ variables.update(cleaned_toplevel)
837
763
 
838
764
  # save the notification target in the result, if it was specified, as
839
765
  # this task may be running in a loop in which case the notification
@@ -858,10 +784,53 @@ class TaskExecutor:
858
784
  display.debug("attempt loop complete, returning result")
859
785
  return result
860
786
 
787
+ @staticmethod
788
+ def _apply_task_result_compat(result: dict[str, t.Any], warning_ctx: _DeferredWarningContext) -> None:
789
+ """Apply backward-compatibility mutations to the supplied task result."""
790
+ if warnings := result.get('warnings'):
791
+ if isinstance(warnings, list):
792
+ for warning in warnings:
793
+ if not isinstance(warning, _messages.WarningSummary):
794
+ # translate non-WarningMessageDetail messages
795
+ warning = _messages.WarningSummary(
796
+ event=_messages.Event(
797
+ msg=str(warning),
798
+ ),
799
+ )
800
+
801
+ warning_ctx.capture(warning)
802
+ else:
803
+ display.warning(f"Task result `warnings` was {type(warnings)} instead of {list}.")
804
+
805
+ if deprecations := result.get('deprecations'):
806
+ if isinstance(deprecations, list):
807
+ for deprecation in deprecations:
808
+ if not isinstance(deprecation, _messages.DeprecationSummary):
809
+ # translate non-DeprecationSummary message dicts
810
+ try:
811
+ if (collection_name := deprecation.pop('collection_name', ...)) is not ...:
812
+ # deprecated: description='enable the deprecation message for collection_name' core_version='2.23'
813
+ # CAUTION: This deprecation cannot be enabled until the replacement (deprecator) has been documented, and the schema finalized.
814
+ # self.deprecated('The `collection_name` key in the `deprecations` dictionary is deprecated.', version='2.27')
815
+ deprecation.update(deprecator=deprecator_from_collection_name(collection_name))
816
+
817
+ deprecation = _messages.DeprecationSummary(
818
+ event=_messages.Event(
819
+ msg=deprecation.pop('msg'),
820
+ ),
821
+ **deprecation,
822
+ )
823
+ except Exception as ex:
824
+ display.error_as_warning("Task result `deprecations` contained an invalid item.", exception=ex)
825
+
826
+ warning_ctx.capture(deprecation)
827
+ else:
828
+ display.warning(f"Task result `deprecations` was {type(deprecations)} instead of {list}.")
829
+
861
830
  def _poll_async_result(self, result, templar, task_vars=None):
862
- '''
831
+ """
863
832
  Polls for the specified JID to be complete
864
- '''
833
+ """
865
834
 
866
835
  if task_vars is None:
867
836
  task_vars = self._job_vars
@@ -891,7 +860,7 @@ class TaskExecutor:
891
860
  connection=self._connection,
892
861
  play_context=self._play_context,
893
862
  loader=self._loader,
894
- templar=templar,
863
+ templar=Templar._from_template_engine(templar),
895
864
  shared_loader_obj=self._shared_loader_obj,
896
865
  )
897
866
 
@@ -903,12 +872,12 @@ class TaskExecutor:
903
872
  async_result = async_handler.run(task_vars=task_vars)
904
873
  # We do not bail out of the loop in cases where the failure
905
874
  # is associated with a parsing error. The async_runner can
906
- # have issues which result in a half-written/unparseable result
875
+ # have issues which result in a half-written/unparsable result
907
876
  # file on disk, which manifests to the user as a timeout happening
908
877
  # before it's time to timeout.
909
- if (int(async_result.get('finished', 0)) == 1 or
910
- ('failed' in async_result and async_result.get('_ansible_parsed', False)) or
911
- 'skipped' in async_result):
878
+ if (async_result.get('finished', False) or
879
+ (async_result.get('failed', False) and async_result.get('_ansible_parsed', False)) or
880
+ async_result.get('skipped', False)):
912
881
  break
913
882
  except Exception as e:
914
883
  # Connections can raise exceptions during polling (eg, network bounce, reboot); these should be non-fatal.
@@ -929,19 +898,19 @@ class TaskExecutor:
929
898
  time_left -= self._task.poll
930
899
  self._final_q.send_callback(
931
900
  'v2_runner_on_async_poll',
932
- TaskResult(
933
- self._host.name,
934
- async_task._uuid,
935
- async_result,
901
+ _RawTaskResult(
902
+ host=self._host,
903
+ task=async_task,
904
+ return_data=async_result,
936
905
  task_fields=async_task.dump_attrs(),
937
906
  ),
938
907
  )
939
908
 
940
- if int(async_result.get('finished', 0)) != 1:
909
+ if not async_result.get('finished', False):
941
910
  if async_result.get('_ansible_parsed'):
942
911
  return dict(failed=True, msg="async task did not complete within the requested time - %ss" % self._task.async_val, async_result=async_result)
943
912
  else:
944
- return dict(failed=True, msg="async task produced unparseable results", async_result=async_result)
913
+ return dict(failed=True, msg="async task produced unparsable results", async_result=async_result)
945
914
  else:
946
915
  # If the async task finished, automatically cleanup the temporary
947
916
  # status file left behind.
@@ -961,7 +930,7 @@ class TaskExecutor:
961
930
  connection=self._connection,
962
931
  play_context=self._play_context,
963
932
  loader=self._loader,
964
- templar=templar,
933
+ templar=Templar._from_template_engine(templar),
965
934
  shared_loader_obj=self._shared_loader_obj,
966
935
  )
967
936
  cleanup_handler.run(task_vars=task_vars)
@@ -977,10 +946,10 @@ class TaskExecutor:
977
946
  return become
978
947
 
979
948
  def _get_connection(self, cvars, templar, current_connection):
980
- '''
949
+ """
981
950
  Reads the connection property for the host, and returns the
982
951
  correct connection object from the list of connection plugins
983
- '''
952
+ """
984
953
 
985
954
  self._play_context.connection = current_connection
986
955
 
@@ -992,7 +961,7 @@ class TaskExecutor:
992
961
  connection, plugin_load_context = self._shared_loader_obj.connection_loader.get_with_context(
993
962
  conn_type,
994
963
  self._play_context,
995
- self._new_stdin,
964
+ new_stdin=None, # No longer used, kept for backwards compat for plugins that explicitly accept this as an arg
996
965
  task_uuid=self._task._uuid,
997
966
  ansible_playbook_pid=to_text(os.getppid())
998
967
  )
@@ -1058,7 +1027,11 @@ class TaskExecutor:
1058
1027
  options = {}
1059
1028
  for k in option_vars:
1060
1029
  if k in variables:
1061
- options[k] = templar.template(variables[k])
1030
+ try:
1031
+ options[k] = templar.template(variables[k])
1032
+ except AnsibleValueOmittedError:
1033
+ pass
1034
+
1062
1035
  # TODO move to task method?
1063
1036
  plugin.set_options(task_keys=task_keys, var_options=options)
1064
1037
 
@@ -1124,15 +1097,15 @@ class TaskExecutor:
1124
1097
  return varnames
1125
1098
 
1126
1099
  def _get_action_handler(self, templar):
1127
- '''
1100
+ """
1128
1101
  Returns the correct action plugin to handle the requestion task action
1129
- '''
1102
+ """
1130
1103
  return self._get_action_handler_with_module_context(templar)[0]
1131
1104
 
1132
- def _get_action_handler_with_module_context(self, templar):
1133
- '''
1105
+ def _get_action_handler_with_module_context(self, templar: TemplateEngine):
1106
+ """
1134
1107
  Returns the correct action plugin to handle the requestion task action and the module context
1135
- '''
1108
+ """
1136
1109
  module_collection, separator, module_name = self._task.action.rpartition(".")
1137
1110
  module_prefix = module_name.split('_')[0]
1138
1111
  if module_collection:
@@ -1156,7 +1129,7 @@ class TaskExecutor:
1156
1129
  # let action plugin override module, fallback to 'normal' action plugin otherwise
1157
1130
  elif self._shared_loader_obj.action_loader.has_plugin(self._task.action, collection_list=collections):
1158
1131
  handler_name = self._task.action
1159
- elif all((module_prefix in C.NETWORK_GROUP_MODULES, self._shared_loader_obj.action_loader.has_plugin(network_action, collection_list=collections))):
1132
+ elif module_prefix in C.NETWORK_GROUP_MODULES and self._shared_loader_obj.action_loader.has_plugin(network_action, collection_list=collections):
1160
1133
  handler_name = network_action
1161
1134
  display.vvvv("Using network group action {handler} for {action}".format(handler=handler_name,
1162
1135
  action=self._task.action),
@@ -1191,7 +1164,7 @@ class TaskExecutor:
1191
1164
  connection=self._connection,
1192
1165
  play_context=self._play_context,
1193
1166
  loader=self._loader,
1194
- templar=templar,
1167
+ templar=Templar._from_template_engine(templar),
1195
1168
  shared_loader_obj=self._shared_loader_obj,
1196
1169
  collection_list=collections
1197
1170
  )
@@ -1206,9 +1179,9 @@ CLI_STUB_NAME = 'ansible_connection_cli_stub.py'
1206
1179
 
1207
1180
 
1208
1181
  def start_connection(play_context, options, task_uuid):
1209
- '''
1182
+ """
1210
1183
  Starts the persistent connection
1211
- '''
1184
+ """
1212
1185
 
1213
1186
  env = os.environ.copy()
1214
1187
  env.update({