ansible-core 2.17.5rc1__py3-none-any.whl → 2.18.0rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (330) hide show
  1. ansible/__main__.py +2 -17
  2. ansible/cli/__init__.py +3 -15
  3. ansible/cli/config.py +187 -24
  4. ansible/cli/console.py +1 -1
  5. ansible/cli/doc.py +38 -16
  6. ansible/cli/galaxy.py +3 -49
  7. ansible/cli/inventory.py +2 -2
  8. ansible/cli/pull.py +2 -2
  9. ansible/cli/scripts/ansible_connection_cli_stub.py +1 -10
  10. ansible/config/base.yml +127 -57
  11. ansible/config/manager.py +89 -11
  12. ansible/constants.py +32 -9
  13. ansible/errors/__init__.py +5 -0
  14. ansible/executor/interpreter_discovery.py +1 -1
  15. ansible/executor/play_iterator.py +34 -0
  16. ansible/executor/playbook_executor.py +1 -4
  17. ansible/executor/powershell/become_wrapper.ps1 +4 -5
  18. ansible/executor/powershell/bootstrap_wrapper.ps1 +2 -3
  19. ansible/executor/powershell/exec_wrapper.ps1 +1 -1
  20. ansible/executor/powershell/module_manifest.py +2 -2
  21. ansible/executor/task_executor.py +50 -39
  22. ansible/executor/task_queue_manager.py +1 -1
  23. ansible/executor/task_result.py +1 -1
  24. ansible/galaxy/api.py +3 -4
  25. ansible/galaxy/collection/__init__.py +21 -10
  26. ansible/galaxy/collection/concrete_artifact_manager.py +10 -5
  27. ansible/galaxy/collection/galaxy_api_proxy.py +10 -16
  28. ansible/galaxy/collection/gpg.py +17 -23
  29. ansible/galaxy/data/COPYING +7 -0
  30. ansible/galaxy/data/apb/Dockerfile.j2 +1 -0
  31. ansible/galaxy/data/apb/Makefile.j2 +1 -0
  32. ansible/galaxy/data/apb/README.md +7 -3
  33. ansible/galaxy/data/apb/apb.yml.j2 +1 -0
  34. ansible/galaxy/data/apb/defaults/main.yml.j2 +1 -0
  35. ansible/galaxy/data/apb/handlers/main.yml.j2 +1 -0
  36. ansible/galaxy/data/apb/meta/main.yml.j2 +1 -0
  37. ansible/galaxy/data/apb/playbooks/deprovision.yml.j2 +1 -0
  38. ansible/galaxy/data/apb/playbooks/provision.yml.j2 +1 -0
  39. ansible/galaxy/data/apb/tasks/main.yml.j2 +1 -0
  40. ansible/galaxy/data/apb/tests/ansible.cfg +1 -0
  41. ansible/galaxy/data/apb/tests/inventory +1 -0
  42. ansible/galaxy/data/apb/tests/test.yml.j2 +1 -0
  43. ansible/galaxy/data/apb/vars/main.yml.j2 +1 -0
  44. ansible/galaxy/data/collections_galaxy_meta.yml +1 -0
  45. ansible/galaxy/data/container/defaults/main.yml.j2 +1 -0
  46. ansible/galaxy/data/container/handlers/main.yml.j2 +1 -0
  47. ansible/galaxy/data/container/meta/container.yml.j2 +1 -0
  48. ansible/galaxy/data/container/meta/main.yml.j2 +1 -0
  49. ansible/galaxy/data/container/tasks/main.yml.j2 +1 -0
  50. ansible/galaxy/data/container/tests/ansible.cfg +1 -0
  51. ansible/galaxy/data/container/tests/inventory +1 -0
  52. ansible/galaxy/data/container/tests/test.yml.j2 +1 -0
  53. ansible/galaxy/data/container/vars/main.yml.j2 +1 -0
  54. ansible/galaxy/data/default/collection/README.md.j2 +1 -0
  55. ansible/galaxy/data/default/collection/galaxy.yml.j2 +1 -0
  56. ansible/galaxy/data/default/collection/meta/runtime.yml +1 -0
  57. ansible/galaxy/data/default/collection/plugins/README.md.j2 +1 -0
  58. ansible/galaxy/data/default/role/defaults/main.yml.j2 +1 -0
  59. ansible/galaxy/data/default/role/handlers/main.yml.j2 +1 -0
  60. ansible/galaxy/data/default/role/meta/main.yml.j2 +1 -0
  61. ansible/galaxy/data/default/role/tasks/main.yml.j2 +1 -0
  62. ansible/galaxy/data/default/role/tests/inventory +1 -0
  63. ansible/galaxy/data/default/role/tests/test.yml.j2 +1 -0
  64. ansible/galaxy/data/default/role/vars/main.yml.j2 +1 -0
  65. ansible/galaxy/data/network/cliconf_plugins/example.py.j2 +1 -0
  66. ansible/galaxy/data/network/defaults/main.yml.j2 +1 -0
  67. ansible/galaxy/data/network/library/example_command.py.j2 +1 -0
  68. ansible/galaxy/data/network/library/example_config.py.j2 +1 -0
  69. ansible/galaxy/data/network/library/example_facts.py.j2 +1 -0
  70. ansible/galaxy/data/network/meta/main.yml.j2 +1 -0
  71. ansible/galaxy/data/network/module_utils/example.py.j2 +1 -0
  72. ansible/galaxy/data/network/netconf_plugins/example.py.j2 +1 -0
  73. ansible/galaxy/data/network/tasks/main.yml.j2 +1 -0
  74. ansible/galaxy/data/network/terminal_plugins/example.py.j2 +1 -0
  75. ansible/galaxy/data/network/tests/inventory +1 -0
  76. ansible/galaxy/data/network/tests/test.yml.j2 +1 -0
  77. ansible/galaxy/data/network/vars/main.yml.j2 +1 -0
  78. ansible/galaxy/dependency_resolution/providers.py +3 -3
  79. ansible/galaxy/role.py +1 -1
  80. ansible/galaxy/token.py +20 -8
  81. ansible/keyword_desc.yml +1 -1
  82. ansible/module_utils/_internal/__init__.py +0 -0
  83. ansible/module_utils/_internal/_concurrent/__init__.py +0 -0
  84. ansible/module_utils/_internal/_concurrent/_daemon_threading.py +28 -0
  85. ansible/module_utils/_internal/_concurrent/_futures.py +21 -0
  86. ansible/module_utils/ansible_release.py +2 -2
  87. ansible/module_utils/api.py +2 -2
  88. ansible/module_utils/basic.py +8 -8
  89. ansible/module_utils/common/collections.py +1 -1
  90. ansible/module_utils/common/file.py +0 -6
  91. ansible/module_utils/common/process.py +22 -9
  92. ansible/module_utils/common/text/converters.py +5 -8
  93. ansible/module_utils/common/text/formatters.py +20 -4
  94. ansible/module_utils/common/validation.py +33 -25
  95. ansible/module_utils/compat/paramiko.py +6 -1
  96. ansible/module_utils/compat/selinux.py +2 -2
  97. ansible/module_utils/connection.py +8 -24
  98. ansible/module_utils/csharp/Ansible.Become.cs +14 -25
  99. ansible/module_utils/csharp/Ansible.Process.cs +1 -1
  100. ansible/module_utils/distro/__init__.py +1 -1
  101. ansible/module_utils/distro/_distro.py +8 -4
  102. ansible/module_utils/facts/collector.py +2 -0
  103. ansible/module_utils/facts/default_collectors.py +3 -1
  104. ansible/module_utils/facts/hardware/aix.py +54 -52
  105. ansible/module_utils/facts/hardware/darwin.py +37 -34
  106. ansible/module_utils/facts/hardware/freebsd.py +55 -15
  107. ansible/module_utils/facts/hardware/hpux.py +3 -0
  108. ansible/module_utils/facts/hardware/linux.py +101 -57
  109. ansible/module_utils/facts/hardware/netbsd.py +3 -0
  110. ansible/module_utils/facts/hardware/openbsd.py +4 -1
  111. ansible/module_utils/facts/hardware/sunos.py +7 -1
  112. ansible/module_utils/facts/network/aix.py +16 -17
  113. ansible/module_utils/facts/network/fc_wwn.py +4 -1
  114. ansible/module_utils/facts/network/hpux.py +21 -4
  115. ansible/module_utils/facts/network/iscsi.py +7 -8
  116. ansible/module_utils/facts/network/linux.py +0 -2
  117. ansible/module_utils/facts/other/facter.py +9 -4
  118. ansible/module_utils/facts/other/ohai.py +5 -5
  119. ansible/module_utils/facts/packages.py +49 -7
  120. ansible/module_utils/facts/sysctl.py +33 -31
  121. ansible/module_utils/facts/system/distribution.py +2 -2
  122. ansible/module_utils/facts/system/local.py +12 -22
  123. ansible/module_utils/facts/system/service_mgr.py +3 -1
  124. ansible/module_utils/facts/system/systemd.py +47 -0
  125. ansible/module_utils/facts/timeout.py +1 -1
  126. ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 +1 -1
  127. ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 +1 -1
  128. ansible/module_utils/splitter.py +1 -1
  129. ansible/modules/add_host.py +1 -1
  130. ansible/modules/apt.py +43 -32
  131. ansible/modules/apt_key.py +6 -6
  132. ansible/modules/apt_repository.py +23 -14
  133. ansible/modules/assemble.py +7 -2
  134. ansible/modules/assert.py +4 -4
  135. ansible/modules/blockinfile.py +3 -6
  136. ansible/modules/command.py +1 -1
  137. ansible/modules/copy.py +4 -4
  138. ansible/modules/cron.py +13 -10
  139. ansible/modules/deb822_repository.py +16 -17
  140. ansible/modules/debconf.py +25 -22
  141. ansible/modules/debug.py +1 -1
  142. ansible/modules/dnf.py +79 -164
  143. ansible/modules/dnf5.py +54 -29
  144. ansible/modules/dpkg_selections.py +2 -2
  145. ansible/modules/expect.py +2 -2
  146. ansible/modules/fetch.py +2 -2
  147. ansible/modules/file.py +5 -3
  148. ansible/modules/find.py +40 -12
  149. ansible/modules/gather_facts.py +4 -2
  150. ansible/modules/get_url.py +29 -24
  151. ansible/modules/git.py +35 -35
  152. ansible/modules/group.py +71 -1
  153. ansible/modules/hostname.py +2 -4
  154. ansible/modules/include_vars.py +5 -5
  155. ansible/modules/iptables.py +13 -16
  156. ansible/modules/known_hosts.py +16 -13
  157. ansible/modules/lineinfile.py +1 -4
  158. ansible/modules/meta.py +6 -1
  159. ansible/modules/mount_facts.py +651 -0
  160. ansible/modules/package_facts.py +63 -80
  161. ansible/modules/pause.py +4 -3
  162. ansible/modules/pip.py +14 -14
  163. ansible/modules/replace.py +1 -4
  164. ansible/modules/rpm_key.py +31 -11
  165. ansible/modules/service.py +8 -8
  166. ansible/modules/service_facts.py +20 -5
  167. ansible/modules/set_stats.py +1 -1
  168. ansible/modules/setup.py +3 -3
  169. ansible/modules/stat.py +3 -3
  170. ansible/modules/subversion.py +1 -1
  171. ansible/modules/systemd.py +16 -10
  172. ansible/modules/systemd_service.py +16 -10
  173. ansible/modules/sysvinit.py +4 -4
  174. ansible/modules/unarchive.py +35 -22
  175. ansible/modules/uri.py +24 -18
  176. ansible/modules/user.py +148 -13
  177. ansible/modules/validate_argument_spec.py +3 -3
  178. ansible/modules/wait_for_connection.py +2 -1
  179. ansible/modules/yum_repository.py +136 -179
  180. ansible/parsing/dataloader.py +2 -2
  181. ansible/parsing/mod_args.py +11 -10
  182. ansible/parsing/vault/__init__.py +8 -3
  183. ansible/parsing/yaml/constructor.py +10 -8
  184. ansible/parsing/yaml/objects.py +1 -1
  185. ansible/playbook/base.py +12 -23
  186. ansible/playbook/helpers.py +4 -0
  187. ansible/playbook/loop_control.py +8 -0
  188. ansible/playbook/play.py +4 -22
  189. ansible/playbook/play_context.py +0 -16
  190. ansible/playbook/playbook_include.py +2 -2
  191. ansible/playbook/role/__init__.py +2 -2
  192. ansible/plugins/__init__.py +2 -0
  193. ansible/plugins/action/__init__.py +7 -9
  194. ansible/plugins/action/dnf.py +7 -5
  195. ansible/plugins/action/package.py +5 -4
  196. ansible/plugins/action/reboot.py +2 -2
  197. ansible/plugins/become/__init__.py +1 -1
  198. ansible/plugins/callback/__init__.py +44 -3
  199. ansible/plugins/callback/default.py +1 -1
  200. ansible/plugins/cliconf/__init__.py +1 -1
  201. ansible/plugins/connection/paramiko_ssh.py +2 -80
  202. ansible/plugins/connection/psrp.py +33 -82
  203. ansible/plugins/connection/ssh.py +0 -8
  204. ansible/plugins/connection/winrm.py +46 -1
  205. ansible/plugins/doc_fragments/connection_pipelining.py +2 -2
  206. ansible/plugins/doc_fragments/constructed.py +10 -10
  207. ansible/plugins/doc_fragments/default_callback.py +8 -8
  208. ansible/plugins/doc_fragments/files.py +5 -5
  209. ansible/plugins/doc_fragments/inventory_cache.py +2 -2
  210. ansible/plugins/doc_fragments/result_format_callback.py +6 -6
  211. ansible/plugins/doc_fragments/return_common.py +1 -1
  212. ansible/plugins/doc_fragments/shell_common.py +2 -10
  213. ansible/plugins/doc_fragments/shell_windows.py +0 -9
  214. ansible/plugins/doc_fragments/url.py +2 -2
  215. ansible/plugins/doc_fragments/url_windows.py +4 -5
  216. ansible/plugins/doc_fragments/validate.py +1 -1
  217. ansible/plugins/filter/core.py +2 -0
  218. ansible/plugins/filter/human_to_bytes.yml +9 -0
  219. ansible/plugins/filter/password_hash.yml +1 -1
  220. ansible/plugins/filter/strftime.yml +1 -1
  221. ansible/plugins/filter/to_nice_json.yml +7 -3
  222. ansible/plugins/filter/to_uuid.yml +1 -1
  223. ansible/plugins/filter/unique.yml +28 -0
  224. ansible/plugins/inventory/script.py +1 -1
  225. ansible/plugins/list.py +1 -1
  226. ansible/plugins/loader.py +0 -11
  227. ansible/plugins/lookup/config.py +1 -1
  228. ansible/plugins/lookup/csvfile.py +21 -9
  229. ansible/plugins/lookup/env.py +8 -9
  230. ansible/plugins/lookup/ini.py +10 -1
  231. ansible/plugins/lookup/random_choice.py +2 -2
  232. ansible/plugins/lookup/url.py +7 -2
  233. ansible/plugins/shell/__init__.py +15 -20
  234. ansible/plugins/shell/powershell.py +9 -6
  235. ansible/plugins/strategy/__init__.py +18 -7
  236. ansible/plugins/strategy/linear.py +1 -13
  237. ansible/plugins/test/core.py +23 -1
  238. ansible/plugins/test/issubset.yml +1 -1
  239. ansible/plugins/test/subset.yml +1 -1
  240. ansible/plugins/test/timedout.yml +20 -0
  241. ansible/plugins/test/vault_encrypted.yml +6 -6
  242. ansible/plugins/test/vaulted_file.yml +19 -0
  243. ansible/release.py +2 -2
  244. ansible/template/__init__.py +3 -8
  245. ansible/utils/collection_loader/_collection_finder.py +23 -55
  246. ansible/utils/display.py +44 -31
  247. ansible/utils/galaxy.py +1 -1
  248. ansible/utils/jsonrpc.py +1 -1
  249. ansible/utils/listify.py +1 -5
  250. ansible/utils/path.py +3 -0
  251. ansible/utils/vars.py +18 -27
  252. ansible/vars/manager.py +7 -150
  253. ansible/vars/plugins.py +1 -1
  254. ansible_core-2.18.0rc1.dist-info/Apache-License.txt +202 -0
  255. {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/METADATA +36 -23
  256. ansible_core-2.18.0rc1.dist-info/MIT-license.txt +14 -0
  257. ansible_core-2.18.0rc1.dist-info/PSF-license.txt +48 -0
  258. {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/RECORD +321 -316
  259. {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/entry_points.txt +1 -1
  260. ansible_core-2.18.0rc1.dist-info/simplified_bsd.txt +8 -0
  261. ansible_test/_data/completion/docker.txt +7 -7
  262. ansible_test/_data/completion/remote.txt +5 -4
  263. ansible_test/_data/completion/windows.txt +4 -4
  264. ansible_test/_data/requirements/ansible-test.txt +1 -2
  265. ansible_test/_data/requirements/constraints.txt +1 -2
  266. ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
  267. ansible_test/_data/requirements/sanity.changelog.in +1 -1
  268. ansible_test/_data/requirements/sanity.changelog.txt +4 -4
  269. ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
  270. ansible_test/_data/requirements/sanity.import.txt +1 -1
  271. ansible_test/_data/requirements/sanity.integration-aliases.txt +1 -1
  272. ansible_test/_data/requirements/sanity.pep8.txt +1 -1
  273. ansible_test/_data/requirements/sanity.pylint.txt +6 -8
  274. ansible_test/_data/requirements/sanity.runtime-metadata.txt +2 -2
  275. ansible_test/_data/requirements/sanity.validate-modules.txt +3 -3
  276. ansible_test/_data/requirements/sanity.yamllint.in +1 -0
  277. ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
  278. ansible_test/_internal/ansible_util.py +8 -35
  279. ansible_test/_internal/ci/azp.py +1 -1
  280. ansible_test/_internal/classification/__init__.py +0 -2
  281. ansible_test/_internal/cli/parsers/key_value_parsers.py +3 -0
  282. ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -1
  283. ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
  284. ansible_test/_internal/commands/integration/cloud/nios.py +1 -1
  285. ansible_test/_internal/commands/sanity/__init__.py +96 -19
  286. ansible_test/_internal/commands/sanity/pylint.py +20 -24
  287. ansible_test/_internal/completion.py +2 -0
  288. ansible_test/_internal/constants.py +0 -1
  289. ansible_test/_internal/coverage_util.py +1 -2
  290. ansible_test/_internal/docker_util.py +10 -2
  291. ansible_test/_internal/encoding.py +4 -4
  292. ansible_test/_internal/host_configs.py +10 -0
  293. ansible_test/_internal/host_profiles.py +9 -13
  294. ansible_test/_internal/pypi_proxy.py +1 -1
  295. ansible_test/_internal/python_requirements.py +5 -14
  296. ansible_test/_internal/timeout.py +1 -1
  297. ansible_test/_internal/util.py +56 -8
  298. ansible_test/_internal/util_common.py +5 -1
  299. ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.json +3 -1
  300. ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +6 -3
  301. ansible_test/_util/controller/sanity/code-smell/empty-init.json +0 -2
  302. ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +5 -0
  303. ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +5 -0
  304. ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +5 -0
  305. ansible_test/_util/controller/sanity/pylint/config/collection.cfg +6 -0
  306. ansible_test/_util/controller/sanity/pylint/config/default.cfg +6 -0
  307. ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -19
  308. ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +3 -4
  309. ansible_test/_util/controller/sanity/shellcheck/exclude.txt +1 -0
  310. ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +67 -2
  311. ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +27 -5
  312. ansible_test/_util/target/cli/ansible_test_cli_stub.py +0 -0
  313. ansible_test/_util/target/common/constants.py +2 -2
  314. ansible_test/_util/target/injector/python.py +5 -0
  315. ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +6 -0
  316. ansible_test/_util/target/sanity/import/importer.py +1 -1
  317. ansible_test/_util/target/setup/bootstrap.sh +6 -17
  318. ansible_test/_util/target/setup/requirements.py +18 -24
  319. ansible_test/config/config.yml +1 -1
  320. ansible_core-2.17.5rc1.data/scripts/ansible-test +0 -44
  321. ansible_test/_data/requirements/sanity.mypy.in +0 -10
  322. ansible_test/_data/requirements/sanity.mypy.txt +0 -18
  323. ansible_test/_internal/commands/sanity/mypy.py +0 -274
  324. ansible_test/_util/controller/sanity/mypy/ansible-core.ini +0 -116
  325. ansible_test/_util/controller/sanity/mypy/ansible-test.ini +0 -27
  326. ansible_test/_util/controller/sanity/mypy/modules.ini +0 -92
  327. ansible_test/_util/controller/sanity/mypy/packaging.ini +0 -20
  328. {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/COPYING +0 -0
  329. {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/WHEEL +0 -0
  330. {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/top_level.txt +0 -0
@@ -20,6 +20,18 @@ SIZE_RANGES = {
20
20
  'B': 1,
21
21
  }
22
22
 
23
+ VALID_UNITS = {
24
+ 'B': (('byte', 'B'), ('bit', 'b')),
25
+ 'K': (('kilobyte', 'KB'), ('kilobit', 'Kb')),
26
+ 'M': (('megabyte', 'MB'), ('megabit', 'Mb')),
27
+ 'G': (('gigabyte', 'GB'), ('gigabit', 'Gb')),
28
+ 'T': (('terabyte', 'TB'), ('terabit', 'Tb')),
29
+ 'P': (('petabyte', 'PB'), ('petabit', 'Pb')),
30
+ 'E': (('exabyte', 'EB'), ('exabit', 'Eb')),
31
+ 'Z': (('zetabyte', 'ZB'), ('zetabit', 'Zb')),
32
+ 'Y': (('yottabyte', 'YB'), ('yottabit', 'Yb')),
33
+ }
34
+
23
35
 
24
36
  def lenient_lowercase(lst):
25
37
  """Lowercase elements of a list.
@@ -53,7 +65,8 @@ def human_to_bytes(number, default_unit=None, isbits=False):
53
65
  The function expects 'b' (lowercase) as a bit identifier, e.g. 'Mb'/'Kb'/etc.
54
66
  if 'MB'/'KB'/... is passed, the ValueError will be rased.
55
67
  """
56
- m = re.search(r'^\s*(\d*\.?\d*)\s*([A-Za-z]+)?', str(number), flags=re.IGNORECASE)
68
+ m = re.search(r'^([0-9]*\.?[0-9]+)(?:\s*([A-Za-z]+))?\s*$', str(number))
69
+
57
70
  if m is None:
58
71
  raise ValueError("human_to_bytes() can't interpret following string: %s" % str(number))
59
72
  try:
@@ -86,10 +99,13 @@ def human_to_bytes(number, default_unit=None, isbits=False):
86
99
  expect_message = 'expect %s%s or %s' % (range_key, unit_class, range_key)
87
100
  if range_key == 'B':
88
101
  expect_message = 'expect %s or %s' % (unit_class, unit_class_name)
89
-
90
- if unit_class_name in unit.lower():
102
+ unit_group = VALID_UNITS.get(range_key, None)
103
+ if unit_group is None:
104
+ raise ValueError(f"human_to_bytes() can't interpret a valid unit for {range_key}")
105
+ isbits_flag = 1 if isbits else 0
106
+ if unit.lower() == unit_group[isbits_flag][0]:
91
107
  pass
92
- elif unit[1] != unit_class:
108
+ elif unit != unit_group[isbits_flag][1]:
93
109
  raise ValueError("human_to_bytes() failed to convert %s. Value is not a valid string (%s)" % (number, expect_message))
94
110
 
95
111
  return int(round(num * limit))
@@ -4,6 +4,7 @@
4
4
 
5
5
  from __future__ import annotations
6
6
 
7
+ import decimal
7
8
  import json
8
9
  import os
9
10
  import re
@@ -13,10 +14,10 @@ from ansible.module_utils.common.text.converters import to_native
13
14
  from ansible.module_utils.common.collections import is_iterable
14
15
  from ansible.module_utils.common.text.converters import jsonify
15
16
  from ansible.module_utils.common.text.formatters import human_to_bytes
17
+ from ansible.module_utils.common.warnings import deprecate
16
18
  from ansible.module_utils.parsing.convert_bool import boolean
17
19
  from ansible.module_utils.six import (
18
20
  binary_type,
19
- integer_types,
20
21
  string_types,
21
22
  text_type,
22
23
  )
@@ -39,6 +40,10 @@ def count_terms(terms, parameters):
39
40
 
40
41
 
41
42
  def safe_eval(value, locals=None, include_exceptions=False):
43
+ deprecate(
44
+ "The safe_eval function should not be used.",
45
+ version="2.21",
46
+ )
42
47
  # do not allow method calls to modules
43
48
  if not isinstance(value, string_types):
44
49
  # already templated to a datavaluestructure, perhaps?
@@ -415,7 +420,7 @@ def check_type_dict(value):
415
420
 
416
421
  Raises :class:`TypeError` if unable to convert to a dict
417
422
 
418
- :arg value: Dict or string to convert to a dict. Accepts ``k1=v2, k2=v2``.
423
+ :arg value: Dict or string to convert to a dict. Accepts ``k1=v2, k2=v2`` or ``k1=v2 k2=v2``.
419
424
 
420
425
  :returns: value converted to a dictionary
421
426
  """
@@ -427,10 +432,14 @@ def check_type_dict(value):
427
432
  try:
428
433
  return json.loads(value)
429
434
  except Exception:
430
- (result, exc) = safe_eval(value, dict(), include_exceptions=True)
431
- if exc is not None:
432
- raise TypeError('unable to evaluate string as dictionary')
433
- return result
435
+ try:
436
+ result = literal_eval(value)
437
+ except Exception:
438
+ pass
439
+ else:
440
+ if isinstance(result, dict):
441
+ return result
442
+ raise TypeError('unable to evaluate string as dictionary')
434
443
  elif '=' in value:
435
444
  fields = []
436
445
  field_buffer = []
@@ -457,7 +466,11 @@ def check_type_dict(value):
457
466
  field = ''.join(field_buffer)
458
467
  if field:
459
468
  fields.append(field)
460
- return dict(x.split("=", 1) for x in fields)
469
+ try:
470
+ return dict(x.split("=", 1) for x in fields)
471
+ except ValueError:
472
+ # no "=" to split on: "k1=v1, k2"
473
+ raise TypeError('unable to evaluate string in the "key=value" format as dictionary')
461
474
  else:
462
475
  raise TypeError("dictionary requested, could not parse JSON or key=value")
463
476
 
@@ -493,16 +506,15 @@ def check_type_int(value):
493
506
 
494
507
  :return: int of given value
495
508
  """
496
- if isinstance(value, integer_types):
497
- return value
498
-
499
- if isinstance(value, string_types):
509
+ if not isinstance(value, int):
500
510
  try:
501
- return int(value)
502
- except ValueError:
503
- pass
504
-
505
- raise TypeError('%s cannot be converted to an int' % type(value))
511
+ if (decimal_value := decimal.Decimal(value)) != (int_value := int(decimal_value)):
512
+ raise ValueError("Significant decimal part found")
513
+ else:
514
+ value = int_value
515
+ except (decimal.DecimalException, TypeError, ValueError) as e:
516
+ raise TypeError(f'"{value!r}" cannot be converted to an int') from e
517
+ return value
506
518
 
507
519
 
508
520
  def check_type_float(value):
@@ -514,16 +526,12 @@ def check_type_float(value):
514
526
 
515
527
  :returns: float of given value.
516
528
  """
517
- if isinstance(value, float):
518
- return value
519
-
520
- if isinstance(value, (binary_type, text_type, int)):
529
+ if not isinstance(value, float):
521
530
  try:
522
- return float(value)
523
- except ValueError:
524
- pass
525
-
526
- raise TypeError('%s cannot be converted to a float' % type(value))
531
+ value = float(value)
532
+ except (TypeError, ValueError) as e:
533
+ raise TypeError(f'{type(value)} cannot be converted to a float')
534
+ return value
527
535
 
528
536
 
529
537
  def check_type_path(value,):
@@ -11,7 +11,12 @@ PARAMIKO_IMPORT_ERR = None
11
11
 
12
12
  try:
13
13
  with warnings.catch_warnings():
14
- warnings.filterwarnings('ignore', message='Blowfish has been deprecated', category=UserWarning)
14
+ # Blowfish has been moved, but the deprecated import is used by paramiko versions older than 2.9.5.
15
+ # See: https://github.com/paramiko/paramiko/pull/2039
16
+ warnings.filterwarnings('ignore', message='Blowfish has been ', category=UserWarning)
17
+ # TripleDES has been moved, but the deprecated import is used by paramiko versions older than 3.3.2 and 3.4.1.
18
+ # See: https://github.com/paramiko/paramiko/pull/2421
19
+ warnings.filterwarnings('ignore', message='TripleDES has been ', category=UserWarning)
15
20
  import paramiko # pylint: disable=unused-import
16
21
  # paramiko and gssapi are incompatible and raise AttributeError not ImportError
17
22
  # When running in FIPS mode, cryptography raises InternalError
@@ -11,8 +11,8 @@ from ctypes import CDLL, c_char_p, c_int, byref, POINTER, get_errno
11
11
 
12
12
  try:
13
13
  _selinux_lib = CDLL('libselinux.so.1', use_errno=True)
14
- except OSError:
15
- raise ImportError('unable to load libselinux.so')
14
+ except OSError as ex:
15
+ raise ImportError('unable to load libselinux.so') from ex
16
16
 
17
17
 
18
18
  def _module_setup():
@@ -29,8 +29,8 @@
29
29
  from __future__ import annotations
30
30
 
31
31
  import os
32
- import hashlib
33
32
  import json
33
+ import pickle
34
34
  import socket
35
35
  import struct
36
36
  import traceback
@@ -40,30 +40,14 @@ from functools import partial
40
40
  from ansible.module_utils.common.text.converters import to_bytes, to_text
41
41
  from ansible.module_utils.common.json import AnsibleJSONEncoder
42
42
  from ansible.module_utils.six import iteritems
43
- from ansible.module_utils.six.moves import cPickle
44
43
 
45
44
 
46
- def write_to_file_descriptor(fd, obj):
47
- """Handles making sure all data is properly written to file descriptor fd.
45
+ def write_to_stream(stream, obj):
46
+ """Write a length+newline-prefixed pickled object to a stream."""
47
+ src = pickle.dumps(obj)
48
48
 
49
- In particular, that data is encoded in a character stream-friendly way and
50
- that all data gets written before returning.
51
- """
52
- # Need to force a protocol that is compatible with both py2 and py3.
53
- # That would be protocol=2 or less.
54
- # Also need to force a protocol that excludes certain control chars as
55
- # stdin in this case is a pty and control chars will cause problems.
56
- # that means only protocol=0 will work.
57
- src = cPickle.dumps(obj, protocol=0)
58
-
59
- # raw \r characters will not survive pty round-trip
60
- # They should be rehydrated on the receiving end
61
- src = src.replace(b'\r', br'\r')
62
- data_hash = to_bytes(hashlib.sha1(src).hexdigest())
63
-
64
- os.write(fd, b'%d\n' % len(src))
65
- os.write(fd, src)
66
- os.write(fd, b'%s\n' % data_hash)
49
+ stream.write(b'%d\n' % len(src))
50
+ stream.write(src)
67
51
 
68
52
 
69
53
  def send_data(s, data):
@@ -146,7 +130,7 @@ class Connection(object):
146
130
  data = json.dumps(req, cls=AnsibleJSONEncoder, vault_to_text=True)
147
131
  except TypeError as exc:
148
132
  raise ConnectionError(
149
- "Failed to encode some variables as JSON for communication with ansible-connection. "
133
+ "Failed to encode some variables as JSON for communication with the persistent connection helper. "
150
134
  "The original exception was: %s" % to_text(exc)
151
135
  )
152
136
 
@@ -176,7 +160,7 @@ class Connection(object):
176
160
  if response['id'] != reqid:
177
161
  raise ConnectionError('invalid json-rpc id received')
178
162
  if "result_type" in response:
179
- response["result"] = cPickle.loads(to_bytes(response["result"]))
163
+ response["result"] = pickle.loads(to_bytes(response["result"], errors="surrogateescape"))
180
164
 
181
165
  return response
182
166
 
@@ -333,13 +333,12 @@ namespace Ansible.Become
333
333
  // Grant access to the current Windows Station and Desktop to the become user
334
334
  GrantAccessToWindowStationAndDesktop(account);
335
335
 
336
- // Try and impersonate a SYSTEM token, we need a SYSTEM token to either become a well known service
337
- // account or have administrative rights on the become access token.
338
- // If we ultimately are becoming the SYSTEM account we want the token with the most privileges available.
339
- // https://github.com/ansible/ansible/issues/71453
340
- bool mostPrivileges = becomeSid == "S-1-5-18";
336
+ // Try and impersonate a SYSTEM token. We need the SeTcbPrivilege for
337
+ // - LogonUser for a service SID
338
+ // - S4U logon
339
+ // - Token elevation
341
340
  systemToken = GetPrimaryTokenForUser(new SecurityIdentifier("S-1-5-18"),
342
- new List<string>() { "SeTcbPrivilege" }, mostPrivileges);
341
+ new List<string>() { "SeTcbPrivilege" });
343
342
  if (systemToken != null)
344
343
  {
345
344
  try
@@ -357,11 +356,9 @@ namespace Ansible.Become
357
356
 
358
357
  try
359
358
  {
360
- if (becomeSid == "S-1-5-18")
361
- userTokens.Add(systemToken);
362
359
  // Cannot use String.IsEmptyOrNull() as an empty string is an account that doesn't have a pass.
363
360
  // We only use S4U if no password was defined or it was null
364
- else if (!SERVICE_SIDS.Contains(becomeSid) && password == null && logonType != LogonType.NewCredentials)
361
+ if (!SERVICE_SIDS.Contains(becomeSid) && password == null && logonType != LogonType.NewCredentials)
365
362
  {
366
363
  // If no password was specified, try and duplicate an existing token for that user or use S4U to
367
364
  // generate one without network credentials
@@ -384,6 +381,11 @@ namespace Ansible.Become
384
381
  string domain = null;
385
382
  switch (becomeSid)
386
383
  {
384
+ case "S-1-5-18":
385
+ logonType = LogonType.Service;
386
+ domain = "NT AUTHORITY";
387
+ username = "SYSTEM";
388
+ break;
387
389
  case "S-1-5-19":
388
390
  logonType = LogonType.Service;
389
391
  domain = "NT AUTHORITY";
@@ -426,7 +428,7 @@ namespace Ansible.Become
426
428
  }
427
429
 
428
430
  private static SafeNativeHandle GetPrimaryTokenForUser(SecurityIdentifier sid,
429
- List<string> requiredPrivileges = null, bool mostPrivileges = false)
431
+ List<string> requiredPrivileges = null)
430
432
  {
431
433
  // According to CreateProcessWithTokenW we require a token with
432
434
  // TOKEN_QUERY, TOKEN_DUPLICATE and TOKEN_ASSIGN_PRIMARY
@@ -436,9 +438,6 @@ namespace Ansible.Become
436
438
  TokenAccessLevels.AssignPrimary |
437
439
  TokenAccessLevels.Impersonate;
438
440
 
439
- SafeNativeHandle userToken = null;
440
- int privilegeCount = 0;
441
-
442
441
  foreach (SafeNativeHandle hToken in TokenUtil.EnumerateUserTokens(sid, dwAccess))
443
442
  {
444
443
  // Filter out any Network logon tokens, using become with that is useless when S4U
@@ -449,10 +448,6 @@ namespace Ansible.Become
449
448
 
450
449
  List<string> actualPrivileges = TokenUtil.GetTokenPrivileges(hToken).Select(x => x.Name).ToList();
451
450
 
452
- // If the token has less or the same number of privileges than the current token, skip it.
453
- if (mostPrivileges && privilegeCount >= actualPrivileges.Count)
454
- continue;
455
-
456
451
  // Check that the required privileges are on the token
457
452
  if (requiredPrivileges != null)
458
453
  {
@@ -464,22 +459,16 @@ namespace Ansible.Become
464
459
  // Duplicate the token to convert it to a primary token with the access level required.
465
460
  try
466
461
  {
467
- userToken = TokenUtil.DuplicateToken(hToken, TokenAccessLevels.MaximumAllowed,
462
+ return TokenUtil.DuplicateToken(hToken, TokenAccessLevels.MaximumAllowed,
468
463
  SecurityImpersonationLevel.Anonymous, TokenType.Primary);
469
- privilegeCount = actualPrivileges.Count;
470
464
  }
471
465
  catch (Process.Win32Exception)
472
466
  {
473
467
  continue;
474
468
  }
475
-
476
- // If we don't care about getting the token with the most privileges, escape the loop as we already
477
- // have a token.
478
- if (!mostPrivileges)
479
- break;
480
469
  }
481
470
 
482
- return userToken;
471
+ return null;
483
472
  }
484
473
 
485
474
  private static SafeNativeHandle GetS4UTokenForUser(SecurityIdentifier sid, LogonType logonType)
@@ -397,7 +397,7 @@ namespace Ansible.Process
397
397
  internal static Result WaitProcess(SafeFileHandle stdoutRead, SafeFileHandle stdoutWrite, SafeFileHandle stderrRead,
398
398
  SafeFileHandle stderrWrite, FileStream stdinStream, byte[] stdin, IntPtr hProcess, string outputEncoding = null)
399
399
  {
400
- // Default to using UTF-8 as the output encoding, this should be a sane default for most scenarios.
400
+ // Default to using UTF-8 as the output encoding, this should be a logical default for most scenarios.
401
401
  outputEncoding = String.IsNullOrEmpty(outputEncoding) ? "utf-8" : outputEncoding;
402
402
  Encoding encodingInstance = Encoding.GetEncoding(outputEncoding);
403
403
 
@@ -22,7 +22,7 @@ Compat distro library.
22
22
  from __future__ import annotations
23
23
 
24
24
  # The following makes it easier for us to script updates of the bundled code
25
- _BUNDLED_METADATA = {"pypi_name": "distro", "version": "1.8.0"}
25
+ _BUNDLED_METADATA = {"pypi_name": "distro", "version": "1.9.0"}
26
26
 
27
27
  # The following additional changes have been made:
28
28
  # * Remove optparse since it is not needed for our use.
@@ -1,4 +1,4 @@
1
- # Copyright 2015,2016,2017 Nir Cohen
1
+ # Copyright 2015-2021 Nir Cohen
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -59,7 +59,7 @@ except ImportError:
59
59
  # Python 3.7
60
60
  TypedDict = dict
61
61
 
62
- __version__ = "1.8.0"
62
+ __version__ = "1.9.0"
63
63
 
64
64
 
65
65
  class VersionDict(TypedDict):
@@ -129,6 +129,7 @@ _DISTRO_RELEASE_BASENAME_PATTERN = re.compile(r"(\w+)[-_](release|version)$")
129
129
  # Base file names to be looked up for if _UNIXCONFDIR is not readable.
130
130
  _DISTRO_RELEASE_BASENAMES = [
131
131
  "SuSE-release",
132
+ "altlinux-release",
132
133
  "arch-release",
133
134
  "base-release",
134
135
  "centos-release",
@@ -155,6 +156,8 @@ _DISTRO_RELEASE_IGNORE_BASENAMES = (
155
156
  "system-release",
156
157
  "plesk-release",
157
158
  "iredmail-release",
159
+ "board-release",
160
+ "ec2_version",
158
161
  )
159
162
 
160
163
 
@@ -247,6 +250,7 @@ def id() -> str:
247
250
  "rocky" Rocky Linux
248
251
  "aix" AIX
249
252
  "guix" Guix System
253
+ "altlinux" ALT Linux
250
254
  ============== =========================================
251
255
 
252
256
  If you have a need to get distros for reliable IDs added into this set,
@@ -995,10 +999,10 @@ class LinuxDistribution:
995
999
 
996
1000
  For details, see :func:`distro.info`.
997
1001
  """
998
- return dict(
1002
+ return InfoDict(
999
1003
  id=self.id(),
1000
1004
  version=self.version(pretty, best),
1001
- version_parts=dict(
1005
+ version_parts=VersionDict(
1002
1006
  major=self.major_version(best),
1003
1007
  minor=self.minor_version(best),
1004
1008
  build_number=self.build_number(best),
@@ -90,6 +90,8 @@ class BaseFactCollector:
90
90
  def _transform_dict_keys(self, fact_dict):
91
91
  '''update a dicts keys to use new names as transformed by self._transform_name'''
92
92
 
93
+ if fact_dict is None:
94
+ return {}
93
95
  for old_key in list(fact_dict.keys()):
94
96
  new_key = self._transform_name(old_key)
95
97
  # pop the item by old_key and replace it using new_key
@@ -53,6 +53,7 @@ from ansible.module_utils.facts.system.python import PythonFactCollector
53
53
  from ansible.module_utils.facts.system.selinux import SelinuxFactCollector
54
54
  from ansible.module_utils.facts.system.service_mgr import ServiceMgrFactCollector
55
55
  from ansible.module_utils.facts.system.ssh_pub_keys import SshPubKeyFactCollector
56
+ from ansible.module_utils.facts.system.systemd import SystemdFactCollector
56
57
  from ansible.module_utils.facts.system.user import UserFactCollector
57
58
 
58
59
  from ansible.module_utils.facts.hardware.base import HardwareCollector
@@ -118,7 +119,8 @@ _general = [
118
119
  EnvFactCollector,
119
120
  LoadAvgFactCollector,
120
121
  SshPubKeyFactCollector,
121
- UserFactCollector
122
+ UserFactCollector,
123
+ SystemdFactCollector
122
124
  ] # type: t.List[t.Type[BaseFactCollector]]
123
125
 
124
126
  # virtual, this might also limit hardware/networking
@@ -195,34 +195,35 @@ class AIXHardware(Hardware):
195
195
  # AIX does not have mtab but mount command is only source of info (or to use
196
196
  # api calls to get same info)
197
197
  mount_path = self.module.get_bin_path('mount')
198
- rc, mount_out, err = self.module.run_command(mount_path)
199
- if mount_out:
200
- for line in mount_out.split('\n'):
201
- fields = line.split()
202
- if len(fields) != 0 and fields[0] != 'node' and fields[0][0] != '-' and re.match('^/.*|^[a-zA-Z].*|^[0-9].*', fields[0]):
203
- if re.match('^/', fields[0]):
204
- # normal mount
205
- mount = fields[1]
206
- mount_info = {'mount': mount,
207
- 'device': fields[0],
208
- 'fstype': fields[2],
209
- 'options': fields[6],
210
- 'time': '%s %s %s' % (fields[3], fields[4], fields[5])}
211
- mount_info.update(get_mount_size(mount))
212
- else:
213
- # nfs or cifs based mount
214
- # in case of nfs if no mount options are provided on command line
215
- # add into fields empty string...
216
- if len(fields) < 8:
217
- fields.append("")
218
-
219
- mount_info = {'mount': fields[2],
220
- 'device': '%s:%s' % (fields[0], fields[1]),
221
- 'fstype': fields[3],
222
- 'options': fields[7],
223
- 'time': '%s %s %s' % (fields[4], fields[5], fields[6])}
224
-
225
- mounts.append(mount_info)
198
+ if mount_path:
199
+ rc, mount_out, err = self.module.run_command(mount_path)
200
+ if mount_out:
201
+ for line in mount_out.split('\n'):
202
+ fields = line.split()
203
+ if len(fields) != 0 and fields[0] != 'node' and fields[0][0] != '-' and re.match('^/.*|^[a-zA-Z].*|^[0-9].*', fields[0]):
204
+ if re.match('^/', fields[0]):
205
+ # normal mount
206
+ mount = fields[1]
207
+ mount_info = {'mount': mount,
208
+ 'device': fields[0],
209
+ 'fstype': fields[2],
210
+ 'options': fields[6],
211
+ 'time': '%s %s %s' % (fields[3], fields[4], fields[5])}
212
+ mount_info.update(get_mount_size(mount))
213
+ else:
214
+ # nfs or cifs based mount
215
+ # in case of nfs if no mount options are provided on command line
216
+ # add into fields empty string...
217
+ if len(fields) < 8:
218
+ fields.append("")
219
+
220
+ mount_info = {'mount': fields[2],
221
+ 'device': '%s:%s' % (fields[0], fields[1]),
222
+ 'fstype': fields[3],
223
+ 'options': fields[7],
224
+ 'time': '%s %s %s' % (fields[4], fields[5], fields[6])}
225
+
226
+ mounts.append(mount_info)
226
227
 
227
228
  mount_facts['mounts'] = mounts
228
229
 
@@ -232,30 +233,31 @@ class AIXHardware(Hardware):
232
233
  device_facts = {}
233
234
  device_facts['devices'] = {}
234
235
 
235
- lsdev_cmd = self.module.get_bin_path('lsdev', True)
236
- lsattr_cmd = self.module.get_bin_path('lsattr', True)
237
- rc, out_lsdev, err = self.module.run_command(lsdev_cmd)
238
-
239
- for line in out_lsdev.splitlines():
240
- field = line.split()
241
-
242
- device_attrs = {}
243
- device_name = field[0]
244
- device_state = field[1]
245
- device_type = field[2:]
246
- lsattr_cmd_args = [lsattr_cmd, '-E', '-l', device_name]
247
- rc, out_lsattr, err = self.module.run_command(lsattr_cmd_args)
248
- for attr in out_lsattr.splitlines():
249
- attr_fields = attr.split()
250
- attr_name = attr_fields[0]
251
- attr_parameter = attr_fields[1]
252
- device_attrs[attr_name] = attr_parameter
253
-
254
- device_facts['devices'][device_name] = {
255
- 'state': device_state,
256
- 'type': ' '.join(device_type),
257
- 'attributes': device_attrs
258
- }
236
+ lsdev_cmd = self.module.get_bin_path('lsdev')
237
+ lsattr_cmd = self.module.get_bin_path('lsattr')
238
+ if lsdev_cmd and lsattr_cmd:
239
+ rc, out_lsdev, err = self.module.run_command(lsdev_cmd)
240
+
241
+ for line in out_lsdev.splitlines():
242
+ field = line.split()
243
+
244
+ device_attrs = {}
245
+ device_name = field[0]
246
+ device_state = field[1]
247
+ device_type = field[2:]
248
+ lsattr_cmd_args = [lsattr_cmd, '-E', '-l', device_name]
249
+ rc, out_lsattr, err = self.module.run_command(lsattr_cmd_args)
250
+ for attr in out_lsattr.splitlines():
251
+ attr_fields = attr.split()
252
+ attr_name = attr_fields[0]
253
+ attr_parameter = attr_fields[1]
254
+ device_attrs[attr_name] = attr_parameter
255
+
256
+ device_facts['devices'][device_name] = {
257
+ 'state': device_state,
258
+ 'type': ' '.join(device_type),
259
+ 'attributes': device_attrs
260
+ }
259
261
 
260
262
  return device_facts
261
263