ansible-core 2.17.6__py3-none-any.whl → 2.18.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ansible-core might be problematic. Click here for more details.
- ansible/__main__.py +2 -17
- ansible/cli/__init__.py +3 -15
- ansible/cli/config.py +187 -24
- ansible/cli/console.py +1 -1
- ansible/cli/doc.py +38 -16
- ansible/cli/galaxy.py +3 -49
- ansible/cli/inventory.py +2 -2
- ansible/cli/pull.py +2 -2
- ansible/cli/scripts/ansible_connection_cli_stub.py +1 -10
- ansible/config/base.yml +127 -57
- ansible/config/manager.py +89 -11
- ansible/constants.py +32 -9
- ansible/errors/__init__.py +5 -0
- ansible/executor/interpreter_discovery.py +1 -1
- ansible/executor/play_iterator.py +16 -0
- ansible/executor/playbook_executor.py +1 -4
- ansible/executor/powershell/become_wrapper.ps1 +4 -5
- ansible/executor/powershell/bootstrap_wrapper.ps1 +2 -3
- ansible/executor/powershell/exec_wrapper.ps1 +1 -1
- ansible/executor/powershell/module_manifest.py +2 -2
- ansible/executor/task_executor.py +50 -39
- ansible/executor/task_queue_manager.py +1 -1
- ansible/executor/task_result.py +1 -1
- ansible/galaxy/api.py +3 -4
- ansible/galaxy/collection/__init__.py +21 -10
- ansible/galaxy/collection/concrete_artifact_manager.py +2 -2
- ansible/galaxy/collection/galaxy_api_proxy.py +10 -16
- ansible/galaxy/collection/gpg.py +17 -23
- ansible/galaxy/data/COPYING +7 -0
- ansible/galaxy/data/apb/Dockerfile.j2 +1 -0
- ansible/galaxy/data/apb/Makefile.j2 +1 -0
- ansible/galaxy/data/apb/README.md +7 -3
- ansible/galaxy/data/apb/apb.yml.j2 +1 -0
- ansible/galaxy/data/apb/defaults/main.yml.j2 +1 -0
- ansible/galaxy/data/apb/handlers/main.yml.j2 +1 -0
- ansible/galaxy/data/apb/meta/main.yml.j2 +1 -0
- ansible/galaxy/data/apb/playbooks/deprovision.yml.j2 +1 -0
- ansible/galaxy/data/apb/playbooks/provision.yml.j2 +1 -0
- ansible/galaxy/data/apb/tasks/main.yml.j2 +1 -0
- ansible/galaxy/data/apb/tests/ansible.cfg +1 -0
- ansible/galaxy/data/apb/tests/inventory +1 -0
- ansible/galaxy/data/apb/tests/test.yml.j2 +1 -0
- ansible/galaxy/data/apb/vars/main.yml.j2 +1 -0
- ansible/galaxy/data/collections_galaxy_meta.yml +1 -0
- ansible/galaxy/data/container/defaults/main.yml.j2 +1 -0
- ansible/galaxy/data/container/handlers/main.yml.j2 +1 -0
- ansible/galaxy/data/container/meta/container.yml.j2 +1 -0
- ansible/galaxy/data/container/meta/main.yml.j2 +1 -0
- ansible/galaxy/data/container/tasks/main.yml.j2 +1 -0
- ansible/galaxy/data/container/tests/ansible.cfg +1 -0
- ansible/galaxy/data/container/tests/inventory +1 -0
- ansible/galaxy/data/container/tests/test.yml.j2 +1 -0
- ansible/galaxy/data/container/vars/main.yml.j2 +1 -0
- ansible/galaxy/data/default/collection/README.md.j2 +1 -0
- ansible/galaxy/data/default/collection/galaxy.yml.j2 +1 -0
- ansible/galaxy/data/default/collection/meta/runtime.yml +1 -0
- ansible/galaxy/data/default/collection/plugins/README.md.j2 +1 -0
- ansible/galaxy/data/default/role/defaults/main.yml.j2 +1 -0
- ansible/galaxy/data/default/role/handlers/main.yml.j2 +1 -0
- ansible/galaxy/data/default/role/meta/main.yml.j2 +1 -0
- ansible/galaxy/data/default/role/tasks/main.yml.j2 +1 -0
- ansible/galaxy/data/default/role/tests/inventory +1 -0
- ansible/galaxy/data/default/role/tests/test.yml.j2 +1 -0
- ansible/galaxy/data/default/role/vars/main.yml.j2 +1 -0
- ansible/galaxy/data/network/cliconf_plugins/example.py.j2 +1 -0
- ansible/galaxy/data/network/defaults/main.yml.j2 +1 -0
- ansible/galaxy/data/network/library/example_command.py.j2 +1 -0
- ansible/galaxy/data/network/library/example_config.py.j2 +1 -0
- ansible/galaxy/data/network/library/example_facts.py.j2 +1 -0
- ansible/galaxy/data/network/meta/main.yml.j2 +1 -0
- ansible/galaxy/data/network/module_utils/example.py.j2 +1 -0
- ansible/galaxy/data/network/netconf_plugins/example.py.j2 +1 -0
- ansible/galaxy/data/network/tasks/main.yml.j2 +1 -0
- ansible/galaxy/data/network/terminal_plugins/example.py.j2 +1 -0
- ansible/galaxy/data/network/tests/inventory +1 -0
- ansible/galaxy/data/network/tests/test.yml.j2 +1 -0
- ansible/galaxy/data/network/vars/main.yml.j2 +1 -0
- ansible/galaxy/dependency_resolution/providers.py +3 -3
- ansible/galaxy/role.py +1 -1
- ansible/galaxy/token.py +20 -8
- ansible/keyword_desc.yml +1 -1
- ansible/module_utils/_internal/__init__.py +0 -0
- ansible/module_utils/_internal/_concurrent/__init__.py +0 -0
- ansible/module_utils/_internal/_concurrent/_daemon_threading.py +28 -0
- ansible/module_utils/_internal/_concurrent/_futures.py +21 -0
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/api.py +2 -2
- ansible/module_utils/basic.py +8 -8
- ansible/module_utils/common/collections.py +1 -1
- ansible/module_utils/common/file.py +0 -6
- ansible/module_utils/common/process.py +22 -9
- ansible/module_utils/common/text/converters.py +5 -8
- ansible/module_utils/common/text/formatters.py +20 -4
- ansible/module_utils/common/validation.py +33 -25
- ansible/module_utils/compat/paramiko.py +6 -1
- ansible/module_utils/compat/selinux.py +2 -2
- ansible/module_utils/connection.py +8 -24
- ansible/module_utils/csharp/Ansible.Become.cs +14 -25
- ansible/module_utils/csharp/Ansible.Process.cs +1 -1
- ansible/module_utils/distro/__init__.py +1 -1
- ansible/module_utils/distro/_distro.py +8 -4
- ansible/module_utils/facts/collector.py +2 -0
- ansible/module_utils/facts/default_collectors.py +3 -1
- ansible/module_utils/facts/hardware/aix.py +54 -52
- ansible/module_utils/facts/hardware/darwin.py +37 -34
- ansible/module_utils/facts/hardware/freebsd.py +55 -15
- ansible/module_utils/facts/hardware/hpux.py +3 -0
- ansible/module_utils/facts/hardware/linux.py +101 -57
- ansible/module_utils/facts/hardware/netbsd.py +3 -0
- ansible/module_utils/facts/hardware/openbsd.py +4 -1
- ansible/module_utils/facts/hardware/sunos.py +7 -1
- ansible/module_utils/facts/network/aix.py +16 -17
- ansible/module_utils/facts/network/fc_wwn.py +4 -1
- ansible/module_utils/facts/network/hpux.py +21 -4
- ansible/module_utils/facts/network/iscsi.py +7 -8
- ansible/module_utils/facts/network/linux.py +0 -2
- ansible/module_utils/facts/other/facter.py +9 -4
- ansible/module_utils/facts/other/ohai.py +5 -5
- ansible/module_utils/facts/packages.py +49 -7
- ansible/module_utils/facts/sysctl.py +33 -31
- ansible/module_utils/facts/system/distribution.py +1 -1
- ansible/module_utils/facts/system/local.py +12 -22
- ansible/module_utils/facts/system/service_mgr.py +3 -1
- ansible/module_utils/facts/system/systemd.py +47 -0
- ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 +1 -1
- ansible/module_utils/splitter.py +1 -1
- ansible/modules/add_host.py +1 -1
- ansible/modules/apt.py +43 -32
- ansible/modules/apt_key.py +6 -6
- ansible/modules/apt_repository.py +23 -14
- ansible/modules/assemble.py +7 -2
- ansible/modules/assert.py +4 -4
- ansible/modules/blockinfile.py +3 -6
- ansible/modules/command.py +1 -1
- ansible/modules/copy.py +4 -4
- ansible/modules/cron.py +13 -10
- ansible/modules/deb822_repository.py +16 -17
- ansible/modules/debconf.py +9 -9
- ansible/modules/debug.py +1 -1
- ansible/modules/dnf.py +79 -164
- ansible/modules/dnf5.py +54 -29
- ansible/modules/dpkg_selections.py +2 -2
- ansible/modules/expect.py +2 -2
- ansible/modules/fetch.py +2 -2
- ansible/modules/file.py +5 -3
- ansible/modules/find.py +40 -12
- ansible/modules/gather_facts.py +4 -2
- ansible/modules/get_url.py +29 -24
- ansible/modules/git.py +35 -35
- ansible/modules/group.py +71 -1
- ansible/modules/hostname.py +2 -4
- ansible/modules/include_vars.py +5 -5
- ansible/modules/iptables.py +13 -16
- ansible/modules/known_hosts.py +16 -13
- ansible/modules/lineinfile.py +1 -4
- ansible/modules/meta.py +6 -1
- ansible/modules/mount_facts.py +651 -0
- ansible/modules/package_facts.py +63 -80
- ansible/modules/pause.py +4 -3
- ansible/modules/pip.py +14 -14
- ansible/modules/replace.py +1 -4
- ansible/modules/rpm_key.py +31 -11
- ansible/modules/service.py +8 -8
- ansible/modules/service_facts.py +20 -5
- ansible/modules/set_stats.py +1 -1
- ansible/modules/setup.py +3 -3
- ansible/modules/stat.py +3 -3
- ansible/modules/subversion.py +1 -1
- ansible/modules/systemd.py +16 -10
- ansible/modules/systemd_service.py +16 -10
- ansible/modules/sysvinit.py +4 -4
- ansible/modules/unarchive.py +35 -22
- ansible/modules/uri.py +24 -18
- ansible/modules/user.py +145 -12
- ansible/modules/validate_argument_spec.py +3 -3
- ansible/modules/wait_for_connection.py +2 -1
- ansible/modules/yum_repository.py +136 -179
- ansible/parsing/dataloader.py +2 -2
- ansible/parsing/mod_args.py +11 -10
- ansible/parsing/vault/__init__.py +8 -3
- ansible/parsing/yaml/constructor.py +10 -8
- ansible/parsing/yaml/objects.py +1 -1
- ansible/playbook/base.py +12 -23
- ansible/playbook/helpers.py +4 -0
- ansible/playbook/loop_control.py +8 -0
- ansible/playbook/play.py +4 -22
- ansible/playbook/play_context.py +0 -16
- ansible/playbook/playbook_include.py +2 -2
- ansible/playbook/role/__init__.py +2 -2
- ansible/plugins/__init__.py +2 -0
- ansible/plugins/action/__init__.py +7 -9
- ansible/plugins/action/dnf.py +7 -5
- ansible/plugins/action/package.py +5 -4
- ansible/plugins/action/reboot.py +2 -2
- ansible/plugins/become/__init__.py +1 -1
- ansible/plugins/callback/__init__.py +44 -3
- ansible/plugins/callback/default.py +1 -1
- ansible/plugins/cliconf/__init__.py +1 -1
- ansible/plugins/connection/paramiko_ssh.py +2 -80
- ansible/plugins/connection/psrp.py +33 -82
- ansible/plugins/connection/ssh.py +0 -8
- ansible/plugins/connection/winrm.py +46 -1
- ansible/plugins/doc_fragments/connection_pipelining.py +2 -2
- ansible/plugins/doc_fragments/constructed.py +10 -10
- ansible/plugins/doc_fragments/default_callback.py +8 -8
- ansible/plugins/doc_fragments/files.py +5 -5
- ansible/plugins/doc_fragments/inventory_cache.py +2 -2
- ansible/plugins/doc_fragments/result_format_callback.py +6 -6
- ansible/plugins/doc_fragments/return_common.py +1 -1
- ansible/plugins/doc_fragments/shell_common.py +2 -10
- ansible/plugins/doc_fragments/shell_windows.py +0 -9
- ansible/plugins/doc_fragments/url.py +2 -2
- ansible/plugins/doc_fragments/url_windows.py +4 -5
- ansible/plugins/doc_fragments/validate.py +1 -1
- ansible/plugins/filter/core.py +2 -0
- ansible/plugins/filter/human_to_bytes.yml +9 -0
- ansible/plugins/filter/password_hash.yml +1 -1
- ansible/plugins/filter/strftime.yml +1 -1
- ansible/plugins/filter/to_nice_json.yml +7 -3
- ansible/plugins/filter/to_uuid.yml +1 -1
- ansible/plugins/inventory/script.py +1 -1
- ansible/plugins/list.py +1 -1
- ansible/plugins/loader.py +0 -11
- ansible/plugins/lookup/config.py +1 -1
- ansible/plugins/lookup/csvfile.py +21 -9
- ansible/plugins/lookup/env.py +8 -9
- ansible/plugins/lookup/ini.py +10 -1
- ansible/plugins/lookup/random_choice.py +2 -2
- ansible/plugins/lookup/url.py +7 -2
- ansible/plugins/shell/__init__.py +15 -20
- ansible/plugins/shell/powershell.py +9 -6
- ansible/plugins/strategy/__init__.py +16 -7
- ansible/plugins/test/core.py +23 -1
- ansible/plugins/test/issubset.yml +1 -1
- ansible/plugins/test/subset.yml +1 -1
- ansible/plugins/test/timedout.yml +20 -0
- ansible/plugins/test/vault_encrypted.yml +6 -6
- ansible/plugins/test/vaulted_file.yml +19 -0
- ansible/release.py +2 -2
- ansible/template/__init__.py +3 -8
- ansible/utils/collection_loader/_collection_finder.py +23 -55
- ansible/utils/display.py +44 -31
- ansible/utils/jsonrpc.py +1 -1
- ansible/utils/listify.py +1 -5
- ansible/utils/path.py +3 -0
- ansible/utils/vars.py +18 -27
- ansible/vars/manager.py +7 -150
- ansible/vars/plugins.py +1 -1
- ansible_core-2.18.0.dist-info/Apache-License.txt +202 -0
- {ansible_core-2.17.6.dist-info → ansible_core-2.18.0.dist-info}/METADATA +36 -23
- ansible_core-2.18.0.dist-info/MIT-license.txt +14 -0
- ansible_core-2.18.0.dist-info/PSF-license.txt +48 -0
- {ansible_core-2.17.6.dist-info → ansible_core-2.18.0.dist-info}/RECORD +316 -311
- {ansible_core-2.17.6.dist-info → ansible_core-2.18.0.dist-info}/entry_points.txt +1 -1
- ansible_core-2.18.0.dist-info/simplified_bsd.txt +8 -0
- ansible_test/_data/completion/docker.txt +7 -7
- ansible_test/_data/completion/remote.txt +5 -4
- ansible_test/_data/completion/windows.txt +4 -4
- ansible_test/_data/requirements/ansible-test.txt +1 -2
- ansible_test/_data/requirements/constraints.txt +1 -2
- ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
- ansible_test/_data/requirements/sanity.changelog.in +1 -1
- ansible_test/_data/requirements/sanity.changelog.txt +4 -4
- ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
- ansible_test/_data/requirements/sanity.import.txt +1 -1
- ansible_test/_data/requirements/sanity.integration-aliases.txt +1 -1
- ansible_test/_data/requirements/sanity.pep8.txt +1 -1
- ansible_test/_data/requirements/sanity.pylint.txt +6 -8
- ansible_test/_data/requirements/sanity.runtime-metadata.txt +2 -2
- ansible_test/_data/requirements/sanity.validate-modules.txt +3 -3
- ansible_test/_data/requirements/sanity.yamllint.in +1 -0
- ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
- ansible_test/_internal/ansible_util.py +8 -35
- ansible_test/_internal/ci/azp.py +1 -1
- ansible_test/_internal/classification/__init__.py +0 -2
- ansible_test/_internal/cli/parsers/key_value_parsers.py +3 -0
- ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -1
- ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
- ansible_test/_internal/commands/integration/cloud/nios.py +1 -1
- ansible_test/_internal/commands/sanity/__init__.py +96 -19
- ansible_test/_internal/commands/sanity/pylint.py +20 -24
- ansible_test/_internal/completion.py +2 -0
- ansible_test/_internal/constants.py +0 -1
- ansible_test/_internal/coverage_util.py +1 -2
- ansible_test/_internal/docker_util.py +1 -1
- ansible_test/_internal/encoding.py +4 -4
- ansible_test/_internal/host_configs.py +10 -0
- ansible_test/_internal/host_profiles.py +9 -13
- ansible_test/_internal/pypi_proxy.py +1 -1
- ansible_test/_internal/python_requirements.py +5 -14
- ansible_test/_internal/timeout.py +1 -1
- ansible_test/_internal/util.py +40 -0
- ansible_test/_internal/util_common.py +5 -1
- ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.json +3 -1
- ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +6 -3
- ansible_test/_util/controller/sanity/code-smell/empty-init.json +0 -2
- ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +5 -0
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +5 -0
- ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +5 -0
- ansible_test/_util/controller/sanity/pylint/config/collection.cfg +6 -0
- ansible_test/_util/controller/sanity/pylint/config/default.cfg +6 -0
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -19
- ansible_test/_util/controller/sanity/shellcheck/exclude.txt +1 -0
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +67 -2
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +27 -5
- ansible_test/_util/target/cli/ansible_test_cli_stub.py +0 -0
- ansible_test/_util/target/common/constants.py +2 -2
- ansible_test/_util/target/injector/python.py +5 -0
- ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +6 -0
- ansible_test/_util/target/sanity/import/importer.py +1 -1
- ansible_test/_util/target/setup/bootstrap.sh +6 -17
- ansible_test/_util/target/setup/requirements.py +18 -24
- ansible_test/config/config.yml +1 -1
- ansible_core-2.17.6.data/scripts/ansible-test +0 -44
- ansible_test/_data/requirements/sanity.mypy.in +0 -10
- ansible_test/_data/requirements/sanity.mypy.txt +0 -18
- ansible_test/_internal/commands/sanity/mypy.py +0 -274
- ansible_test/_util/controller/sanity/mypy/ansible-core.ini +0 -116
- ansible_test/_util/controller/sanity/mypy/ansible-test.ini +0 -27
- ansible_test/_util/controller/sanity/mypy/modules.ini +0 -92
- ansible_test/_util/controller/sanity/mypy/packaging.ini +0 -20
- {ansible_core-2.17.6.dist-info → ansible_core-2.18.0.dist-info}/COPYING +0 -0
- {ansible_core-2.17.6.dist-info → ansible_core-2.18.0.dist-info}/WHEEL +0 -0
- {ansible_core-2.17.6.dist-info → ansible_core-2.18.0.dist-info}/top_level.txt +0 -0
|
@@ -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
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
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
|
-
|
|
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,
|
|
497
|
-
return value
|
|
498
|
-
|
|
499
|
-
if isinstance(value, string_types):
|
|
509
|
+
if not isinstance(value, int):
|
|
500
510
|
try:
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
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
|
-
|
|
523
|
-
except ValueError:
|
|
524
|
-
|
|
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
|
-
|
|
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
|
|
47
|
-
"""
|
|
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
|
-
|
|
50
|
-
|
|
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
|
|
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"] =
|
|
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
|
|
337
|
-
//
|
|
338
|
-
//
|
|
339
|
-
//
|
|
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" }
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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.
|
|
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
|
|
1002
|
+
return InfoDict(
|
|
999
1003
|
id=self.id(),
|
|
1000
1004
|
version=self.version(pretty, best),
|
|
1001
|
-
version_parts=
|
|
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
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
if re.match('
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
fields
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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'
|
|
236
|
-
lsattr_cmd = self.module.get_bin_path('lsattr'
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
'
|
|
256
|
-
|
|
257
|
-
|
|
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
|
|
|
@@ -19,7 +19,6 @@ from __future__ import annotations
|
|
|
19
19
|
import struct
|
|
20
20
|
import time
|
|
21
21
|
|
|
22
|
-
from ansible.module_utils.common.process import get_bin_path
|
|
23
22
|
from ansible.module_utils.facts.hardware.base import Hardware, HardwareCollector
|
|
24
23
|
from ansible.module_utils.facts.sysctl import get_sysctl
|
|
25
24
|
|
|
@@ -41,7 +40,7 @@ class DarwinHardware(Hardware):
|
|
|
41
40
|
def populate(self, collected_facts=None):
|
|
42
41
|
hardware_facts = {}
|
|
43
42
|
|
|
44
|
-
self.sysctl = get_sysctl(self.module, ['hw', 'machdep', 'kern'])
|
|
43
|
+
self.sysctl = get_sysctl(self.module, ['hw', 'machdep', 'kern', 'hw.model'])
|
|
45
44
|
mac_facts = self.get_mac_facts()
|
|
46
45
|
cpu_facts = self.get_cpu_facts()
|
|
47
46
|
memory_facts = self.get_memory_facts()
|
|
@@ -67,9 +66,8 @@ class DarwinHardware(Hardware):
|
|
|
67
66
|
|
|
68
67
|
def get_mac_facts(self):
|
|
69
68
|
mac_facts = {}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
mac_facts['model'] = mac_facts['product_name'] = out.splitlines()[-1].split()[1]
|
|
69
|
+
if 'hw.model' in self.sysctl:
|
|
70
|
+
mac_facts['model'] = mac_facts['product_name'] = self.sysctl['hw.model']
|
|
73
71
|
mac_facts['osversion'] = self.sysctl['kern.osversion']
|
|
74
72
|
mac_facts['osrevision'] = self.sysctl['kern.osrevision']
|
|
75
73
|
|
|
@@ -96,44 +94,49 @@ class DarwinHardware(Hardware):
|
|
|
96
94
|
|
|
97
95
|
total_used = 0
|
|
98
96
|
page_size = 4096
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
97
|
+
|
|
98
|
+
vm_stat_command = self.module.get_bin_path('vm_stat')
|
|
99
|
+
if vm_stat_command is None:
|
|
102
100
|
return memory_facts
|
|
103
101
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
102
|
+
if vm_stat_command:
|
|
103
|
+
rc, out, err = self.module.run_command(vm_stat_command)
|
|
104
|
+
if rc == 0:
|
|
105
|
+
# Free = Total - (Wired + active + inactive)
|
|
106
|
+
# Get a generator of tuples from the command output so we can later
|
|
107
|
+
# turn it into a dictionary
|
|
108
|
+
memory_stats = (line.rstrip('.').split(':', 1) for line in out.splitlines())
|
|
109
|
+
|
|
110
|
+
# Strip extra left spaces from the value
|
|
111
|
+
memory_stats = dict((k, v.lstrip()) for k, v in memory_stats)
|
|
112
|
+
|
|
113
|
+
for k, v in memory_stats.items():
|
|
114
|
+
try:
|
|
115
|
+
memory_stats[k] = int(v)
|
|
116
|
+
except ValueError:
|
|
117
|
+
# Most values convert cleanly to integer values but if the field does
|
|
118
|
+
# not convert to an integer, just leave it alone.
|
|
119
|
+
pass
|
|
120
|
+
|
|
121
|
+
if memory_stats.get('Pages wired down'):
|
|
122
|
+
total_used += memory_stats['Pages wired down'] * page_size
|
|
123
|
+
if memory_stats.get('Pages active'):
|
|
124
|
+
total_used += memory_stats['Pages active'] * page_size
|
|
125
|
+
if memory_stats.get('Pages inactive'):
|
|
126
|
+
total_used += memory_stats['Pages inactive'] * page_size
|
|
127
|
+
|
|
128
|
+
memory_facts['memfree_mb'] = memory_facts['memtotal_mb'] - (total_used // 1024 // 1024)
|
|
130
129
|
|
|
131
130
|
return memory_facts
|
|
132
131
|
|
|
133
132
|
def get_uptime_facts(self):
|
|
133
|
+
|
|
134
134
|
# On Darwin, the default format is annoying to parse.
|
|
135
135
|
# Use -b to get the raw value and decode it.
|
|
136
136
|
sysctl_cmd = self.module.get_bin_path('sysctl')
|
|
137
|
+
if not sysctl_cmd:
|
|
138
|
+
return {}
|
|
139
|
+
|
|
137
140
|
cmd = [sysctl_cmd, '-b', 'kern.boottime']
|
|
138
141
|
|
|
139
142
|
# We need to get raw bytes, not UTF-8.
|