ansible-core 2.18.5rc1__py3-none-any.whl → 2.19.0b2__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.
Files changed (710) hide show
  1. ansible/_internal/__init__.py +53 -0
  2. ansible/_internal/_ansiballz.py +265 -0
  3. ansible/_internal/_collection_proxy.py +47 -0
  4. ansible/_internal/_datatag/__init__.py +0 -0
  5. ansible/_internal/_datatag/_tags.py +130 -0
  6. ansible/_internal/_datatag/_utils.py +19 -0
  7. ansible/_internal/_datatag/_wrappers.py +33 -0
  8. ansible/_internal/_errors/__init__.py +0 -0
  9. ansible/_internal/_errors/_captured.py +128 -0
  10. ansible/_internal/_errors/_handler.py +91 -0
  11. ansible/_internal/_errors/_utils.py +310 -0
  12. ansible/_internal/_json/__init__.py +203 -0
  13. ansible/_internal/_json/_legacy_encoder.py +34 -0
  14. ansible/_internal/_json/_profiles/__init__.py +0 -0
  15. ansible/_internal/_json/_profiles/_cache_persistence.py +55 -0
  16. ansible/_internal/_json/_profiles/_inventory_legacy.py +40 -0
  17. ansible/_internal/_json/_profiles/_legacy.py +197 -0
  18. ansible/_internal/_locking.py +21 -0
  19. ansible/_internal/_plugins/__init__.py +0 -0
  20. ansible/_internal/_plugins/_cache.py +57 -0
  21. ansible/_internal/_task.py +78 -0
  22. ansible/_internal/_templating/__init__.py +10 -0
  23. ansible/_internal/_templating/_access.py +86 -0
  24. ansible/_internal/_templating/_chain_templar.py +63 -0
  25. ansible/_internal/_templating/_datatag.py +95 -0
  26. ansible/_internal/_templating/_engine.py +588 -0
  27. ansible/_internal/_templating/_errors.py +28 -0
  28. ansible/_internal/_templating/_jinja_bits.py +1066 -0
  29. ansible/_internal/_templating/_jinja_common.py +332 -0
  30. ansible/_internal/_templating/_jinja_patches.py +44 -0
  31. ansible/_internal/_templating/_jinja_plugins.py +345 -0
  32. ansible/_internal/_templating/_lazy_containers.py +633 -0
  33. ansible/_internal/_templating/_marker_behaviors.py +103 -0
  34. ansible/_internal/_templating/_transform.py +63 -0
  35. ansible/_internal/_templating/_utils.py +107 -0
  36. ansible/_internal/_wrapt.py +1052 -0
  37. ansible/_internal/_yaml/__init__.py +0 -0
  38. ansible/_internal/_yaml/_constructor.py +240 -0
  39. ansible/_internal/_yaml/_dumper.py +62 -0
  40. ansible/_internal/_yaml/_errors.py +166 -0
  41. ansible/_internal/_yaml/_loader.py +66 -0
  42. ansible/_internal/ansible_collections/ansible/_protomatter/README.md +11 -0
  43. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/debug.py +36 -0
  44. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/apply_trust.py +19 -0
  45. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py +18 -0
  46. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/finalize.py +16 -0
  47. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/origin.py +18 -0
  48. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.py +24 -0
  49. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.yml +33 -0
  50. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/tag_names.py +16 -0
  51. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +17 -0
  52. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +49 -0
  53. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.py +21 -0
  54. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.yml +2 -0
  55. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.py +15 -0
  56. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.yml +19 -0
  57. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.py +18 -0
  58. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.yml +19 -0
  59. ansible/cli/__init__.py +159 -89
  60. ansible/cli/_ssh_askpass.py +47 -0
  61. ansible/cli/adhoc.py +14 -7
  62. ansible/cli/arguments/option_helpers.py +154 -7
  63. ansible/cli/config.py +43 -68
  64. ansible/cli/console.py +10 -8
  65. ansible/cli/doc.py +62 -53
  66. ansible/cli/galaxy.py +27 -20
  67. ansible/cli/inventory.py +28 -26
  68. ansible/cli/playbook.py +4 -12
  69. ansible/cli/pull.py +51 -11
  70. ansible/cli/scripts/ansible_connection_cli_stub.py +7 -7
  71. ansible/cli/vault.py +12 -11
  72. ansible/compat/__init__.py +2 -2
  73. ansible/config/base.yml +166 -112
  74. ansible/config/manager.py +52 -49
  75. ansible/constants.py +3 -4
  76. ansible/errors/__init__.py +277 -235
  77. ansible/executor/interpreter_discovery.py +28 -149
  78. ansible/executor/module_common.py +426 -493
  79. ansible/executor/play_iterator.py +22 -27
  80. ansible/executor/playbook_executor.py +11 -11
  81. ansible/executor/powershell/async_watchdog.ps1 +97 -102
  82. ansible/executor/powershell/async_wrapper.ps1 +202 -151
  83. ansible/executor/powershell/become_wrapper.ps1 +89 -144
  84. ansible/executor/powershell/bootstrap_wrapper.ps1 +24 -9
  85. ansible/executor/powershell/coverage_wrapper.ps1 +82 -135
  86. ansible/executor/powershell/exec_wrapper.ps1 +462 -196
  87. ansible/executor/powershell/module_manifest.py +417 -265
  88. ansible/executor/powershell/module_wrapper.ps1 +169 -186
  89. ansible/executor/powershell/psrp_fetch_file.ps1 +41 -0
  90. ansible/executor/powershell/psrp_put_file.ps1 +122 -0
  91. ansible/executor/powershell/winrm_fetch_file.ps1 +46 -0
  92. ansible/executor/powershell/winrm_put_file.ps1 +36 -0
  93. ansible/executor/process/worker.py +161 -96
  94. ansible/executor/stats.py +5 -5
  95. ansible/executor/task_executor.py +268 -258
  96. ansible/executor/task_queue_manager.py +124 -90
  97. ansible/executor/task_result.py +183 -78
  98. ansible/galaxy/__init__.py +2 -2
  99. ansible/galaxy/api.py +22 -18
  100. ansible/galaxy/collection/__init__.py +1 -1
  101. ansible/galaxy/collection/concrete_artifact_manager.py +8 -11
  102. ansible/galaxy/dependency_resolution/dataclasses.py +14 -4
  103. ansible/galaxy/dependency_resolution/providers.py +1 -1
  104. ansible/galaxy/dependency_resolution/reporters.py +81 -0
  105. ansible/galaxy/role.py +4 -8
  106. ansible/galaxy/token.py +28 -21
  107. ansible/inventory/data.py +47 -57
  108. ansible/inventory/group.py +44 -72
  109. ansible/inventory/helpers.py +9 -0
  110. ansible/inventory/host.py +32 -54
  111. ansible/inventory/manager.py +78 -34
  112. ansible/keyword_desc.yml +1 -1
  113. ansible/module_utils/_internal/__init__.py +55 -0
  114. ansible/module_utils/_internal/_ambient_context.py +58 -0
  115. ansible/module_utils/_internal/_ansiballz.py +133 -0
  116. ansible/module_utils/_internal/_concurrent/_daemon_threading.py +1 -0
  117. ansible/module_utils/_internal/_dataclass_annotation_patch.py +64 -0
  118. ansible/module_utils/_internal/_dataclass_validation.py +217 -0
  119. ansible/module_utils/_internal/_datatag/__init__.py +928 -0
  120. ansible/module_utils/_internal/_datatag/_tags.py +38 -0
  121. ansible/module_utils/_internal/_debugging.py +31 -0
  122. ansible/module_utils/_internal/_errors.py +30 -0
  123. ansible/module_utils/_internal/_json/__init__.py +63 -0
  124. ansible/module_utils/_internal/_json/_legacy_encoder.py +26 -0
  125. ansible/module_utils/_internal/_json/_profiles/__init__.py +410 -0
  126. ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py +73 -0
  127. ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +31 -0
  128. ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +35 -0
  129. ansible/module_utils/_internal/_json/_profiles/_module_modern_c2m.py +35 -0
  130. ansible/module_utils/_internal/_json/_profiles/_module_modern_m2c.py +33 -0
  131. ansible/module_utils/_internal/_json/_profiles/_tagless.py +50 -0
  132. ansible/module_utils/_internal/_patches/__init__.py +66 -0
  133. ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +55 -0
  134. ansible/module_utils/_internal/_patches/_socket_patch.py +34 -0
  135. ansible/module_utils/_internal/_patches/_sys_intern_patch.py +34 -0
  136. ansible/module_utils/_internal/_plugin_exec_context.py +49 -0
  137. ansible/module_utils/_internal/_testing.py +0 -0
  138. ansible/module_utils/_internal/_traceback.py +89 -0
  139. ansible/module_utils/ansible_release.py +2 -2
  140. ansible/module_utils/api.py +1 -2
  141. ansible/module_utils/basic.py +152 -120
  142. ansible/module_utils/common/_utils.py +24 -28
  143. ansible/module_utils/common/collections.py +1 -2
  144. ansible/module_utils/common/dict_transformations.py +2 -2
  145. ansible/module_utils/common/file.py +2 -2
  146. ansible/module_utils/common/json.py +90 -84
  147. ansible/module_utils/common/locale.py +2 -2
  148. ansible/module_utils/common/messages.py +108 -0
  149. ansible/module_utils/common/parameters.py +27 -24
  150. ansible/module_utils/common/process.py +2 -2
  151. ansible/module_utils/common/respawn.py +41 -19
  152. ansible/module_utils/common/sentinel.py +66 -0
  153. ansible/module_utils/common/sys_info.py +8 -8
  154. ansible/module_utils/common/text/converters.py +16 -37
  155. ansible/module_utils/common/validation.py +35 -24
  156. ansible/module_utils/common/warnings.py +86 -25
  157. ansible/module_utils/common/yaml.py +29 -3
  158. ansible/module_utils/compat/datetime.py +33 -21
  159. ansible/module_utils/compat/paramiko.py +21 -10
  160. ansible/module_utils/compat/typing.py +6 -5
  161. ansible/module_utils/connection.py +2 -2
  162. ansible/module_utils/csharp/Ansible.Basic.cs +14 -11
  163. ansible/module_utils/csharp/Ansible.Become.cs +1 -0
  164. ansible/module_utils/csharp/Ansible._Async.cs +517 -0
  165. ansible/module_utils/datatag.py +46 -0
  166. ansible/module_utils/distro/__init__.py +2 -2
  167. ansible/module_utils/facts/ansible_collector.py +4 -5
  168. ansible/module_utils/facts/collector.py +13 -14
  169. ansible/module_utils/facts/compat.py +4 -4
  170. ansible/module_utils/facts/default_collectors.py +1 -1
  171. ansible/module_utils/facts/hardware/aix.py +34 -0
  172. ansible/module_utils/facts/hardware/base.py +1 -1
  173. ansible/module_utils/facts/hardware/darwin.py +1 -3
  174. ansible/module_utils/facts/hardware/freebsd.py +2 -2
  175. ansible/module_utils/facts/hardware/linux.py +4 -4
  176. ansible/module_utils/facts/namespace.py +1 -1
  177. ansible/module_utils/facts/network/base.py +1 -1
  178. ansible/module_utils/facts/network/fc_wwn.py +1 -2
  179. ansible/module_utils/facts/network/iscsi.py +1 -2
  180. ansible/module_utils/facts/network/nvme.py +1 -2
  181. ansible/module_utils/facts/other/facter.py +1 -2
  182. ansible/module_utils/facts/other/ohai.py +2 -3
  183. ansible/module_utils/facts/system/apparmor.py +1 -2
  184. ansible/module_utils/facts/system/caps.py +1 -1
  185. ansible/module_utils/facts/system/chroot.py +1 -2
  186. ansible/module_utils/facts/system/cmdline.py +1 -2
  187. ansible/module_utils/facts/system/date_time.py +5 -3
  188. ansible/module_utils/facts/system/distribution.py +9 -8
  189. ansible/module_utils/facts/system/dns.py +1 -1
  190. ansible/module_utils/facts/system/env.py +1 -2
  191. ansible/module_utils/facts/system/fips.py +7 -20
  192. ansible/module_utils/facts/system/loadavg.py +1 -2
  193. ansible/module_utils/facts/system/local.py +1 -2
  194. ansible/module_utils/facts/system/lsb.py +1 -2
  195. ansible/module_utils/facts/system/pkg_mgr.py +1 -2
  196. ansible/module_utils/facts/system/platform.py +1 -2
  197. ansible/module_utils/facts/system/python.py +1 -2
  198. ansible/module_utils/facts/system/selinux.py +1 -1
  199. ansible/module_utils/facts/system/service_mgr.py +1 -2
  200. ansible/module_utils/facts/system/ssh_pub_keys.py +1 -1
  201. ansible/module_utils/facts/system/systemd.py +1 -1
  202. ansible/module_utils/facts/system/user.py +1 -2
  203. ansible/module_utils/facts/utils.py +3 -3
  204. ansible/module_utils/facts/virtual/base.py +1 -1
  205. ansible/module_utils/facts/virtual/sunos.py +3 -15
  206. ansible/module_utils/facts/virtual/sysctl.py +3 -16
  207. ansible/module_utils/json_utils.py +2 -2
  208. ansible/module_utils/parsing/convert_bool.py +1 -1
  209. ansible/module_utils/service.py +18 -21
  210. ansible/module_utils/splitter.py +7 -7
  211. ansible/module_utils/testing.py +31 -0
  212. ansible/module_utils/urls.py +60 -31
  213. ansible/modules/add_host.py +4 -4
  214. ansible/modules/apt.py +60 -46
  215. ansible/modules/apt_key.py +19 -12
  216. ansible/modules/apt_repository.py +19 -16
  217. ansible/modules/assemble.py +6 -6
  218. ansible/modules/assert.py +4 -4
  219. ansible/modules/async_status.py +10 -12
  220. ansible/modules/async_wrapper.py +8 -3
  221. ansible/modules/blockinfile.py +6 -7
  222. ansible/modules/command.py +10 -17
  223. ansible/modules/copy.py +57 -144
  224. ansible/modules/cron.py +20 -15
  225. ansible/modules/deb822_repository.py +8 -9
  226. ansible/modules/debconf.py +5 -5
  227. ansible/modules/debug.py +4 -4
  228. ansible/modules/dnf.py +8 -8
  229. ansible/modules/dnf5.py +39 -13
  230. ansible/modules/dpkg_selections.py +4 -4
  231. ansible/modules/expect.py +8 -10
  232. ansible/modules/fail.py +4 -4
  233. ansible/modules/fetch.py +4 -4
  234. ansible/modules/file.py +174 -133
  235. ansible/modules/find.py +19 -17
  236. ansible/modules/gather_facts.py +3 -3
  237. ansible/modules/get_url.py +59 -53
  238. ansible/modules/getent.py +7 -9
  239. ansible/modules/git.py +28 -25
  240. ansible/modules/group.py +6 -6
  241. ansible/modules/group_by.py +4 -4
  242. ansible/modules/hostname.py +13 -29
  243. ansible/modules/import_playbook.py +6 -6
  244. ansible/modules/import_role.py +6 -6
  245. ansible/modules/import_tasks.py +6 -6
  246. ansible/modules/include_role.py +6 -6
  247. ansible/modules/include_tasks.py +6 -6
  248. ansible/modules/include_vars.py +6 -6
  249. ansible/modules/iptables.py +86 -73
  250. ansible/modules/known_hosts.py +10 -10
  251. ansible/modules/lineinfile.py +5 -5
  252. ansible/modules/meta.py +4 -4
  253. ansible/modules/mount_facts.py +2 -2
  254. ansible/modules/package.py +4 -4
  255. ansible/modules/package_facts.py +22 -10
  256. ansible/modules/pause.py +6 -6
  257. ansible/modules/ping.py +6 -6
  258. ansible/modules/pip.py +10 -11
  259. ansible/modules/raw.py +4 -4
  260. ansible/modules/reboot.py +6 -6
  261. ansible/modules/replace.py +9 -13
  262. ansible/modules/rpm_key.py +7 -8
  263. ansible/modules/script.py +4 -4
  264. ansible/modules/service.py +7 -8
  265. ansible/modules/service_facts.py +87 -10
  266. ansible/modules/set_fact.py +5 -5
  267. ansible/modules/set_stats.py +4 -4
  268. ansible/modules/setup.py +2 -2
  269. ansible/modules/shell.py +6 -6
  270. ansible/modules/slurp.py +6 -6
  271. ansible/modules/stat.py +9 -23
  272. ansible/modules/subversion.py +15 -15
  273. ansible/modules/systemd.py +6 -6
  274. ansible/modules/systemd_service.py +6 -6
  275. ansible/modules/sysvinit.py +6 -6
  276. ansible/modules/tempfile.py +5 -6
  277. ansible/modules/template.py +6 -6
  278. ansible/modules/unarchive.py +32 -11
  279. ansible/modules/uri.py +33 -26
  280. ansible/modules/user.py +53 -34
  281. ansible/modules/validate_argument_spec.py +10 -7
  282. ansible/modules/wait_for.py +32 -27
  283. ansible/modules/wait_for_connection.py +6 -6
  284. ansible/modules/yum_repository.py +6 -6
  285. ansible/parsing/ajson.py +14 -32
  286. ansible/parsing/dataloader.py +99 -54
  287. ansible/parsing/mod_args.py +28 -44
  288. ansible/parsing/plugin_docs.py +21 -86
  289. ansible/parsing/quoting.py +1 -1
  290. ansible/parsing/splitter.py +27 -12
  291. ansible/parsing/utils/addresses.py +24 -24
  292. ansible/parsing/utils/jsonify.py +5 -1
  293. ansible/parsing/utils/yaml.py +32 -61
  294. ansible/parsing/vault/__init__.py +319 -87
  295. ansible/parsing/yaml/__init__.py +0 -18
  296. ansible/parsing/yaml/dumper.py +6 -120
  297. ansible/parsing/yaml/loader.py +6 -39
  298. ansible/parsing/yaml/objects.py +43 -335
  299. ansible/playbook/__init__.py +1 -1
  300. ansible/playbook/attribute.py +8 -3
  301. ansible/playbook/base.py +182 -132
  302. ansible/playbook/block.py +26 -24
  303. ansible/playbook/collectionsearch.py +1 -15
  304. ansible/playbook/conditional.py +3 -77
  305. ansible/playbook/handler.py +8 -2
  306. ansible/playbook/helpers.py +41 -53
  307. ansible/playbook/included_file.py +31 -27
  308. ansible/playbook/loop_control.py +2 -2
  309. ansible/playbook/play.py +85 -44
  310. ansible/playbook/play_context.py +12 -17
  311. ansible/playbook/playbook_include.py +14 -15
  312. ansible/playbook/role/__init__.py +24 -26
  313. ansible/playbook/role/definition.py +15 -17
  314. ansible/playbook/role/include.py +2 -4
  315. ansible/playbook/role/metadata.py +10 -11
  316. ansible/playbook/role_include.py +3 -3
  317. ansible/playbook/taggable.py +13 -8
  318. ansible/playbook/task.py +188 -118
  319. ansible/playbook/task_include.py +5 -5
  320. ansible/plugins/__init__.py +68 -21
  321. ansible/plugins/action/__init__.py +209 -176
  322. ansible/plugins/action/add_host.py +1 -1
  323. ansible/plugins/action/assemble.py +1 -1
  324. ansible/plugins/action/assert.py +54 -66
  325. ansible/plugins/action/copy.py +7 -11
  326. ansible/plugins/action/debug.py +37 -31
  327. ansible/plugins/action/dnf.py +3 -4
  328. ansible/plugins/action/fail.py +1 -1
  329. ansible/plugins/action/fetch.py +4 -5
  330. ansible/plugins/action/gather_facts.py +7 -6
  331. ansible/plugins/action/group_by.py +1 -1
  332. ansible/plugins/action/include_vars.py +10 -11
  333. ansible/plugins/action/package.py +3 -6
  334. ansible/plugins/action/pause.py +2 -2
  335. ansible/plugins/action/script.py +15 -8
  336. ansible/plugins/action/service.py +6 -11
  337. ansible/plugins/action/set_fact.py +3 -12
  338. ansible/plugins/action/set_stats.py +3 -8
  339. ansible/plugins/action/template.py +35 -59
  340. ansible/plugins/action/unarchive.py +1 -1
  341. ansible/plugins/action/validate_argument_spec.py +5 -5
  342. ansible/plugins/action/wait_for_connection.py +1 -1
  343. ansible/plugins/become/__init__.py +31 -8
  344. ansible/plugins/become/runas.py +71 -0
  345. ansible/plugins/become/su.py +13 -8
  346. ansible/plugins/become/sudo.py +19 -0
  347. ansible/plugins/cache/__init__.py +35 -44
  348. ansible/plugins/cache/base.py +8 -0
  349. ansible/plugins/cache/jsonfile.py +10 -16
  350. ansible/plugins/cache/memory.py +6 -12
  351. ansible/plugins/callback/__init__.py +284 -179
  352. ansible/plugins/callback/default.py +99 -92
  353. ansible/plugins/callback/junit.py +44 -39
  354. ansible/plugins/callback/minimal.py +28 -25
  355. ansible/plugins/callback/oneline.py +28 -21
  356. ansible/plugins/callback/tree.py +16 -11
  357. ansible/plugins/connection/__init__.py +47 -34
  358. ansible/plugins/connection/local.py +150 -54
  359. ansible/plugins/connection/paramiko_ssh.py +21 -18
  360. ansible/plugins/connection/psrp.py +76 -165
  361. ansible/plugins/connection/ssh.py +301 -78
  362. ansible/plugins/connection/winrm.py +58 -140
  363. ansible/plugins/doc_fragments/action_common_attributes.py +14 -14
  364. ansible/plugins/doc_fragments/action_core.py +6 -6
  365. ansible/plugins/doc_fragments/backup.py +2 -2
  366. ansible/plugins/doc_fragments/checksum_common.py +27 -0
  367. ansible/plugins/doc_fragments/constructed.py +6 -2
  368. ansible/plugins/doc_fragments/decrypt.py +2 -2
  369. ansible/plugins/doc_fragments/default_callback.py +2 -2
  370. ansible/plugins/doc_fragments/files.py +2 -2
  371. ansible/plugins/doc_fragments/inventory_cache.py +2 -2
  372. ansible/plugins/doc_fragments/result_format_callback.py +2 -2
  373. ansible/plugins/doc_fragments/return_common.py +2 -2
  374. ansible/plugins/doc_fragments/template_common.py +4 -4
  375. ansible/plugins/doc_fragments/url.py +17 -1
  376. ansible/plugins/doc_fragments/url_windows.py +2 -2
  377. ansible/plugins/doc_fragments/validate.py +2 -2
  378. ansible/plugins/doc_fragments/vars_plugin_staging.py +2 -2
  379. ansible/plugins/filter/__init__.py +6 -2
  380. ansible/plugins/filter/b64decode.yml +22 -0
  381. ansible/plugins/filter/b64encode.yml +22 -0
  382. ansible/plugins/filter/bool.yml +11 -4
  383. ansible/plugins/filter/core.py +225 -108
  384. ansible/plugins/filter/encryption.py +32 -32
  385. ansible/plugins/filter/flatten.yml +3 -2
  386. ansible/plugins/filter/human_to_bytes.yml +1 -1
  387. ansible/plugins/filter/mathstuff.py +30 -37
  388. ansible/plugins/filter/password_hash.yml +8 -0
  389. ansible/plugins/filter/regex_search.yml +1 -4
  390. ansible/plugins/filter/split.yml +1 -1
  391. ansible/plugins/filter/to_nice_yaml.yml +0 -4
  392. ansible/plugins/filter/to_yaml.yml +0 -4
  393. ansible/plugins/filter/unvault.yml +1 -1
  394. ansible/plugins/filter/urls.py +1 -1
  395. ansible/plugins/filter/urlsplit.py +8 -9
  396. ansible/plugins/filter/vault.yml +14 -9
  397. ansible/plugins/filter/win_basename.yml +6 -1
  398. ansible/plugins/filter/win_dirname.yml +5 -0
  399. ansible/plugins/inventory/__init__.py +97 -77
  400. ansible/plugins/inventory/advanced_host_list.py +7 -5
  401. ansible/plugins/inventory/auto.py +11 -4
  402. ansible/plugins/inventory/constructed.py +21 -24
  403. ansible/plugins/inventory/generator.py +16 -11
  404. ansible/plugins/inventory/host_list.py +7 -5
  405. ansible/plugins/inventory/ini.py +78 -44
  406. ansible/plugins/inventory/script.py +189 -119
  407. ansible/plugins/inventory/toml.py +16 -126
  408. ansible/plugins/inventory/yaml.py +10 -8
  409. ansible/plugins/list.py +3 -3
  410. ansible/plugins/loader.py +197 -82
  411. ansible/plugins/lookup/__init__.py +21 -4
  412. ansible/plugins/lookup/config.py +21 -35
  413. ansible/plugins/lookup/csvfile.py +3 -2
  414. ansible/plugins/lookup/dict.py +1 -6
  415. ansible/plugins/lookup/env.py +12 -9
  416. ansible/plugins/lookup/file.py +5 -8
  417. ansible/plugins/lookup/first_found.py +86 -55
  418. ansible/plugins/lookup/indexed_items.py +1 -10
  419. ansible/plugins/lookup/ini.py +14 -13
  420. ansible/plugins/lookup/items.py +1 -1
  421. ansible/plugins/lookup/lines.py +8 -1
  422. ansible/plugins/lookup/list.py +1 -1
  423. ansible/plugins/lookup/nested.py +2 -18
  424. ansible/plugins/lookup/password.py +5 -5
  425. ansible/plugins/lookup/pipe.py +5 -7
  426. ansible/plugins/lookup/sequence.py +18 -8
  427. ansible/plugins/lookup/subelements.py +1 -4
  428. ansible/plugins/lookup/template.py +42 -36
  429. ansible/plugins/lookup/together.py +0 -12
  430. ansible/plugins/lookup/unvault.py +1 -5
  431. ansible/plugins/lookup/url.py +2 -8
  432. ansible/plugins/lookup/vars.py +16 -24
  433. ansible/plugins/shell/__init__.py +2 -2
  434. ansible/plugins/shell/cmd.py +2 -2
  435. ansible/plugins/shell/powershell.py +39 -22
  436. ansible/plugins/shell/sh.py +3 -2
  437. ansible/plugins/strategy/__init__.py +159 -184
  438. ansible/plugins/strategy/debug.py +2 -2
  439. ansible/plugins/strategy/free.py +16 -31
  440. ansible/plugins/strategy/host_pinned.py +2 -2
  441. ansible/plugins/strategy/linear.py +41 -41
  442. ansible/plugins/terminal/__init__.py +4 -4
  443. ansible/plugins/test/__init__.py +7 -2
  444. ansible/plugins/test/core.py +55 -21
  445. ansible/plugins/test/files.py +1 -1
  446. ansible/plugins/test/mathstuff.py +3 -3
  447. ansible/plugins/test/uri.py +3 -3
  448. ansible/plugins/vars/host_group_vars.py +7 -14
  449. ansible/release.py +2 -2
  450. ansible/template/__init__.py +370 -944
  451. ansible/utils/__init__.py +0 -18
  452. ansible/utils/_ssh_agent.py +657 -0
  453. ansible/utils/collection_loader/__init__.py +52 -5
  454. ansible/utils/collection_loader/_collection_config.py +5 -6
  455. ansible/utils/collection_loader/_collection_finder.py +79 -93
  456. ansible/utils/collection_loader/_collection_meta.py +13 -8
  457. ansible/utils/display.py +433 -63
  458. ansible/utils/encrypt.py +27 -19
  459. ansible/utils/fqcn.py +2 -2
  460. ansible/utils/hashing.py +2 -2
  461. ansible/utils/helpers.py +2 -2
  462. ansible/utils/listify.py +8 -8
  463. ansible/utils/lock.py +2 -2
  464. ansible/utils/path.py +4 -4
  465. ansible/utils/plugin_docs.py +14 -13
  466. ansible/utils/sentinel.py +4 -62
  467. ansible/utils/singleton.py +2 -0
  468. ansible/utils/ssh_functions.py +1 -1
  469. ansible/utils/unsafe_proxy.py +23 -332
  470. ansible/utils/vars.py +51 -8
  471. ansible/utils/version.py +2 -2
  472. ansible/vars/clean.py +5 -5
  473. ansible/vars/hostvars.py +60 -90
  474. ansible/vars/manager.py +206 -282
  475. ansible/vars/reserved.py +8 -9
  476. ansible_core-2.19.0b2.dist-info/BSD-3-Clause.txt +28 -0
  477. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/METADATA +5 -4
  478. ansible_core-2.19.0b2.dist-info/RECORD +1072 -0
  479. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/WHEEL +1 -1
  480. ansible_test/_data/completion/docker.txt +7 -7
  481. ansible_test/_data/completion/remote.txt +6 -6
  482. ansible_test/_data/completion/windows.txt +1 -0
  483. ansible_test/_data/requirements/ansible.txt +2 -2
  484. ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
  485. ansible_test/_data/requirements/sanity.changelog.txt +1 -1
  486. ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
  487. ansible_test/_data/requirements/sanity.pylint.txt +4 -4
  488. ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
  489. ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
  490. ansible_test/_data/requirements/units.txt +1 -0
  491. ansible_test/_internal/__init__.py +1 -0
  492. ansible_test/_internal/ansible_util.py +2 -0
  493. ansible_test/_internal/become.py +1 -0
  494. ansible_test/_internal/bootstrap.py +1 -0
  495. ansible_test/_internal/cache.py +1 -0
  496. ansible_test/_internal/cgroup.py +1 -0
  497. ansible_test/_internal/ci/__init__.py +1 -0
  498. ansible_test/_internal/ci/azp.py +1 -0
  499. ansible_test/_internal/ci/local.py +1 -0
  500. ansible_test/_internal/classification/__init__.py +1 -0
  501. ansible_test/_internal/classification/common.py +1 -0
  502. ansible_test/_internal/classification/csharp.py +1 -0
  503. ansible_test/_internal/classification/powershell.py +1 -0
  504. ansible_test/_internal/classification/python.py +1 -0
  505. ansible_test/_internal/cli/__init__.py +1 -0
  506. ansible_test/_internal/cli/actions.py +1 -0
  507. ansible_test/_internal/cli/argparsing/__init__.py +1 -0
  508. ansible_test/_internal/cli/argparsing/actions.py +1 -0
  509. ansible_test/_internal/cli/argparsing/argcompletion.py +1 -0
  510. ansible_test/_internal/cli/argparsing/parsers.py +1 -0
  511. ansible_test/_internal/cli/commands/__init__.py +11 -0
  512. ansible_test/_internal/cli/commands/coverage/__init__.py +1 -0
  513. ansible_test/_internal/cli/commands/coverage/analyze/__init__.py +1 -0
  514. ansible_test/_internal/cli/commands/coverage/analyze/targets/__init__.py +1 -0
  515. ansible_test/_internal/cli/commands/coverage/analyze/targets/combine.py +1 -0
  516. ansible_test/_internal/cli/commands/coverage/analyze/targets/expand.py +1 -0
  517. ansible_test/_internal/cli/commands/coverage/analyze/targets/filter.py +1 -0
  518. ansible_test/_internal/cli/commands/coverage/analyze/targets/generate.py +1 -0
  519. ansible_test/_internal/cli/commands/coverage/analyze/targets/missing.py +1 -0
  520. ansible_test/_internal/cli/commands/coverage/combine.py +1 -0
  521. ansible_test/_internal/cli/commands/coverage/erase.py +1 -0
  522. ansible_test/_internal/cli/commands/coverage/html.py +1 -0
  523. ansible_test/_internal/cli/commands/coverage/report.py +1 -0
  524. ansible_test/_internal/cli/commands/coverage/xml.py +1 -0
  525. ansible_test/_internal/cli/commands/env.py +1 -0
  526. ansible_test/_internal/cli/commands/integration/__init__.py +1 -0
  527. ansible_test/_internal/cli/commands/integration/network.py +1 -0
  528. ansible_test/_internal/cli/commands/integration/posix.py +1 -0
  529. ansible_test/_internal/cli/commands/integration/windows.py +1 -0
  530. ansible_test/_internal/cli/commands/sanity.py +9 -0
  531. ansible_test/_internal/cli/commands/shell.py +1 -0
  532. ansible_test/_internal/cli/commands/units.py +1 -0
  533. ansible_test/_internal/cli/compat.py +1 -0
  534. ansible_test/_internal/cli/completers.py +1 -0
  535. ansible_test/_internal/cli/converters.py +1 -0
  536. ansible_test/_internal/cli/environments.py +1 -0
  537. ansible_test/_internal/cli/epilog.py +1 -0
  538. ansible_test/_internal/cli/parsers/__init__.py +1 -0
  539. ansible_test/_internal/cli/parsers/base_argument_parsers.py +1 -0
  540. ansible_test/_internal/cli/parsers/helpers.py +1 -0
  541. ansible_test/_internal/cli/parsers/host_config_parsers.py +1 -0
  542. ansible_test/_internal/cli/parsers/key_value_parsers.py +1 -0
  543. ansible_test/_internal/cli/parsers/value_parsers.py +1 -0
  544. ansible_test/_internal/commands/__init__.py +1 -0
  545. ansible_test/_internal/commands/coverage/__init__.py +2 -1
  546. ansible_test/_internal/commands/coverage/analyze/__init__.py +1 -0
  547. ansible_test/_internal/commands/coverage/analyze/targets/__init__.py +1 -0
  548. ansible_test/_internal/commands/coverage/analyze/targets/combine.py +1 -0
  549. ansible_test/_internal/commands/coverage/analyze/targets/expand.py +1 -0
  550. ansible_test/_internal/commands/coverage/analyze/targets/filter.py +1 -0
  551. ansible_test/_internal/commands/coverage/analyze/targets/generate.py +1 -0
  552. ansible_test/_internal/commands/coverage/analyze/targets/missing.py +1 -0
  553. ansible_test/_internal/commands/coverage/combine.py +2 -1
  554. ansible_test/_internal/commands/coverage/erase.py +1 -0
  555. ansible_test/_internal/commands/coverage/html.py +1 -0
  556. ansible_test/_internal/commands/coverage/report.py +1 -0
  557. ansible_test/_internal/commands/coverage/xml.py +1 -0
  558. ansible_test/_internal/commands/env/__init__.py +2 -0
  559. ansible_test/_internal/commands/integration/__init__.py +4 -0
  560. ansible_test/_internal/commands/integration/cloud/__init__.py +1 -0
  561. ansible_test/_internal/commands/integration/cloud/acme.py +2 -1
  562. ansible_test/_internal/commands/integration/cloud/aws.py +1 -0
  563. ansible_test/_internal/commands/integration/cloud/azure.py +1 -0
  564. ansible_test/_internal/commands/integration/cloud/cs.py +1 -0
  565. ansible_test/_internal/commands/integration/cloud/digitalocean.py +1 -0
  566. ansible_test/_internal/commands/integration/cloud/galaxy.py +3 -2
  567. ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -0
  568. ansible_test/_internal/commands/integration/cloud/httptester.py +2 -1
  569. ansible_test/_internal/commands/integration/cloud/nios.py +2 -1
  570. ansible_test/_internal/commands/integration/cloud/opennebula.py +1 -0
  571. ansible_test/_internal/commands/integration/cloud/openshift.py +1 -0
  572. ansible_test/_internal/commands/integration/cloud/scaleway.py +1 -0
  573. ansible_test/_internal/commands/integration/cloud/vcenter.py +1 -0
  574. ansible_test/_internal/commands/integration/cloud/vultr.py +1 -0
  575. ansible_test/_internal/commands/integration/coverage.py +1 -0
  576. ansible_test/_internal/commands/integration/filters.py +1 -0
  577. ansible_test/_internal/commands/integration/network.py +1 -0
  578. ansible_test/_internal/commands/integration/posix.py +1 -0
  579. ansible_test/_internal/commands/integration/windows.py +1 -0
  580. ansible_test/_internal/commands/sanity/__init__.py +16 -1
  581. ansible_test/_internal/commands/sanity/ansible_doc.py +1 -0
  582. ansible_test/_internal/commands/sanity/bin_symlinks.py +1 -0
  583. ansible_test/_internal/commands/sanity/compile.py +1 -0
  584. ansible_test/_internal/commands/sanity/ignores.py +1 -0
  585. ansible_test/_internal/commands/sanity/import.py +1 -0
  586. ansible_test/_internal/commands/sanity/integration_aliases.py +1 -0
  587. ansible_test/_internal/commands/sanity/pep8.py +1 -0
  588. ansible_test/_internal/commands/sanity/pslint.py +1 -0
  589. ansible_test/_internal/commands/sanity/pylint.py +24 -26
  590. ansible_test/_internal/commands/sanity/shellcheck.py +1 -0
  591. ansible_test/_internal/commands/sanity/validate_modules.py +1 -0
  592. ansible_test/_internal/commands/sanity/yamllint.py +1 -0
  593. ansible_test/_internal/commands/shell/__init__.py +1 -0
  594. ansible_test/_internal/commands/units/__init__.py +1 -0
  595. ansible_test/_internal/compat/__init__.py +1 -0
  596. ansible_test/_internal/compat/packaging.py +1 -0
  597. ansible_test/_internal/compat/yaml.py +1 -0
  598. ansible_test/_internal/completion.py +1 -0
  599. ansible_test/_internal/config.py +2 -0
  600. ansible_test/_internal/connections.py +1 -0
  601. ansible_test/_internal/constants.py +1 -0
  602. ansible_test/_internal/containers.py +1 -0
  603. ansible_test/_internal/content_config.py +1 -0
  604. ansible_test/_internal/core_ci.py +1 -0
  605. ansible_test/_internal/coverage_util.py +11 -10
  606. ansible_test/_internal/data.py +1 -0
  607. ansible_test/_internal/delegation.py +1 -0
  608. ansible_test/_internal/dev/__init__.py +1 -0
  609. ansible_test/_internal/dev/container_probe.py +1 -0
  610. ansible_test/_internal/diff.py +3 -2
  611. ansible_test/_internal/docker_util.py +2 -1
  612. ansible_test/_internal/encoding.py +1 -0
  613. ansible_test/_internal/executor.py +1 -0
  614. ansible_test/_internal/git.py +1 -0
  615. ansible_test/_internal/host_configs.py +1 -0
  616. ansible_test/_internal/host_profiles.py +1 -0
  617. ansible_test/_internal/http.py +1 -0
  618. ansible_test/_internal/init.py +1 -0
  619. ansible_test/_internal/inventory.py +35 -3
  620. ansible_test/_internal/io.py +1 -0
  621. ansible_test/_internal/metadata.py +1 -0
  622. ansible_test/_internal/payload.py +1 -0
  623. ansible_test/_internal/provider/__init__.py +1 -0
  624. ansible_test/_internal/provider/layout/__init__.py +1 -0
  625. ansible_test/_internal/provider/layout/ansible.py +1 -0
  626. ansible_test/_internal/provider/layout/collection.py +1 -0
  627. ansible_test/_internal/provider/layout/unsupported.py +1 -0
  628. ansible_test/_internal/provider/source/__init__.py +1 -0
  629. ansible_test/_internal/provider/source/git.py +1 -0
  630. ansible_test/_internal/provider/source/installed.py +1 -0
  631. ansible_test/_internal/provider/source/unsupported.py +1 -0
  632. ansible_test/_internal/provider/source/unversioned.py +1 -0
  633. ansible_test/_internal/provisioning.py +1 -0
  634. ansible_test/_internal/pypi_proxy.py +6 -5
  635. ansible_test/_internal/python_requirements.py +1 -0
  636. ansible_test/_internal/ssh.py +1 -0
  637. ansible_test/_internal/target.py +1 -0
  638. ansible_test/_internal/test.py +3 -2
  639. ansible_test/_internal/thread.py +1 -0
  640. ansible_test/_internal/timeout.py +1 -0
  641. ansible_test/_internal/util.py +1 -0
  642. ansible_test/_internal/util_common.py +5 -2
  643. ansible_test/_internal/venv.py +1 -0
  644. ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +1 -0
  645. ansible_test/_util/controller/sanity/code-smell/changelog/sphinx.py +1 -0
  646. ansible_test/_util/controller/sanity/code-smell/changelog.py +1 -0
  647. ansible_test/_util/controller/sanity/code-smell/empty-init.py +1 -0
  648. ansible_test/_util/controller/sanity/code-smell/line-endings.py +1 -0
  649. ansible_test/_util/controller/sanity/code-smell/no-assert.py +1 -0
  650. ansible_test/_util/controller/sanity/code-smell/no-get-exception.py +1 -0
  651. ansible_test/_util/controller/sanity/code-smell/no-illegal-filenames.py +1 -0
  652. ansible_test/_util/controller/sanity/code-smell/no-smart-quotes.py +1 -0
  653. ansible_test/_util/controller/sanity/code-smell/replace-urlopen.py +1 -0
  654. ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +28 -1
  655. ansible_test/_util/controller/sanity/code-smell/shebang.py +1 -0
  656. ansible_test/_util/controller/sanity/code-smell/symlinks.py +1 -0
  657. ansible_test/_util/controller/sanity/code-smell/use-argspec-type-path.py +1 -0
  658. ansible_test/_util/controller/sanity/code-smell/use-compat-six.py +1 -0
  659. ansible_test/_util/controller/sanity/integration-aliases/yaml_to_json.py +2 -1
  660. ansible_test/_util/controller/sanity/pep8/current-ignore.txt +4 -0
  661. ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +7 -5
  662. ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +7 -5
  663. ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +7 -5
  664. ansible_test/_util/controller/sanity/pylint/config/collection.cfg +3 -5
  665. ansible_test/_util/controller/sanity/pylint/config/default.cfg +7 -7
  666. ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -13
  667. ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +1 -0
  668. ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +1 -8
  669. ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +1 -8
  670. ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +55 -28
  671. ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +12 -5
  672. ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +13 -2
  673. ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -0
  674. ansible_test/_util/controller/sanity/yamllint/yamllinter.py +35 -17
  675. ansible_test/_util/controller/tools/collection_detail.py +1 -0
  676. ansible_test/_util/controller/tools/yaml_to_json.py +2 -1
  677. ansible_test/_util/target/pytest/plugins/ansible_forked.py +6 -1
  678. ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py +2 -1
  679. ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +1 -0
  680. ansible_test/_util/target/sanity/compile/compile.py +1 -0
  681. ansible_test/_util/target/sanity/import/importer.py +15 -16
  682. ansible_test/_util/target/setup/bootstrap.sh +9 -20
  683. ansible_test/_util/target/setup/probe_cgroups.py +1 -0
  684. ansible_test/_util/target/setup/quiet_pip.py +1 -0
  685. ansible_test/_util/target/setup/requirements.py +35 -27
  686. ansible_test/_util/target/tools/virtualenvcheck.py +2 -1
  687. ansible_test/_util/target/tools/yamlcheck.py +2 -1
  688. ansible/compat/selectors.py +0 -32
  689. ansible/errors/yaml_strings.py +0 -138
  690. ansible/executor/action_write_locks.py +0 -44
  691. ansible/executor/discovery/python_target.py +0 -47
  692. ansible/executor/powershell/module_powershell_wrapper.ps1 +0 -86
  693. ansible/executor/powershell/module_script_wrapper.ps1 +0 -22
  694. ansible/module_utils/compat/importlib.py +0 -26
  695. ansible/module_utils/compat/selectors.py +0 -32
  696. ansible/module_utils/pycompat24.py +0 -73
  697. ansible/parsing/yaml/constructor.py +0 -178
  698. ansible/template/native_helpers.py +0 -251
  699. ansible/template/template.py +0 -43
  700. ansible/template/vars.py +0 -77
  701. ansible/utils/native_jinja.py +0 -11
  702. ansible/vars/fact_cache.py +0 -71
  703. ansible_core-2.18.5rc1.dist-info/RECORD +0 -992
  704. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/Apache-License.txt +0 -0
  705. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/COPYING +0 -0
  706. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/MIT-license.txt +0 -0
  707. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/PSF-license.txt +0 -0
  708. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/entry_points.txt +0 -0
  709. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/simplified_bsd.txt +0 -0
  710. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/top_level.txt +0 -0
@@ -4,38 +4,61 @@
4
4
  from __future__ import annotations
5
5
 
6
6
  import base64
7
+ import dataclasses
7
8
  import errno
8
9
  import json
9
10
  import os
10
11
  import pkgutil
11
12
  import secrets
12
13
  import re
14
+ import typing as t
15
+
13
16
  from importlib import import_module
14
17
 
15
18
  from ansible.module_utils.compat.version import LooseVersion
16
19
 
17
20
  from ansible import constants as C
18
- from ansible.errors import AnsibleError
19
- from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
21
+ from ansible.module_utils.common.json import Direction, get_module_encoder
22
+ from ansible.errors import AnsibleError, AnsibleFileNotFound
23
+ from ansible.module_utils.common.text.converters import to_bytes, to_text
24
+ from ansible.plugins.become import BecomeBase
25
+ from ansible.plugins.become.runas import BecomeModule as RunasBecomeModule
20
26
  from ansible.plugins.loader import ps_module_utils_loader
21
- from ansible.utils.collection_loader import resource_from_fqcr
27
+
28
+
29
+ @dataclasses.dataclass(frozen=True)
30
+ class _ExecManifest:
31
+ scripts: dict[str, _ScriptInfo] = dataclasses.field(default_factory=dict)
32
+ actions: list[_ManifestAction] = dataclasses.field(default_factory=list)
33
+
34
+
35
+ @dataclasses.dataclass(frozen=True, kw_only=True)
36
+ class _ScriptInfo:
37
+ content: dataclasses.InitVar[bytes]
38
+ path: str
39
+ script: str = dataclasses.field(init=False)
40
+
41
+ def __post_init__(self, content: bytes) -> None:
42
+ object.__setattr__(self, 'script', base64.b64encode(content).decode())
43
+
44
+
45
+ @dataclasses.dataclass(frozen=True, kw_only=True)
46
+ class _ManifestAction:
47
+ name: str
48
+ params: dict[str, object] = dataclasses.field(default_factory=dict)
49
+ secure_params: dict[str, object] = dataclasses.field(default_factory=dict)
22
50
 
23
51
 
24
52
  class PSModuleDepFinder(object):
25
53
 
26
- def __init__(self):
54
+ def __init__(self) -> None:
27
55
  # This is also used by validate-modules to get a module's required utils in base and a collection.
28
- self.ps_modules = dict()
29
- self.exec_scripts = dict()
56
+ self.scripts: dict[str, _ScriptInfo] = {}
30
57
 
31
- # by defining an explicit dict of cs utils and where they are used, we
32
- # can potentially save time by not adding the type multiple times if it
33
- # isn't needed
34
- self.cs_utils_wrapper = dict()
35
- self.cs_utils_module = dict()
58
+ self._util_deps: dict[str, set[str]] = {}
36
59
 
37
- self.ps_version = None
38
- self.os_version = None
60
+ self.ps_version: str | None = None
61
+ self.os_version: str | None = None
39
62
  self.become = False
40
63
 
41
64
  self._re_cs_module = [
@@ -70,36 +93,49 @@ class PSModuleDepFinder(object):
70
93
  r'(\.[\w\.]+))(?P<optional>\s+-Optional){0,1}')),
71
94
  ]
72
95
 
73
- self._re_wrapper = re.compile(to_bytes(r'(?i)^#\s*ansiblerequires\s+-wrapper\s+(\w*)'))
74
96
  self._re_ps_version = re.compile(to_bytes(r'(?i)^#requires\s+\-version\s+([0-9]+(\.[0-9]+){0,3})$'))
75
97
  self._re_os_version = re.compile(to_bytes(r'(?i)^#ansiblerequires\s+\-osversion\s+([0-9]+(\.[0-9]+){0,3})$'))
76
98
  self._re_become = re.compile(to_bytes(r'(?i)^#ansiblerequires\s+\-become$'))
77
99
 
78
- def scan_module(self, module_data, fqn=None, wrapper=False, powershell=True):
100
+ def scan_exec_script(self, name: str) -> None:
101
+ # scans lib/ansible/executor/powershell for scripts used in the module
102
+ # exec side. It also scans these scripts for any dependencies
103
+ if name in self.scripts:
104
+ return
105
+
106
+ exec_code = _get_powershell_script(name)
107
+ self.scripts[name] = _ScriptInfo(
108
+ content=exec_code,
109
+ path=name,
110
+ )
111
+ self.scan_module(exec_code, powershell=True)
112
+
113
+ def scan_module(
114
+ self,
115
+ module_data: bytes,
116
+ fqn: str | None = None,
117
+ powershell: bool = True,
118
+ ) -> set[str]:
79
119
  lines = module_data.split(b'\n')
80
- module_utils = set()
81
- if wrapper:
82
- cs_utils = self.cs_utils_wrapper
83
- else:
84
- cs_utils = self.cs_utils_module
120
+ module_utils: set[tuple[str, str, bool]] = set()
85
121
 
86
122
  if powershell:
87
123
  checks = [
88
124
  # PS module contains '#Requires -Module Ansible.ModuleUtils.*'
89
125
  # PS module contains '#AnsibleRequires -Powershell Ansible.*' (or collections module_utils ref)
90
- (self._re_ps_module, self.ps_modules, ".psm1"),
126
+ (self._re_ps_module, ".psm1"),
91
127
  # PS module contains '#AnsibleRequires -CSharpUtil Ansible.*' (or collections module_utils ref)
92
- (self._re_cs_in_ps_module, cs_utils, ".cs"),
128
+ (self._re_cs_in_ps_module, ".cs"),
93
129
  ]
94
130
  else:
95
131
  checks = [
96
132
  # CS module contains 'using Ansible.*;' or 'using ansible_collections.ns.coll.plugins.module_utils.*;'
97
- (self._re_cs_module, cs_utils, ".cs"),
133
+ (self._re_cs_module, ".cs"),
98
134
  ]
99
135
 
100
136
  for line in lines:
101
- for check in checks:
102
- for pattern in check[0]:
137
+ for patterns, util_extension in checks:
138
+ for pattern in patterns:
103
139
  match = pattern.match(line)
104
140
  if match:
105
141
  # tolerate windows line endings by stripping any remaining
@@ -107,82 +143,66 @@ class PSModuleDepFinder(object):
107
143
  module_util_name = to_text(match.group(1).rstrip())
108
144
  match_dict = match.groupdict()
109
145
  optional = match_dict.get('optional', None) is not None
110
-
111
- if module_util_name not in check[1].keys():
112
- module_utils.add((module_util_name, check[2], fqn, optional))
113
-
146
+ module_utils.add((module_util_name, util_extension, optional))
114
147
  break
115
148
 
116
- if powershell:
117
- ps_version_match = self._re_ps_version.match(line)
118
- if ps_version_match:
119
- self._parse_version_match(ps_version_match, "ps_version")
120
-
121
- os_version_match = self._re_os_version.match(line)
122
- if os_version_match:
123
- self._parse_version_match(os_version_match, "os_version")
124
-
125
- # once become is set, no need to keep on checking recursively
126
- if not self.become:
127
- become_match = self._re_become.match(line)
128
- if become_match:
129
- self.become = True
130
-
131
- if wrapper:
132
- wrapper_match = self._re_wrapper.match(line)
133
- if wrapper_match:
134
- self.scan_exec_script(wrapper_match.group(1).rstrip())
135
-
136
- # recursively drill into each Requires to see if there are any more
137
- # requirements
138
- for m in set(module_utils):
139
- self._add_module(*m, wrapper=wrapper)
140
-
141
- def scan_exec_script(self, name):
142
- # scans lib/ansible/executor/powershell for scripts used in the module
143
- # exec side. It also scans these scripts for any dependencies
144
- name = to_text(name)
145
- if name in self.exec_scripts.keys():
146
- return
147
-
148
- data = pkgutil.get_data("ansible.executor.powershell", to_native(name + ".ps1"))
149
- if data is None:
150
- raise AnsibleError("Could not find executor powershell script "
151
- "for '%s'" % name)
152
-
153
- b_data = to_bytes(data)
154
-
155
- # remove comments to reduce the payload size in the exec wrappers
156
- if C.DEFAULT_DEBUG:
157
- exec_script = b_data
158
- else:
159
- exec_script = _strip_comments(b_data)
160
- self.exec_scripts[name] = to_bytes(exec_script)
161
- self.scan_module(b_data, wrapper=True, powershell=True)
162
-
163
- def _add_module(self, name, ext, fqn, optional, wrapper=False):
164
- m = to_text(name)
165
-
166
- util_fqn = None
167
-
168
- if m.startswith("Ansible."):
169
- # Builtin util, use plugin loader to get the data
170
- mu_path = ps_module_utils_loader.find_plugin(m, ext)
171
-
172
- if not mu_path:
149
+ if not powershell:
150
+ continue
151
+
152
+ if ps_version_match := self._re_ps_version.match(line):
153
+ self._parse_version_match(ps_version_match, "ps_version")
154
+
155
+ if os_version_match := self._re_os_version.match(line):
156
+ self._parse_version_match(os_version_match, "os_version")
157
+
158
+ # once become is set, no need to keep on checking recursively
159
+ if not self.become and self._re_become.match(line):
160
+ self.become = True
161
+
162
+ dependencies: set[str] = set()
163
+ for name, ext, optional in set(module_utils):
164
+ util_name = self._scan_module_util(name, ext, fqn, optional)
165
+ if util_name:
166
+ dependencies.add(util_name)
167
+ util_deps = self._util_deps[util_name]
168
+ dependencies.update(util_deps)
169
+
170
+ return dependencies
171
+
172
+ def _scan_module_util(
173
+ self,
174
+ name: str,
175
+ ext: str,
176
+ module_fqn: str | None,
177
+ optional: bool,
178
+ ) -> str | None:
179
+ util_name: str
180
+ util_path: str
181
+ util_data: bytes
182
+ util_fqn: str | None = None
183
+
184
+ if name.startswith("Ansible."):
185
+ # Builtin util, or the old role module_utils reference.
186
+ util_name = f"{name}{ext}"
187
+
188
+ if util_name in self._util_deps:
189
+ return util_name
190
+
191
+ util_path = ps_module_utils_loader.find_plugin(name, ext)
192
+ if not util_path or not os.path.exists(util_path):
173
193
  if optional:
174
- return
194
+ return None
195
+
196
+ raise AnsibleError(f"Could not find imported module util '{name}'")
175
197
 
176
- raise AnsibleError('Could not find imported module support code '
177
- 'for \'%s\'' % m)
198
+ with open(util_path, 'rb') as mu_file:
199
+ util_data = mu_file.read()
178
200
 
179
- module_util_data = to_bytes(_slurp(mu_path))
180
201
  else:
181
202
  # Collection util, load the package data based on the util import.
182
-
183
- submodules = m.split(".")
184
- if m.startswith('.'):
185
- fqn_submodules = fqn.split('.')
203
+ submodules = name.split(".")
204
+ if name.startswith('.'):
205
+ fqn_submodules = (module_fqn or "").split('.')
186
206
  for submodule in submodules:
187
207
  if submodule:
188
208
  break
@@ -190,56 +210,70 @@ class PSModuleDepFinder(object):
190
210
 
191
211
  submodules = fqn_submodules + [s for s in submodules if s]
192
212
 
193
- n_package_name = to_native('.'.join(submodules[:-1]), errors='surrogate_or_strict')
194
- n_resource_name = to_native(submodules[-1] + ext, errors='surrogate_or_strict')
213
+ util_package = '.'.join(submodules[:-1])
214
+ util_resource_name = f"{submodules[-1]}{ext}"
215
+ util_fqn = f"{util_package}.{submodules[-1]}"
216
+ util_name = f"{util_package}.{util_resource_name}"
217
+
218
+ if util_name in self._util_deps:
219
+ return util_name
195
220
 
196
221
  try:
197
- module_util = import_module(n_package_name)
198
- pkg_data = pkgutil.get_data(n_package_name, n_resource_name)
199
- if pkg_data is None:
222
+ module_util = import_module(util_package)
223
+ util_code = pkgutil.get_data(util_package, util_resource_name)
224
+ if util_code is None:
200
225
  raise ImportError("No package data found")
201
-
202
- module_util_data = to_bytes(pkg_data, errors='surrogate_or_strict')
203
- util_fqn = to_text("%s.%s " % (n_package_name, submodules[-1]), errors='surrogate_or_strict')
226
+ util_data = util_code
204
227
 
205
228
  # Get the path of the util which is required for coverage collection.
206
229
  resource_paths = list(module_util.__path__)
207
230
  if len(resource_paths) != 1:
208
231
  # This should never happen with a collection but we are just being defensive about it.
209
- raise AnsibleError("Internal error: Referenced module_util package '%s' contains 0 or multiple "
210
- "import locations when we only expect 1." % n_package_name)
211
- mu_path = os.path.join(resource_paths[0], n_resource_name)
232
+ raise AnsibleError(f"Internal error: Referenced module_util package '{util_package}' contains 0 "
233
+ "or multiple import locations when we only expect 1.")
234
+
235
+ util_path = os.path.join(resource_paths[0], util_resource_name)
212
236
  except (ImportError, OSError) as err:
213
237
  if getattr(err, "errno", errno.ENOENT) == errno.ENOENT:
214
238
  if optional:
215
- return
239
+ return None
216
240
 
217
- raise AnsibleError('Could not find collection imported module support code for \'%s\''
218
- % to_native(m))
241
+ raise AnsibleError(f"Could not find collection imported module support code for '{name}'")
219
242
 
220
243
  else:
221
244
  raise
222
245
 
223
- util_info = {
224
- 'data': module_util_data,
225
- 'path': to_text(mu_path),
226
- }
227
- if ext == ".psm1":
228
- self.ps_modules[m] = util_info
229
- else:
230
- if wrapper:
231
- self.cs_utils_wrapper[m] = util_info
232
- else:
233
- self.cs_utils_module[m] = util_info
234
- self.scan_module(module_util_data, fqn=util_fqn, wrapper=wrapper, powershell=(ext == ".psm1"))
246
+ # This is important to be set before scan_module is called to avoid
247
+ # recursive dependencies.
248
+ self.scripts[util_name] = _ScriptInfo(
249
+ content=util_data,
250
+ path=util_path,
251
+ )
252
+
253
+ # It is important this is set before calling scan_module to ensure
254
+ # recursive dependencies don't result in an infinite loop.
255
+ dependencies = self._util_deps[util_name] = set()
256
+
257
+ util_deps = self.scan_module(util_data, fqn=util_fqn, powershell=(ext == ".psm1"))
258
+ dependencies.update(util_deps)
259
+ for dep in dependencies:
260
+ if dep_list := self._util_deps.get(dep):
261
+ dependencies.update(dep_list)
262
+
263
+ if ext == ".cs":
264
+ # Any C# code requires the AddType.psm1 module to load.
265
+ dependencies.add("Ansible.ModuleUtils.AddType.psm1")
266
+ self._scan_module_util("Ansible.ModuleUtils.AddType", ".psm1", None, False)
267
+
268
+ return util_name
235
269
 
236
- def _parse_version_match(self, match, attribute):
270
+ def _parse_version_match(self, match: re.Match, attribute: str) -> None:
237
271
  new_version = to_text(match.group(1)).rstrip()
238
272
 
239
273
  # PowerShell cannot cast a string of "1" to Version, it must have at
240
274
  # least the major.minor for it to be valid so we append 0
241
275
  if match.group(2) is None:
242
- new_version = "%s.0" % new_version
276
+ new_version = f"{new_version}.0"
243
277
 
244
278
  existing_version = getattr(self, attribute, None)
245
279
  if existing_version is None:
@@ -250,152 +284,270 @@ class PSModuleDepFinder(object):
250
284
  setattr(self, attribute, new_version)
251
285
 
252
286
 
253
- def _slurp(path):
254
- if not os.path.exists(path):
255
- raise AnsibleError("imported module support code does not exist at %s"
256
- % os.path.abspath(path))
257
- fd = open(path, 'rb')
258
- data = fd.read()
259
- fd.close()
260
- return data
261
-
262
-
263
- def _strip_comments(source):
264
- # Strip comments and blank lines from the wrapper
265
- buf = []
266
- start_block = False
267
- for line in source.splitlines():
268
- l = line.strip()
269
-
270
- if start_block and l.endswith(b'#>'):
271
- start_block = False
272
- continue
273
- elif start_block:
274
- continue
275
- elif l.startswith(b'<#'):
276
- start_block = True
277
- continue
278
- elif not l or l.startswith(b'#'):
279
- continue
280
-
281
- buf.append(line)
282
- return b'\n'.join(buf)
283
-
284
-
285
- def _create_powershell_wrapper(b_module_data, module_path, module_args,
286
- environment, async_timeout, become,
287
- become_method, become_user, become_password,
288
- become_flags, substyle, task_vars, module_fqn):
289
- # creates the manifest/wrapper used in PowerShell/C# modules to enable
290
- # things like become and async - this is also called in action/script.py
291
-
292
- # FUTURE: add process_wrapper.ps1 to run module_wrapper in a new process
293
- # if running under a persistent connection and substyle is C# so we
294
- # don't have type conflicts
287
+ def _bootstrap_powershell_script(
288
+ name: str,
289
+ parameters: dict[str, t.Any] | None = None,
290
+ *,
291
+ has_input: bool = False,
292
+ ) -> tuple[str, bytes]:
293
+ """Build bootstrap wrapper for specified script.
294
+
295
+ Builds the bootstrap wrapper and input needed to run the specified executor
296
+ PowerShell script specified.
297
+
298
+ :param name: The name of the PowerShell script to run.
299
+ :param parameters: The parameters to pass to the script.
300
+ :param has_input: The script will be provided with input data.
301
+ :return: The bootstrap wrapper and input to provide to it.
302
+ """
303
+ exec_manifest = _ExecManifest()
304
+
305
+ script = _get_powershell_script(name)
306
+ exec_manifest.scripts[name] = _ScriptInfo(
307
+ content=script,
308
+ path=name,
309
+ )
310
+
311
+ exec_manifest.actions.append(
312
+ _ManifestAction(
313
+ name=name,
314
+ params=parameters or {},
315
+ )
316
+ )
317
+
318
+ bootstrap_wrapper = _get_powershell_script("bootstrap_wrapper.ps1")
319
+ bootstrap_input = _get_bootstrap_input(exec_manifest)
320
+ if has_input:
321
+ bootstrap_input += b"\n\0\0\0\0\n"
322
+
323
+ return bootstrap_wrapper.decode(), bootstrap_input
324
+
325
+
326
+ def _get_powershell_script(
327
+ name: str,
328
+ ) -> bytes:
329
+ """Get the requested PowerShell script.
330
+
331
+ Gets the script stored in the ansible.executore.powershell package.
332
+
333
+ :param name: The name of the PowerShell script to retrieve.
334
+ :return: The contents of the requested PowerShell script as a byte string.
335
+ """
336
+ package_name = 'ansible.executor.powershell'
337
+
338
+ code = pkgutil.get_data(package_name, name)
339
+ if code is None:
340
+ raise AnsibleFileNotFound(f"Could not find powershell script '{package_name}.{name}'")
341
+
342
+ return code
343
+
344
+
345
+ def _create_powershell_wrapper(
346
+ *,
347
+ name: str,
348
+ module_data: bytes,
349
+ module_path: str,
350
+ module_args: dict[t.Any, t.Any],
351
+ environment: dict[str, str],
352
+ async_timeout: int,
353
+ become_plugin: BecomeBase | None,
354
+ substyle: t.Literal["powershell", "script"],
355
+ task_vars: dict[str, t.Any],
356
+ profile: str,
357
+ ) -> bytes:
358
+ """Creates module or script wrapper for PowerShell.
359
+
360
+ Creates the input data to provide to bootstrap_wrapper.ps1 when running a
361
+ PowerShell module or script.
362
+
363
+ :param name: The fully qualified name of the module or script filename (without extension).
364
+ :param module_data: The data of the module or script.
365
+ :param module_path: The path of the module or script.
366
+ :param module_args: The arguments to pass to the module or script.
367
+ :param environment: The environment variables to set when running the module or script.
368
+ :param async_timeout: The timeout to use for async execution or 0 for no async.
369
+ :param become_plugin: The become plugin to use for privilege escalation or None for no become.
370
+ :param substyle: The substyle of the module or script to run [powershell or script].
371
+ :param task_vars: The task variables used on the task.
372
+
373
+ :return: The input data for bootstrap_wrapper.ps1 as a byte string.
374
+ """
375
+
376
+ actions: list[_ManifestAction] = []
295
377
  finder = PSModuleDepFinder()
296
- if substyle != 'script':
297
- # don't scan the module for util dependencies and other Ansible related
298
- # flags if the substyle is 'script' which is set by action/script
299
- finder.scan_module(b_module_data, fqn=module_fqn, powershell=(substyle == "powershell"))
300
-
301
- module_wrapper = "module_%s_wrapper" % substyle
302
- exec_manifest = dict(
303
- module_entry=to_text(base64.b64encode(b_module_data)),
304
- powershell_modules=dict(),
305
- csharp_utils=dict(),
306
- csharp_utils_module=list(), # csharp_utils only required by a module
307
- module_args=module_args,
308
- actions=[module_wrapper],
309
- environment=environment,
310
- encoded_output=False,
378
+ finder.scan_exec_script('module_wrapper.ps1')
379
+
380
+ ext = os.path.splitext(module_path)[1]
381
+ name_with_ext = f"{name}{ext}"
382
+ finder.scripts[name_with_ext] = _ScriptInfo(
383
+ content=module_data,
384
+ path=module_path,
311
385
  )
312
- finder.scan_exec_script(module_wrapper)
386
+
387
+ module_params: dict[str, t.Any] = {
388
+ 'Script': name_with_ext,
389
+ 'Environment': environment,
390
+ }
391
+ if substyle != 'script':
392
+ module_deps = finder.scan_module(
393
+ module_data,
394
+ fqn=name,
395
+ powershell=True,
396
+ )
397
+ cs_deps = []
398
+ ps_deps = []
399
+ for dep in module_deps:
400
+ if dep.endswith('.cs'):
401
+ cs_deps.append(dep)
402
+ else:
403
+ ps_deps.append(dep)
404
+
405
+ module_params |= {
406
+ 'Variables': [
407
+ {
408
+ 'Name': 'complex_args',
409
+ 'Value': _prepare_module_args(module_args, profile),
410
+ 'Scope': 'Global',
411
+ },
412
+ ],
413
+ 'CSharpModules': cs_deps,
414
+ 'PowerShellModules': ps_deps,
415
+ 'ForModule': True,
416
+ }
417
+
418
+ if become_plugin or finder.become:
419
+ become_script = 'become_wrapper.ps1'
420
+ become_params: dict[str, t.Any] = {
421
+ 'BecomeUser': 'SYSTEM',
422
+ }
423
+ become_secure_params: dict[str, t.Any] = {}
424
+
425
+ if become_plugin:
426
+ if not isinstance(become_plugin, RunasBecomeModule):
427
+ msg = f"Become plugin {become_plugin.name} is not supported by the Windows exec wrapper. Make sure to set the become method to runas."
428
+ raise AnsibleError(msg)
429
+
430
+ become_script, become_params, become_secure_params = become_plugin._build_powershell_wrapper_action()
431
+
432
+ finder.scan_exec_script('exec_wrapper.ps1')
433
+ finder.scan_exec_script(become_script)
434
+ actions.append(
435
+ _ManifestAction(
436
+ name=become_script,
437
+ params=become_params,
438
+ secure_params=become_secure_params,
439
+ )
440
+ )
313
441
 
314
442
  if async_timeout > 0:
315
- finder.scan_exec_script('exec_wrapper')
316
- finder.scan_exec_script('async_watchdog')
317
- finder.scan_exec_script('async_wrapper')
318
-
319
- exec_manifest["actions"].insert(0, 'async_watchdog')
320
- exec_manifest["actions"].insert(0, 'async_wrapper')
321
- exec_manifest["async_jid"] = f'j{secrets.randbelow(999999999999)}'
322
- exec_manifest["async_timeout_sec"] = async_timeout
323
- exec_manifest["async_startup_timeout"] = C.config.get_config_value("WIN_ASYNC_STARTUP_TIMEOUT", variables=task_vars)
324
-
325
- if become and resource_from_fqcr(become_method) == 'runas': # runas and namespace.collection.runas
326
- finder.scan_exec_script('exec_wrapper')
327
- finder.scan_exec_script('become_wrapper')
328
-
329
- exec_manifest["actions"].insert(0, 'become_wrapper')
330
- exec_manifest["become_user"] = become_user
331
- exec_manifest["become_password"] = become_password
332
- exec_manifest['become_flags'] = become_flags
333
-
334
- exec_manifest['min_ps_version'] = finder.ps_version
335
- exec_manifest['min_os_version'] = finder.os_version
336
- if finder.become and 'become_wrapper' not in exec_manifest['actions']:
337
- finder.scan_exec_script('exec_wrapper')
338
- finder.scan_exec_script('become_wrapper')
339
-
340
- exec_manifest['actions'].insert(0, 'become_wrapper')
341
- exec_manifest['become_user'] = 'SYSTEM'
342
- exec_manifest['become_password'] = None
343
- exec_manifest['become_flags'] = None
344
-
345
- coverage_manifest = dict(
346
- module_path=module_path,
347
- module_util_paths=dict(),
348
- output=None,
349
- )
443
+ finder.scan_exec_script('bootstrap_wrapper.ps1')
444
+ finder.scan_exec_script('exec_wrapper.ps1')
445
+
446
+ async_dir = environment.get('ANSIBLE_ASYNC_DIR', None)
447
+ if not async_dir:
448
+ raise AnsibleError("The environment variable 'ANSIBLE_ASYNC_DIR' is not set.")
449
+
450
+ finder.scan_exec_script('async_wrapper.ps1')
451
+ actions.append(
452
+ _ManifestAction(
453
+ name='async_wrapper.ps1',
454
+ params={
455
+ 'AsyncDir': async_dir,
456
+ 'AsyncJid': f'j{secrets.randbelow(999999999999)}',
457
+ 'StartupTimeout': C.config.get_config_value("WIN_ASYNC_STARTUP_TIMEOUT", variables=task_vars),
458
+ },
459
+ )
460
+ )
461
+
462
+ finder.scan_exec_script('async_watchdog.ps1')
463
+ actions.append(
464
+ _ManifestAction(
465
+ name='async_watchdog.ps1',
466
+ params={
467
+ 'Timeout': async_timeout,
468
+ },
469
+ )
470
+ )
471
+
350
472
  coverage_output = C.config.get_config_value('COVERAGE_REMOTE_OUTPUT', variables=task_vars)
351
473
  if coverage_output and substyle == 'powershell':
352
- finder.scan_exec_script('coverage_wrapper')
353
- coverage_manifest['output'] = coverage_output
354
-
355
- coverage_enabled = C.config.get_config_value('COVERAGE_REMOTE_PATHS', variables=task_vars)
356
- coverage_manifest['path_filter'] = coverage_enabled
357
-
358
- # make sure Ansible.ModuleUtils.AddType is added if any C# utils are used
359
- if len(finder.cs_utils_wrapper) > 0 or len(finder.cs_utils_module) > 0:
360
- finder._add_module(b"Ansible.ModuleUtils.AddType", ".psm1", None, False,
361
- wrapper=False)
362
-
363
- # exec_wrapper is only required to be part of the payload if using
364
- # become or async, to save on payload space we check if exec_wrapper has
365
- # already been added, and remove it manually if it hasn't later
366
- exec_required = "exec_wrapper" in finder.exec_scripts.keys()
367
- finder.scan_exec_script("exec_wrapper")
368
- # must contain an empty newline so it runs the begin/process/end block
369
- finder.exec_scripts["exec_wrapper"] += b"\n\n"
370
-
371
- exec_wrapper = finder.exec_scripts["exec_wrapper"]
372
- if not exec_required:
373
- finder.exec_scripts.pop("exec_wrapper")
374
-
375
- for name, data in finder.exec_scripts.items():
376
- b64_data = to_text(base64.b64encode(data))
377
- exec_manifest[name] = b64_data
378
-
379
- for name, data in finder.ps_modules.items():
380
- b64_data = to_text(base64.b64encode(data['data']))
381
- exec_manifest['powershell_modules'][name] = b64_data
382
- coverage_manifest['module_util_paths'][name] = data['path']
383
-
384
- cs_utils = {}
385
- for cs_util in [finder.cs_utils_wrapper, finder.cs_utils_module]:
386
- for name, data in cs_util.items():
387
- cs_utils[name] = data['data']
388
-
389
- for name, data in cs_utils.items():
390
- b64_data = to_text(base64.b64encode(data))
391
- exec_manifest['csharp_utils'][name] = b64_data
392
- exec_manifest['csharp_utils_module'] = list(finder.cs_utils_module.keys())
393
-
394
- # To save on the data we are sending across we only add the coverage info if coverage is being run
395
- if 'coverage_wrapper' in exec_manifest:
396
- exec_manifest['coverage'] = coverage_manifest
397
-
398
- b_json = to_bytes(json.dumps(exec_manifest))
399
- # delimit the payload JSON from the wrapper to keep sensitive contents out of scriptblocks (which can be logged)
400
- b_data = exec_wrapper + b'\0\0\0\0' + b_json
401
- return b_data
474
+ path_filter = C.config.get_config_value('COVERAGE_REMOTE_PATHS', variables=task_vars)
475
+
476
+ finder.scan_exec_script('coverage_wrapper.ps1')
477
+ actions.append(
478
+ _ManifestAction(
479
+ name='coverage_wrapper.ps1',
480
+ params={
481
+ 'ModuleName': name_with_ext,
482
+ 'OutputPath': coverage_output,
483
+ 'PathFilter': path_filter,
484
+ },
485
+ )
486
+ )
487
+
488
+ actions.append(
489
+ _ManifestAction(
490
+ name='module_wrapper.ps1',
491
+ params=module_params,
492
+ ),
493
+ )
494
+
495
+ temp_path: str | None = None
496
+ for temp_key in ['_ansible_tmpdir', '_ansible_remote_tmp']:
497
+ if temp_value := module_args.get(temp_key, None):
498
+ temp_path = temp_value
499
+ break
500
+
501
+ exec_manifest = _ExecManifest(
502
+ scripts=finder.scripts,
503
+ actions=actions,
504
+ )
505
+
506
+ return _get_bootstrap_input(
507
+ exec_manifest,
508
+ min_os_version=finder.os_version,
509
+ min_ps_version=finder.ps_version,
510
+ temp_path=temp_path,
511
+ )
512
+
513
+
514
+ def _get_bootstrap_input(
515
+ manifest: _ExecManifest,
516
+ min_os_version: str | None = None,
517
+ min_ps_version: str | None = None,
518
+ temp_path: str | None = None,
519
+ ) -> bytes:
520
+ """Gets the input for bootstrap_wrapper.ps1
521
+
522
+ Gets the input needed to send to bootstrap_wrapper.ps1 to run code through
523
+ exec_wrapper.ps1.
524
+
525
+ :param manifest: The exec wrapper manifest of scripts and actions to run.
526
+ :param min_os_version: The minimum OS version required to run the scripts.
527
+ :param min_ps_version: The minimum PowerShell version required to run the scripts.
528
+ :param temp_path: The temporary path to use for the scripts if needed.
529
+ :return: The input for bootstrap_wrapper.ps1 as a byte string.
530
+ """
531
+ bootstrap_manifest = {
532
+ 'name': 'exec_wrapper',
533
+ 'script': _get_powershell_script("exec_wrapper.ps1").decode(),
534
+ 'params': {
535
+ 'MinOSVersion': min_os_version,
536
+ 'MinPSVersion': min_ps_version,
537
+ 'TempPath': temp_path,
538
+ },
539
+ }
540
+
541
+ bootstrap_input = json.dumps(bootstrap_manifest, ensure_ascii=True)
542
+ exec_input = json.dumps(dataclasses.asdict(manifest))
543
+ return f"{bootstrap_input}\n\0\0\0\0\n{exec_input}".encode()
544
+
545
+
546
+ def _prepare_module_args(module_args: dict[str, t.Any], profile: str) -> dict[str, t.Any]:
547
+ """
548
+ Serialize the module args with the specified profile and deserialize them with the Python built-in JSON decoder.
549
+ This is used to facilitate serializing module args with a different encoder (profile) than is used for the manifest.
550
+ """
551
+ encoder = get_module_encoder(profile, Direction.CONTROLLER_TO_MODULE)
552
+
553
+ return json.loads(json.dumps(module_args, cls=encoder))