ansible-core 2.18.7rc1__py3-none-any.whl → 2.19.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ansible-core might be problematic. Click here for more details.
- ansible/_internal/__init__.py +53 -0
- ansible/_internal/_ansiballz/__init__.py +0 -0
- ansible/_internal/_ansiballz/_builder.py +101 -0
- ansible/_internal/_ansiballz/_wrapper.py +262 -0
- ansible/_internal/_collection_proxy.py +47 -0
- ansible/_internal/_datatag/__init__.py +0 -0
- ansible/_internal/_datatag/_tags.py +130 -0
- ansible/_internal/_datatag/_utils.py +19 -0
- ansible/_internal/_datatag/_wrappers.py +33 -0
- ansible/_internal/_errors/__init__.py +0 -0
- ansible/_internal/_errors/_alarm_timeout.py +66 -0
- ansible/_internal/_errors/_captured.py +123 -0
- ansible/_internal/_errors/_error_factory.py +89 -0
- ansible/_internal/_errors/_error_utils.py +240 -0
- ansible/_internal/_errors/_handler.py +91 -0
- ansible/_internal/_errors/_task_timeout.py +28 -0
- ansible/_internal/_event_formatting.py +127 -0
- ansible/_internal/_json/__init__.py +214 -0
- ansible/_internal/_json/_legacy_encoder.py +34 -0
- ansible/_internal/_json/_profiles/__init__.py +0 -0
- ansible/_internal/_json/_profiles/_cache_persistence.py +57 -0
- ansible/_internal/_json/_profiles/_inventory_legacy.py +40 -0
- ansible/_internal/_json/_profiles/_legacy.py +189 -0
- ansible/_internal/_locking.py +21 -0
- ansible/_internal/_plugins/__init__.py +0 -0
- ansible/_internal/_plugins/_cache.py +57 -0
- ansible/_internal/_ssh/__init__.py +0 -0
- ansible/_internal/_ssh/_agent_launch.py +91 -0
- ansible/_internal/_ssh/_ssh_agent.py +619 -0
- ansible/_internal/_task.py +78 -0
- ansible/_internal/_templating/__init__.py +12 -0
- ansible/_internal/_templating/_access.py +86 -0
- ansible/_internal/_templating/_chain_templar.py +63 -0
- ansible/_internal/_templating/_datatag.py +95 -0
- ansible/_internal/_templating/_engine.py +592 -0
- ansible/_internal/_templating/_errors.py +28 -0
- ansible/_internal/_templating/_jinja_bits.py +1106 -0
- ansible/_internal/_templating/_jinja_common.py +323 -0
- ansible/_internal/_templating/_jinja_patches.py +44 -0
- ansible/_internal/_templating/_jinja_plugins.py +375 -0
- ansible/_internal/_templating/_lazy_containers.py +633 -0
- ansible/_internal/_templating/_marker_behaviors.py +103 -0
- ansible/_internal/_templating/_template_vars.py +72 -0
- ansible/_internal/_templating/_transform.py +70 -0
- ansible/_internal/_templating/_utils.py +108 -0
- ansible/_internal/_testing.py +26 -0
- ansible/_internal/_wrapt.py +1052 -0
- ansible/_internal/_yaml/__init__.py +0 -0
- ansible/_internal/_yaml/_constructor.py +240 -0
- ansible/_internal/_yaml/_dumper.py +70 -0
- ansible/_internal/_yaml/_errors.py +166 -0
- ansible/_internal/_yaml/_loader.py +66 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/README.md +11 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/debug.py +36 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/apply_trust.py +19 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py +27 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/finalize.py +16 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/origin.py +18 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.py +24 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.yml +33 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/tag_names.py +16 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +17 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +49 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.py +21 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.yml +2 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.py +15 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.yml +19 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.py +18 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.yml +19 -0
- ansible/cli/__init__.py +93 -104
- ansible/cli/_ssh_askpass.py +54 -0
- ansible/cli/adhoc.py +20 -10
- ansible/cli/arguments/option_helpers.py +163 -10
- ansible/cli/config.py +43 -68
- ansible/cli/console.py +13 -11
- ansible/cli/doc.py +134 -77
- ansible/cli/galaxy.py +27 -20
- ansible/cli/inventory.py +28 -28
- ansible/cli/playbook.py +4 -12
- ansible/cli/pull.py +6 -3
- ansible/cli/scripts/ansible_connection_cli_stub.py +7 -7
- ansible/cli/vault.py +12 -11
- ansible/compat/__init__.py +2 -2
- ansible/compat/importlib_resources.py +9 -12
- ansible/config/base.yml +218 -133
- ansible/config/manager.py +220 -159
- ansible/constants.py +2 -65
- ansible/errors/__init__.py +350 -256
- ansible/executor/interpreter_discovery.py +28 -149
- ansible/executor/module_common.py +480 -514
- ansible/executor/play_iterator.py +22 -27
- ansible/executor/playbook_executor.py +11 -11
- ansible/executor/powershell/async_watchdog.ps1 +97 -102
- ansible/executor/powershell/async_wrapper.ps1 +204 -153
- ansible/executor/powershell/become_wrapper.ps1 +107 -144
- ansible/executor/powershell/bootstrap_wrapper.ps1 +46 -9
- ansible/executor/powershell/coverage_wrapper.ps1 +91 -135
- ansible/executor/powershell/exec_wrapper.ps1 +675 -196
- ansible/executor/powershell/module_manifest.py +469 -265
- ansible/executor/powershell/module_wrapper.ps1 +195 -186
- ansible/executor/powershell/powershell_expand_user.ps1 +20 -0
- ansible/executor/powershell/powershell_mkdtemp.ps1 +17 -0
- ansible/executor/powershell/psrp_fetch_file.ps1 +41 -0
- ansible/executor/powershell/psrp_put_file.ps1 +122 -0
- ansible/executor/powershell/winrm_fetch_file.ps1 +46 -0
- ansible/executor/powershell/winrm_put_file.ps1 +36 -0
- ansible/executor/process/worker.py +139 -149
- ansible/executor/stats.py +5 -5
- ansible/executor/task_executor.py +270 -297
- ansible/executor/task_queue_manager.py +135 -137
- ansible/executor/task_result.py +182 -79
- ansible/galaxy/__init__.py +2 -2
- ansible/galaxy/api.py +26 -25
- ansible/galaxy/collection/__init__.py +6 -14
- ansible/galaxy/collection/concrete_artifact_manager.py +12 -21
- ansible/galaxy/dependency_resolution/dataclasses.py +14 -4
- ansible/galaxy/dependency_resolution/providers.py +4 -4
- ansible/galaxy/dependency_resolution/reporters.py +81 -0
- ansible/galaxy/role.py +6 -10
- ansible/galaxy/token.py +28 -21
- ansible/inventory/data.py +47 -57
- ansible/inventory/group.py +50 -73
- ansible/inventory/helpers.py +9 -0
- ansible/inventory/host.py +37 -54
- ansible/inventory/manager.py +79 -34
- ansible/keyword_desc.yml +1 -1
- ansible/module_utils/_internal/__init__.py +55 -0
- ansible/module_utils/_internal/_ambient_context.py +58 -0
- ansible/module_utils/_internal/_ansiballz/__init__.py +0 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/__init__.py +0 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/_coverage.py +45 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/_pydevd.py +62 -0
- ansible/module_utils/_internal/_ansiballz/_loader.py +81 -0
- ansible/module_utils/_internal/_ansiballz/_respawn.py +32 -0
- ansible/module_utils/_internal/_ansiballz/_respawn_wrapper.py +23 -0
- ansible/module_utils/_internal/_concurrent/_daemon_threading.py +1 -0
- ansible/module_utils/_internal/_dataclass_validation.py +217 -0
- ansible/module_utils/_internal/_datatag/__init__.py +961 -0
- ansible/module_utils/_internal/_datatag/_tags.py +16 -0
- ansible/module_utils/_internal/_debugging.py +31 -0
- ansible/module_utils/_internal/_deprecator.py +157 -0
- ansible/module_utils/_internal/_errors.py +101 -0
- ansible/module_utils/_internal/_event_utils.py +61 -0
- ansible/module_utils/_internal/_json/__init__.py +63 -0
- ansible/module_utils/_internal/_json/_legacy_encoder.py +26 -0
- ansible/module_utils/_internal/_json/_profiles/__init__.py +428 -0
- ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py +73 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +33 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +37 -0
- ansible/module_utils/_internal/_json/_profiles/_module_modern_c2m.py +35 -0
- ansible/module_utils/_internal/_json/_profiles/_module_modern_m2c.py +33 -0
- ansible/module_utils/_internal/_json/_profiles/_tagless.py +52 -0
- ansible/module_utils/_internal/_messages.py +130 -0
- ansible/module_utils/_internal/_patches/__init__.py +66 -0
- ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +53 -0
- ansible/module_utils/_internal/_patches/_socket_patch.py +34 -0
- ansible/module_utils/_internal/_patches/_sys_intern_patch.py +34 -0
- ansible/module_utils/_internal/_plugin_info.py +38 -0
- ansible/module_utils/_internal/_stack.py +22 -0
- ansible/module_utils/_internal/_testing.py +0 -0
- ansible/module_utils/_internal/_text_utils.py +6 -0
- ansible/module_utils/_internal/_traceback.py +92 -0
- ansible/module_utils/_internal/_validation.py +14 -0
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/api.py +1 -2
- ansible/module_utils/basic.py +303 -202
- ansible/module_utils/common/_utils.py +24 -28
- ansible/module_utils/common/arg_spec.py +8 -3
- ansible/module_utils/common/collections.py +7 -2
- ansible/module_utils/common/dict_transformations.py +2 -2
- ansible/module_utils/common/file.py +2 -2
- ansible/module_utils/common/json.py +90 -84
- ansible/module_utils/common/locale.py +2 -2
- ansible/module_utils/common/parameters.py +27 -24
- ansible/module_utils/common/process.py +2 -3
- ansible/module_utils/common/respawn.py +11 -33
- ansible/module_utils/common/sentinel.py +66 -0
- ansible/module_utils/common/sys_info.py +8 -8
- ansible/module_utils/common/text/converters.py +16 -37
- ansible/module_utils/common/validation.py +35 -24
- ansible/module_utils/common/warnings.py +143 -25
- ansible/module_utils/common/yaml.py +29 -3
- ansible/module_utils/compat/datetime.py +33 -21
- ansible/module_utils/compat/paramiko.py +21 -10
- ansible/module_utils/compat/typing.py +6 -5
- ansible/module_utils/connection.py +10 -13
- ansible/module_utils/csharp/Ansible.Basic.cs +15 -12
- ansible/module_utils/csharp/Ansible.Become.cs +1 -0
- ansible/module_utils/csharp/Ansible.Privilege.cs +2 -2
- ansible/module_utils/csharp/Ansible._Async.cs +517 -0
- ansible/module_utils/datatag.py +49 -0
- ansible/module_utils/distro/__init__.py +2 -2
- ansible/module_utils/facts/ansible_collector.py +4 -5
- ansible/module_utils/facts/collector.py +13 -14
- ansible/module_utils/facts/compat.py +4 -4
- ansible/module_utils/facts/default_collectors.py +1 -1
- ansible/module_utils/facts/hardware/aix.py +34 -0
- ansible/module_utils/facts/hardware/base.py +2 -2
- ansible/module_utils/facts/hardware/darwin.py +1 -3
- ansible/module_utils/facts/hardware/freebsd.py +2 -2
- ansible/module_utils/facts/hardware/linux.py +5 -5
- ansible/module_utils/facts/namespace.py +1 -1
- ansible/module_utils/facts/network/base.py +1 -1
- ansible/module_utils/facts/network/fc_wwn.py +1 -2
- ansible/module_utils/facts/network/iscsi.py +1 -2
- ansible/module_utils/facts/network/nvme.py +1 -2
- ansible/module_utils/facts/other/facter.py +2 -3
- ansible/module_utils/facts/other/ohai.py +2 -3
- ansible/module_utils/facts/sysctl.py +4 -6
- ansible/module_utils/facts/system/apparmor.py +1 -2
- ansible/module_utils/facts/system/caps.py +3 -3
- ansible/module_utils/facts/system/chroot.py +1 -2
- ansible/module_utils/facts/system/cmdline.py +1 -2
- ansible/module_utils/facts/system/date_time.py +5 -3
- ansible/module_utils/facts/system/distribution.py +27 -13
- ansible/module_utils/facts/system/dns.py +1 -1
- ansible/module_utils/facts/system/env.py +1 -2
- ansible/module_utils/facts/system/fips.py +7 -20
- ansible/module_utils/facts/system/loadavg.py +1 -2
- ansible/module_utils/facts/system/local.py +2 -3
- ansible/module_utils/facts/system/lsb.py +1 -2
- ansible/module_utils/facts/system/pkg_mgr.py +1 -2
- ansible/module_utils/facts/system/platform.py +1 -2
- ansible/module_utils/facts/system/python.py +1 -2
- ansible/module_utils/facts/system/selinux.py +1 -1
- ansible/module_utils/facts/system/service_mgr.py +1 -2
- ansible/module_utils/facts/system/ssh_pub_keys.py +1 -1
- ansible/module_utils/facts/system/systemd.py +1 -1
- ansible/module_utils/facts/system/user.py +1 -2
- ansible/module_utils/facts/utils.py +3 -3
- ansible/module_utils/facts/virtual/base.py +1 -1
- ansible/module_utils/facts/virtual/linux.py +3 -3
- ansible/module_utils/facts/virtual/sunos.py +3 -15
- ansible/module_utils/facts/virtual/sysctl.py +3 -16
- ansible/module_utils/json_utils.py +2 -2
- ansible/module_utils/parsing/convert_bool.py +7 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.CommandUtil.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.WebRequest.psm1 +1 -1
- ansible/module_utils/service.py +21 -31
- ansible/module_utils/splitter.py +7 -7
- ansible/module_utils/testing.py +31 -0
- ansible/module_utils/urls.py +64 -35
- ansible/modules/add_host.py +4 -4
- ansible/modules/apt.py +69 -49
- ansible/modules/apt_key.py +19 -12
- ansible/modules/apt_repository.py +32 -51
- ansible/modules/assemble.py +16 -14
- ansible/modules/assert.py +4 -4
- ansible/modules/async_status.py +24 -24
- ansible/modules/async_wrapper.py +20 -25
- ansible/modules/blockinfile.py +6 -7
- ansible/modules/command.py +13 -20
- ansible/modules/copy.py +60 -147
- ansible/modules/cron.py +24 -21
- ansible/modules/deb822_repository.py +8 -9
- ansible/modules/debconf.py +5 -5
- ansible/modules/debug.py +4 -4
- ansible/modules/dnf.py +8 -8
- ansible/modules/dnf5.py +39 -13
- ansible/modules/dpkg_selections.py +4 -4
- ansible/modules/expect.py +13 -15
- ansible/modules/fail.py +4 -4
- ansible/modules/fetch.py +4 -4
- ansible/modules/file.py +184 -144
- ansible/modules/find.py +22 -20
- ansible/modules/gather_facts.py +3 -3
- ansible/modules/get_url.py +77 -54
- ansible/modules/getent.py +7 -9
- ansible/modules/git.py +38 -38
- ansible/modules/group.py +6 -6
- ansible/modules/group_by.py +4 -4
- ansible/modules/hostname.py +15 -32
- ansible/modules/import_playbook.py +6 -6
- ansible/modules/import_role.py +6 -6
- ansible/modules/import_tasks.py +6 -6
- ansible/modules/include_role.py +6 -6
- ansible/modules/include_tasks.py +6 -6
- ansible/modules/include_vars.py +6 -6
- ansible/modules/iptables.py +86 -73
- ansible/modules/known_hosts.py +22 -24
- ansible/modules/lineinfile.py +5 -5
- ansible/modules/meta.py +4 -4
- ansible/modules/mount_facts.py +2 -2
- ansible/modules/package.py +10 -4
- ansible/modules/package_facts.py +22 -10
- ansible/modules/pause.py +6 -6
- ansible/modules/ping.py +6 -6
- ansible/modules/pip.py +21 -26
- ansible/modules/raw.py +6 -6
- ansible/modules/reboot.py +6 -6
- ansible/modules/replace.py +10 -14
- ansible/modules/rpm_key.py +7 -8
- ansible/modules/script.py +4 -4
- ansible/modules/service.py +10 -17
- ansible/modules/service_facts.py +87 -10
- ansible/modules/set_fact.py +5 -5
- ansible/modules/set_stats.py +4 -4
- ansible/modules/setup.py +2 -2
- ansible/modules/shell.py +6 -6
- ansible/modules/slurp.py +16 -19
- ansible/modules/stat.py +15 -31
- ansible/modules/subversion.py +15 -15
- ansible/modules/systemd.py +7 -7
- ansible/modules/systemd_service.py +7 -7
- ansible/modules/sysvinit.py +9 -9
- ansible/modules/tempfile.py +5 -6
- ansible/modules/template.py +6 -6
- ansible/modules/unarchive.py +38 -17
- ansible/modules/uri.py +33 -26
- ansible/modules/user.py +45 -32
- ansible/modules/validate_argument_spec.py +10 -7
- ansible/modules/wait_for.py +70 -60
- ansible/modules/wait_for_connection.py +6 -6
- ansible/modules/yum_repository.py +10 -9
- ansible/parsing/ajson.py +17 -37
- ansible/parsing/dataloader.py +99 -54
- ansible/parsing/mod_args.py +62 -60
- ansible/parsing/plugin_docs.py +21 -86
- ansible/parsing/quoting.py +1 -1
- ansible/parsing/splitter.py +27 -12
- ansible/parsing/utils/addresses.py +24 -24
- ansible/parsing/utils/jsonify.py +5 -1
- ansible/parsing/utils/yaml.py +32 -61
- ansible/parsing/vault/__init__.py +327 -99
- ansible/parsing/yaml/__init__.py +0 -18
- ansible/parsing/yaml/dumper.py +6 -120
- ansible/parsing/yaml/loader.py +6 -39
- ansible/parsing/yaml/objects.py +43 -335
- ansible/playbook/__init__.py +1 -1
- ansible/playbook/attribute.py +8 -3
- ansible/playbook/base.py +187 -134
- ansible/playbook/block.py +26 -24
- ansible/playbook/collectionsearch.py +1 -15
- ansible/playbook/conditional.py +3 -77
- ansible/playbook/handler.py +8 -2
- ansible/playbook/helpers.py +41 -53
- ansible/playbook/included_file.py +32 -26
- ansible/playbook/loop_control.py +2 -2
- ansible/playbook/play.py +85 -44
- ansible/playbook/play_context.py +14 -17
- ansible/playbook/playbook_include.py +27 -62
- ansible/playbook/role/__init__.py +64 -49
- ansible/playbook/role/definition.py +15 -17
- ansible/playbook/role/include.py +2 -4
- ansible/playbook/role/metadata.py +10 -11
- ansible/playbook/role_include.py +3 -3
- ansible/playbook/taggable.py +28 -12
- ansible/playbook/task.py +192 -121
- ansible/playbook/task_include.py +5 -5
- ansible/plugins/__init__.py +58 -26
- ansible/plugins/action/__init__.py +188 -186
- ansible/plugins/action/add_host.py +2 -2
- ansible/plugins/action/assemble.py +11 -18
- ansible/plugins/action/assert.py +55 -67
- ansible/plugins/action/async_status.py +7 -2
- ansible/plugins/action/copy.py +14 -17
- ansible/plugins/action/debug.py +37 -31
- ansible/plugins/action/dnf.py +3 -4
- ansible/plugins/action/fail.py +1 -1
- ansible/plugins/action/fetch.py +7 -8
- ansible/plugins/action/gather_facts.py +13 -14
- ansible/plugins/action/group_by.py +1 -1
- ansible/plugins/action/include_vars.py +10 -11
- ansible/plugins/action/package.py +8 -14
- ansible/plugins/action/pause.py +2 -2
- ansible/plugins/action/script.py +27 -38
- ansible/plugins/action/service.py +9 -18
- ansible/plugins/action/set_fact.py +3 -12
- ansible/plugins/action/set_stats.py +3 -8
- ansible/plugins/action/template.py +47 -67
- ansible/plugins/action/unarchive.py +6 -16
- ansible/plugins/action/uri.py +9 -20
- ansible/plugins/action/validate_argument_spec.py +5 -5
- ansible/plugins/action/wait_for_connection.py +1 -1
- ansible/plugins/become/__init__.py +31 -8
- ansible/plugins/become/runas.py +71 -0
- ansible/plugins/become/su.py +13 -8
- ansible/plugins/become/sudo.py +19 -0
- ansible/plugins/cache/__init__.py +52 -63
- ansible/plugins/cache/base.py +8 -0
- ansible/plugins/cache/jsonfile.py +10 -16
- ansible/plugins/cache/memory.py +6 -12
- ansible/plugins/callback/__init__.py +294 -201
- ansible/plugins/callback/default.py +99 -95
- ansible/plugins/callback/junit.py +44 -43
- ansible/plugins/callback/minimal.py +28 -25
- ansible/plugins/callback/oneline.py +34 -21
- ansible/plugins/callback/tree.py +27 -16
- ansible/plugins/connection/__init__.py +47 -34
- ansible/plugins/connection/local.py +156 -60
- ansible/plugins/connection/paramiko_ssh.py +34 -24
- ansible/plugins/connection/psrp.py +76 -165
- ansible/plugins/connection/ssh.py +326 -86
- ansible/plugins/connection/winrm.py +62 -141
- ansible/plugins/doc_fragments/action_common_attributes.py +14 -14
- ansible/plugins/doc_fragments/action_core.py +6 -6
- ansible/plugins/doc_fragments/backup.py +2 -2
- ansible/plugins/doc_fragments/checksum_common.py +27 -0
- ansible/plugins/doc_fragments/constructed.py +8 -4
- ansible/plugins/doc_fragments/decrypt.py +2 -2
- ansible/plugins/doc_fragments/default_callback.py +2 -2
- ansible/plugins/doc_fragments/files.py +2 -2
- ansible/plugins/doc_fragments/inventory_cache.py +2 -2
- ansible/plugins/doc_fragments/result_format_callback.py +2 -2
- ansible/plugins/doc_fragments/return_common.py +2 -2
- ansible/plugins/doc_fragments/template_common.py +4 -4
- ansible/plugins/doc_fragments/url.py +17 -1
- ansible/plugins/doc_fragments/url_windows.py +2 -2
- ansible/plugins/doc_fragments/validate.py +2 -2
- ansible/plugins/doc_fragments/vars_plugin_staging.py +2 -2
- ansible/plugins/filter/__init__.py +6 -2
- ansible/plugins/filter/b64decode.yml +22 -0
- ansible/plugins/filter/b64encode.yml +22 -0
- ansible/plugins/filter/bool.yml +11 -4
- ansible/plugins/filter/core.py +245 -120
- ansible/plugins/filter/encryption.py +42 -34
- ansible/plugins/filter/flatten.yml +3 -2
- ansible/plugins/filter/human_to_bytes.yml +1 -1
- ansible/plugins/filter/mathstuff.py +30 -37
- ansible/plugins/filter/password_hash.yml +8 -0
- ansible/plugins/filter/pow.yml +1 -1
- ansible/plugins/filter/regex_search.yml +1 -4
- ansible/plugins/filter/root.yml +1 -1
- ansible/plugins/filter/split.yml +1 -1
- ansible/plugins/filter/strftime.yml +3 -3
- ansible/plugins/filter/to_nice_yaml.yml +0 -4
- ansible/plugins/filter/to_uuid.yml +1 -1
- ansible/plugins/filter/to_yaml.yml +0 -4
- ansible/plugins/filter/unvault.yml +1 -1
- ansible/plugins/filter/urls.py +1 -1
- ansible/plugins/filter/urlsplit.py +8 -9
- ansible/plugins/filter/vault.yml +14 -9
- ansible/plugins/filter/win_basename.yml +6 -1
- ansible/plugins/filter/win_dirname.yml +5 -0
- ansible/plugins/inventory/__init__.py +107 -86
- ansible/plugins/inventory/advanced_host_list.py +7 -5
- ansible/plugins/inventory/auto.py +11 -4
- ansible/plugins/inventory/constructed.py +21 -24
- ansible/plugins/inventory/generator.py +16 -11
- ansible/plugins/inventory/host_list.py +7 -5
- ansible/plugins/inventory/ini.py +78 -44
- ansible/plugins/inventory/script.py +190 -120
- ansible/plugins/inventory/toml.py +16 -126
- ansible/plugins/inventory/yaml.py +10 -8
- ansible/plugins/list.py +72 -19
- ansible/plugins/loader.py +383 -198
- ansible/plugins/lookup/__init__.py +21 -4
- ansible/plugins/lookup/config.py +21 -35
- ansible/plugins/lookup/csvfile.py +19 -73
- ansible/plugins/lookup/dict.py +1 -6
- ansible/plugins/lookup/env.py +12 -9
- ansible/plugins/lookup/file.py +5 -8
- ansible/plugins/lookup/first_found.py +87 -55
- ansible/plugins/lookup/indexed_items.py +1 -10
- ansible/plugins/lookup/ini.py +14 -13
- ansible/plugins/lookup/items.py +1 -1
- ansible/plugins/lookup/lines.py +8 -1
- ansible/plugins/lookup/list.py +1 -1
- ansible/plugins/lookup/nested.py +2 -18
- ansible/plugins/lookup/password.py +5 -5
- ansible/plugins/lookup/pipe.py +5 -7
- ansible/plugins/lookup/sequence.py +18 -8
- ansible/plugins/lookup/subelements.py +1 -4
- ansible/plugins/lookup/template.py +47 -36
- ansible/plugins/lookup/together.py +0 -12
- ansible/plugins/lookup/unvault.py +1 -5
- ansible/plugins/lookup/url.py +4 -10
- ansible/plugins/lookup/vars.py +16 -24
- ansible/plugins/shell/__init__.py +58 -4
- ansible/plugins/shell/cmd.py +2 -2
- ansible/plugins/shell/powershell.py +106 -31
- ansible/plugins/shell/sh.py +13 -7
- ansible/plugins/strategy/__init__.py +168 -193
- ansible/plugins/strategy/debug.py +2 -2
- ansible/plugins/strategy/free.py +16 -31
- ansible/plugins/strategy/host_pinned.py +2 -2
- ansible/plugins/strategy/linear.py +41 -41
- ansible/plugins/terminal/__init__.py +4 -4
- ansible/plugins/test/__init__.py +7 -2
- ansible/plugins/test/core.py +75 -35
- ansible/plugins/test/files.py +1 -1
- ansible/plugins/test/finished.yml +1 -1
- ansible/plugins/test/mathstuff.py +3 -3
- ansible/plugins/test/uri.py +5 -8
- ansible/plugins/vars/host_group_vars.py +7 -14
- ansible/release.py +2 -2
- ansible/template/__init__.py +353 -943
- ansible/utils/__init__.py +0 -18
- ansible/utils/collection_loader/__init__.py +54 -5
- ansible/utils/collection_loader/_collection_config.py +5 -6
- ansible/utils/collection_loader/_collection_finder.py +82 -96
- ansible/utils/collection_loader/_collection_meta.py +15 -8
- ansible/utils/display.py +485 -73
- ansible/utils/encrypt.py +27 -19
- ansible/utils/fqcn.py +2 -2
- ansible/utils/galaxy.py +2 -2
- ansible/utils/hashing.py +8 -10
- ansible/utils/helpers.py +2 -2
- ansible/utils/listify.py +10 -8
- ansible/utils/lock.py +2 -2
- ansible/utils/path.py +10 -12
- ansible/utils/plugin_docs.py +16 -14
- ansible/utils/py3compat.py +2 -7
- ansible/utils/sentinel.py +4 -62
- ansible/utils/singleton.py +2 -0
- ansible/utils/ssh_functions.py +6 -2
- ansible/utils/unsafe_proxy.py +23 -332
- ansible/utils/vars.py +55 -8
- ansible/utils/version.py +2 -2
- ansible/vars/clean.py +5 -5
- ansible/vars/hostvars.py +60 -90
- ansible/vars/manager.py +220 -285
- ansible/vars/plugins.py +4 -4
- ansible/vars/reserved.py +13 -12
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/METADATA +4 -3
- ansible_core-2.19.0.dist-info/RECORD +1097 -0
- ansible_core-2.19.0.dist-info/licenses/licenses/BSD-3-Clause.txt +28 -0
- ansible_test/_data/completion/docker.txt +7 -7
- ansible_test/_data/completion/remote.txt +6 -6
- ansible_test/_data/completion/windows.txt +1 -0
- ansible_test/_data/requirements/ansible.txt +2 -2
- ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
- ansible_test/_data/requirements/sanity.changelog.txt +2 -2
- ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
- ansible_test/_data/requirements/sanity.pep8.txt +1 -1
- ansible_test/_data/requirements/sanity.pylint.txt +5 -5
- ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
- ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
- ansible_test/_data/requirements/units.txt +1 -0
- ansible_test/_internal/__init__.py +6 -0
- ansible_test/_internal/ansible_util.py +3 -1
- ansible_test/_internal/become.py +1 -0
- ansible_test/_internal/bootstrap.py +1 -0
- ansible_test/_internal/cache.py +1 -0
- ansible_test/_internal/cgroup.py +1 -0
- ansible_test/_internal/ci/__init__.py +1 -0
- ansible_test/_internal/ci/azp.py +1 -0
- ansible_test/_internal/ci/local.py +1 -0
- ansible_test/_internal/classification/__init__.py +1 -0
- ansible_test/_internal/classification/common.py +1 -0
- ansible_test/_internal/classification/csharp.py +1 -0
- ansible_test/_internal/classification/powershell.py +1 -0
- ansible_test/_internal/classification/python.py +1 -0
- ansible_test/_internal/cli/__init__.py +1 -0
- ansible_test/_internal/cli/actions.py +1 -0
- ansible_test/_internal/cli/argparsing/__init__.py +1 -0
- ansible_test/_internal/cli/argparsing/actions.py +1 -0
- ansible_test/_internal/cli/argparsing/argcompletion.py +1 -0
- ansible_test/_internal/cli/argparsing/parsers.py +1 -0
- ansible_test/_internal/cli/commands/__init__.py +11 -5
- ansible_test/_internal/cli/commands/coverage/__init__.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/__init__.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/__init__.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/combine.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/expand.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/filter.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/generate.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/missing.py +1 -0
- ansible_test/_internal/cli/commands/coverage/combine.py +1 -0
- ansible_test/_internal/cli/commands/coverage/erase.py +1 -0
- ansible_test/_internal/cli/commands/coverage/html.py +1 -0
- ansible_test/_internal/cli/commands/coverage/report.py +1 -0
- ansible_test/_internal/cli/commands/coverage/xml.py +1 -0
- ansible_test/_internal/cli/commands/env.py +1 -0
- ansible_test/_internal/cli/commands/integration/__init__.py +1 -0
- ansible_test/_internal/cli/commands/integration/network.py +1 -0
- ansible_test/_internal/cli/commands/integration/posix.py +1 -0
- ansible_test/_internal/cli/commands/integration/windows.py +1 -0
- ansible_test/_internal/cli/commands/sanity.py +9 -0
- ansible_test/_internal/cli/commands/shell.py +1 -0
- ansible_test/_internal/cli/commands/units.py +1 -0
- ansible_test/_internal/cli/compat.py +1 -0
- ansible_test/_internal/cli/completers.py +1 -0
- ansible_test/_internal/cli/converters.py +1 -0
- ansible_test/_internal/cli/environments.py +52 -5
- ansible_test/_internal/cli/epilog.py +1 -0
- ansible_test/_internal/cli/parsers/__init__.py +1 -0
- ansible_test/_internal/cli/parsers/base_argument_parsers.py +1 -0
- ansible_test/_internal/cli/parsers/helpers.py +1 -0
- ansible_test/_internal/cli/parsers/host_config_parsers.py +1 -0
- ansible_test/_internal/cli/parsers/key_value_parsers.py +1 -0
- ansible_test/_internal/cli/parsers/value_parsers.py +1 -0
- ansible_test/_internal/commands/__init__.py +1 -0
- ansible_test/_internal/commands/coverage/__init__.py +3 -2
- ansible_test/_internal/commands/coverage/analyze/__init__.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/__init__.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/combine.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/expand.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/filter.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/generate.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/missing.py +1 -0
- ansible_test/_internal/commands/coverage/combine.py +2 -1
- ansible_test/_internal/commands/coverage/erase.py +1 -0
- ansible_test/_internal/commands/coverage/html.py +1 -0
- ansible_test/_internal/commands/coverage/report.py +1 -0
- ansible_test/_internal/commands/coverage/xml.py +1 -0
- ansible_test/_internal/commands/env/__init__.py +2 -0
- ansible_test/_internal/commands/integration/__init__.py +22 -5
- ansible_test/_internal/commands/integration/cloud/__init__.py +1 -0
- ansible_test/_internal/commands/integration/cloud/acme.py +2 -1
- ansible_test/_internal/commands/integration/cloud/aws.py +1 -0
- ansible_test/_internal/commands/integration/cloud/azure.py +1 -0
- ansible_test/_internal/commands/integration/cloud/cs.py +1 -0
- ansible_test/_internal/commands/integration/cloud/digitalocean.py +1 -0
- ansible_test/_internal/commands/integration/cloud/galaxy.py +3 -2
- ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -0
- ansible_test/_internal/commands/integration/cloud/httptester.py +3 -2
- ansible_test/_internal/commands/integration/cloud/nios.py +2 -1
- ansible_test/_internal/commands/integration/cloud/opennebula.py +1 -0
- ansible_test/_internal/commands/integration/cloud/openshift.py +1 -0
- ansible_test/_internal/commands/integration/cloud/scaleway.py +1 -0
- ansible_test/_internal/commands/integration/cloud/vcenter.py +1 -0
- ansible_test/_internal/commands/integration/cloud/vultr.py +1 -0
- ansible_test/_internal/commands/integration/coverage.py +8 -2
- ansible_test/_internal/commands/integration/filters.py +1 -0
- ansible_test/_internal/commands/integration/network.py +1 -0
- ansible_test/_internal/commands/integration/posix.py +1 -0
- ansible_test/_internal/commands/integration/windows.py +1 -0
- ansible_test/_internal/commands/sanity/__init__.py +19 -2
- ansible_test/_internal/commands/sanity/ansible_doc.py +1 -0
- ansible_test/_internal/commands/sanity/bin_symlinks.py +1 -0
- ansible_test/_internal/commands/sanity/compile.py +1 -0
- ansible_test/_internal/commands/sanity/ignores.py +1 -0
- ansible_test/_internal/commands/sanity/import.py +1 -0
- ansible_test/_internal/commands/sanity/integration_aliases.py +12 -0
- ansible_test/_internal/commands/sanity/pep8.py +1 -0
- ansible_test/_internal/commands/sanity/pslint.py +1 -0
- ansible_test/_internal/commands/sanity/pylint.py +25 -26
- ansible_test/_internal/commands/sanity/shellcheck.py +1 -0
- ansible_test/_internal/commands/sanity/validate_modules.py +1 -0
- ansible_test/_internal/commands/sanity/yamllint.py +1 -0
- ansible_test/_internal/commands/shell/__init__.py +44 -4
- ansible_test/_internal/commands/units/__init__.py +5 -1
- ansible_test/_internal/compat/__init__.py +1 -0
- ansible_test/_internal/compat/packaging.py +1 -0
- ansible_test/_internal/compat/yaml.py +1 -0
- ansible_test/_internal/completion.py +1 -0
- ansible_test/_internal/config.py +23 -13
- ansible_test/_internal/connections.py +1 -0
- ansible_test/_internal/constants.py +1 -0
- ansible_test/_internal/containers.py +1 -0
- ansible_test/_internal/content_config.py +1 -0
- ansible_test/_internal/core_ci.py +1 -0
- ansible_test/_internal/coverage_util.py +11 -10
- ansible_test/_internal/data.py +1 -0
- ansible_test/_internal/debugging.py +166 -0
- ansible_test/_internal/delegation.py +22 -13
- ansible_test/_internal/dev/__init__.py +1 -0
- ansible_test/_internal/dev/container_probe.py +1 -0
- ansible_test/_internal/diff.py +3 -2
- ansible_test/_internal/docker_util.py +2 -1
- ansible_test/_internal/encoding.py +1 -0
- ansible_test/_internal/executor.py +1 -0
- ansible_test/_internal/git.py +1 -0
- ansible_test/_internal/host_configs.py +1 -0
- ansible_test/_internal/host_profiles.py +260 -16
- ansible_test/_internal/http.py +1 -0
- ansible_test/_internal/init.py +1 -0
- ansible_test/_internal/inventory.py +39 -3
- ansible_test/_internal/io.py +1 -0
- ansible_test/_internal/metadata.py +95 -4
- ansible_test/_internal/payload.py +1 -0
- ansible_test/_internal/processes.py +80 -0
- ansible_test/_internal/provider/__init__.py +1 -0
- ansible_test/_internal/provider/layout/__init__.py +1 -0
- ansible_test/_internal/provider/layout/ansible.py +1 -0
- ansible_test/_internal/provider/layout/collection.py +1 -0
- ansible_test/_internal/provider/layout/unsupported.py +1 -0
- ansible_test/_internal/provider/source/__init__.py +1 -0
- ansible_test/_internal/provider/source/git.py +1 -0
- ansible_test/_internal/provider/source/installed.py +1 -0
- ansible_test/_internal/provider/source/unsupported.py +1 -0
- ansible_test/_internal/provider/source/unversioned.py +1 -0
- ansible_test/_internal/provisioning.py +11 -4
- ansible_test/_internal/pypi_proxy.py +6 -5
- ansible_test/_internal/python_requirements.py +28 -0
- ansible_test/_internal/ssh.py +2 -5
- ansible_test/_internal/target.py +9 -0
- ansible_test/_internal/test.py +3 -2
- ansible_test/_internal/thread.py +3 -1
- ansible_test/_internal/timeout.py +2 -1
- ansible_test/_internal/util.py +41 -12
- ansible_test/_internal/util_common.py +18 -5
- ansible_test/_internal/venv.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/changelog/sphinx.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/changelog.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/empty-init.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/line-endings.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-assert.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-get-exception.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-illegal-filenames.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-smart-quotes.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/replace-urlopen.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +28 -1
- ansible_test/_util/controller/sanity/code-smell/shebang.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/symlinks.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/use-argspec-type-path.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/use-compat-six.py +1 -0
- ansible_test/_util/controller/sanity/integration-aliases/yaml_to_json.py +2 -1
- ansible_test/_util/controller/sanity/pep8/current-ignore.txt +4 -0
- ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +8 -5
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +8 -5
- ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +8 -5
- ansible_test/_util/controller/sanity/pylint/config/collection.cfg +4 -5
- ansible_test/_util/controller/sanity/pylint/config/default.cfg +8 -7
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +541 -0
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_comment.py +137 -0
- ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +1 -0
- ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +1 -8
- ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +1 -8
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +55 -28
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +12 -5
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +13 -2
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -0
- ansible_test/_util/controller/sanity/yamllint/yamllinter.py +35 -17
- ansible_test/_util/controller/tools/collection_detail.py +1 -0
- ansible_test/_util/controller/tools/yaml_to_json.py +2 -1
- ansible_test/_util/target/injector/python.py +8 -0
- ansible_test/_util/target/pytest/plugins/ansible_forked.py +6 -1
- ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py +2 -1
- ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +1 -0
- ansible_test/_util/target/sanity/compile/compile.py +1 -0
- ansible_test/_util/target/sanity/import/importer.py +15 -16
- ansible_test/_util/target/setup/bootstrap.sh +9 -20
- ansible_test/_util/target/setup/probe_cgroups.py +1 -0
- ansible_test/_util/target/setup/quiet_pip.py +1 -0
- ansible_test/_util/target/setup/requirements.py +38 -36
- ansible_test/_util/target/tools/virtualenvcheck.py +2 -1
- ansible_test/_util/target/tools/yamlcheck.py +2 -1
- ansible/compat/selectors.py +0 -32
- ansible/errors/yaml_strings.py +0 -138
- ansible/executor/action_write_locks.py +0 -44
- ansible/executor/discovery/python_target.py +0 -47
- ansible/executor/powershell/module_powershell_wrapper.ps1 +0 -86
- ansible/executor/powershell/module_script_wrapper.ps1 +0 -22
- ansible/module_utils/compat/importlib.py +0 -26
- ansible/module_utils/compat/selectors.py +0 -32
- ansible/module_utils/pycompat24.py +0 -73
- ansible/parsing/yaml/constructor.py +0 -178
- ansible/template/native_helpers.py +0 -251
- ansible/template/template.py +0 -43
- ansible/template/vars.py +0 -77
- ansible/utils/native_jinja.py +0 -11
- ansible/vars/fact_cache.py +0 -71
- ansible_core-2.18.7rc1.dist-info/RECORD +0 -992
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +0 -411
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/WHEEL +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/top_level.txt +0 -0
ansible/inventory/group.py
CHANGED
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
|
+
import typing as t
|
|
20
|
+
|
|
19
21
|
from collections.abc import Mapping, MutableMapping
|
|
20
22
|
from enum import Enum
|
|
21
23
|
from itertools import chain
|
|
@@ -24,10 +26,15 @@ from ansible import constants as C
|
|
|
24
26
|
from ansible.errors import AnsibleError
|
|
25
27
|
from ansible.module_utils.common.text.converters import to_native, to_text
|
|
26
28
|
from ansible.utils.display import Display
|
|
27
|
-
from ansible.utils.vars import combine_vars
|
|
29
|
+
from ansible.utils.vars import combine_vars, validate_variable_name
|
|
30
|
+
|
|
31
|
+
from . import helpers # this is left as a module import to facilitate easier unit test patching
|
|
28
32
|
|
|
29
33
|
display = Display()
|
|
30
34
|
|
|
35
|
+
if t.TYPE_CHECKING:
|
|
36
|
+
from .host import Host
|
|
37
|
+
|
|
31
38
|
|
|
32
39
|
def to_safe_group_name(name, replacer="_", force=False, silent=False):
|
|
33
40
|
# Converts 'bad' characters in a string to underscores (or provided replacer) so they can be used as Ansible hosts or groups
|
|
@@ -59,22 +66,23 @@ class InventoryObjectType(Enum):
|
|
|
59
66
|
|
|
60
67
|
|
|
61
68
|
class Group:
|
|
62
|
-
|
|
69
|
+
"""A group of ansible hosts."""
|
|
63
70
|
base_type = InventoryObjectType.GROUP
|
|
64
71
|
|
|
65
72
|
# __slots__ = [ 'name', 'hosts', 'vars', 'child_groups', 'parent_groups', 'depth', '_hosts_cache' ]
|
|
66
73
|
|
|
67
|
-
def __init__(self, name
|
|
74
|
+
def __init__(self, name: str) -> None:
|
|
75
|
+
name = helpers.remove_trust(name)
|
|
68
76
|
|
|
69
|
-
self.depth = 0
|
|
70
|
-
self.name = to_safe_group_name(name)
|
|
71
|
-
self.hosts = []
|
|
72
|
-
self._hosts = None
|
|
73
|
-
self.vars = {}
|
|
74
|
-
self.child_groups = []
|
|
75
|
-
self.parent_groups = []
|
|
76
|
-
self._hosts_cache = None
|
|
77
|
-
self.priority = 1
|
|
77
|
+
self.depth: int = 0
|
|
78
|
+
self.name: str = to_safe_group_name(name)
|
|
79
|
+
self.hosts: list[Host] = []
|
|
80
|
+
self._hosts: set[str] | None = None
|
|
81
|
+
self.vars: dict[str, t.Any] = {}
|
|
82
|
+
self.child_groups: list[Group] = []
|
|
83
|
+
self.parent_groups: list[Group] = []
|
|
84
|
+
self._hosts_cache: list[Host] | None = None
|
|
85
|
+
self.priority: int = 1
|
|
78
86
|
|
|
79
87
|
def __repr__(self):
|
|
80
88
|
return self.get_name()
|
|
@@ -82,45 +90,8 @@ class Group:
|
|
|
82
90
|
def __str__(self):
|
|
83
91
|
return self.get_name()
|
|
84
92
|
|
|
85
|
-
def
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
def __setstate__(self, data):
|
|
89
|
-
return self.deserialize(data)
|
|
90
|
-
|
|
91
|
-
def serialize(self):
|
|
92
|
-
parent_groups = []
|
|
93
|
-
for parent in self.parent_groups:
|
|
94
|
-
parent_groups.append(parent.serialize())
|
|
95
|
-
|
|
96
|
-
self._hosts = None
|
|
97
|
-
|
|
98
|
-
result = dict(
|
|
99
|
-
name=self.name,
|
|
100
|
-
vars=self.vars.copy(),
|
|
101
|
-
parent_groups=parent_groups,
|
|
102
|
-
depth=self.depth,
|
|
103
|
-
hosts=self.hosts,
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
return result
|
|
107
|
-
|
|
108
|
-
def deserialize(self, data):
|
|
109
|
-
self.__init__() # used by __setstate__ to deserialize in place # pylint: disable=unnecessary-dunder-call
|
|
110
|
-
self.name = data.get('name')
|
|
111
|
-
self.vars = data.get('vars', dict())
|
|
112
|
-
self.depth = data.get('depth', 0)
|
|
113
|
-
self.hosts = data.get('hosts', [])
|
|
114
|
-
self._hosts = None
|
|
115
|
-
|
|
116
|
-
parent_groups = data.get('parent_groups', [])
|
|
117
|
-
for parent_data in parent_groups:
|
|
118
|
-
g = Group()
|
|
119
|
-
g.deserialize(parent_data)
|
|
120
|
-
self.parent_groups.append(g)
|
|
121
|
-
|
|
122
|
-
def _walk_relationship(self, rel, include_self=False, preserve_ordering=False):
|
|
123
|
-
'''
|
|
93
|
+
def _walk_relationship(self, rel, include_self=False, preserve_ordering=False) -> set[Group] | list[Group]:
|
|
94
|
+
"""
|
|
124
95
|
Given `rel` that is an iterable property of Group,
|
|
125
96
|
consitituting a directed acyclic graph among all groups,
|
|
126
97
|
Returns a set of all groups in full tree
|
|
@@ -132,13 +103,13 @@ class Group:
|
|
|
132
103
|
| / are directed upward
|
|
133
104
|
F
|
|
134
105
|
Called on F, returns set of (A, B, C, D, E)
|
|
135
|
-
|
|
136
|
-
seen = set([])
|
|
106
|
+
"""
|
|
107
|
+
seen: set[Group] = set([])
|
|
137
108
|
unprocessed = set(getattr(self, rel))
|
|
138
109
|
if include_self:
|
|
139
110
|
unprocessed.add(self)
|
|
140
111
|
if preserve_ordering:
|
|
141
|
-
ordered = [self] if include_self else []
|
|
112
|
+
ordered: list[Group] = [self] if include_self else []
|
|
142
113
|
ordered.extend(getattr(self, rel))
|
|
143
114
|
|
|
144
115
|
while unprocessed:
|
|
@@ -158,22 +129,22 @@ class Group:
|
|
|
158
129
|
return ordered
|
|
159
130
|
return seen
|
|
160
131
|
|
|
161
|
-
def get_ancestors(self):
|
|
162
|
-
return self._walk_relationship('parent_groups')
|
|
132
|
+
def get_ancestors(self) -> set[Group]:
|
|
133
|
+
return t.cast(set, self._walk_relationship('parent_groups'))
|
|
163
134
|
|
|
164
|
-
def get_descendants(self, **kwargs):
|
|
135
|
+
def get_descendants(self, **kwargs) -> set[Group] | list[Group]:
|
|
165
136
|
return self._walk_relationship('child_groups', **kwargs)
|
|
166
137
|
|
|
167
138
|
@property
|
|
168
|
-
def host_names(self):
|
|
139
|
+
def host_names(self) -> set[str]:
|
|
169
140
|
if self._hosts is None:
|
|
170
|
-
self._hosts =
|
|
141
|
+
self._hosts = {h.name for h in self.hosts}
|
|
171
142
|
return self._hosts
|
|
172
143
|
|
|
173
|
-
def get_name(self):
|
|
144
|
+
def get_name(self) -> str:
|
|
174
145
|
return self.name
|
|
175
146
|
|
|
176
|
-
def add_child_group(self, group):
|
|
147
|
+
def add_child_group(self, group: Group) -> bool:
|
|
177
148
|
added = False
|
|
178
149
|
if self == group:
|
|
179
150
|
raise Exception("can't add group to itself")
|
|
@@ -208,7 +179,7 @@ class Group:
|
|
|
208
179
|
self.clear_hosts_cache()
|
|
209
180
|
return added
|
|
210
181
|
|
|
211
|
-
def _check_children_depth(self):
|
|
182
|
+
def _check_children_depth(self) -> None:
|
|
212
183
|
|
|
213
184
|
depth = self.depth
|
|
214
185
|
start_depth = self.depth # self.depth could change over loop
|
|
@@ -227,7 +198,7 @@ class Group:
|
|
|
227
198
|
if depth - start_depth > len(seen):
|
|
228
199
|
raise AnsibleError("The group named '%s' has a recursive dependency loop." % to_native(self.name))
|
|
229
200
|
|
|
230
|
-
def add_host(self, host):
|
|
201
|
+
def add_host(self, host: Host) -> bool:
|
|
231
202
|
added = False
|
|
232
203
|
if host.name not in self.host_names:
|
|
233
204
|
self.hosts.append(host)
|
|
@@ -237,7 +208,7 @@ class Group:
|
|
|
237
208
|
added = True
|
|
238
209
|
return added
|
|
239
210
|
|
|
240
|
-
def remove_host(self, host):
|
|
211
|
+
def remove_host(self, host: Host) -> bool:
|
|
241
212
|
removed = False
|
|
242
213
|
if host.name in self.host_names:
|
|
243
214
|
self.hosts.remove(host)
|
|
@@ -247,7 +218,13 @@ class Group:
|
|
|
247
218
|
removed = True
|
|
248
219
|
return removed
|
|
249
220
|
|
|
250
|
-
def set_variable(self, key, value):
|
|
221
|
+
def set_variable(self, key: str, value: t.Any) -> None:
|
|
222
|
+
key = helpers.remove_trust(key)
|
|
223
|
+
|
|
224
|
+
try:
|
|
225
|
+
validate_variable_name(key)
|
|
226
|
+
except AnsibleError as ex:
|
|
227
|
+
Display().deprecated(msg=f'Accepting inventory variable with invalid name {key!r}.', version='2.23', help_text=ex._help_text, obj=ex.obj)
|
|
251
228
|
|
|
252
229
|
if key == 'ansible_group_priority':
|
|
253
230
|
self.set_priority(int(value))
|
|
@@ -257,36 +234,36 @@ class Group:
|
|
|
257
234
|
else:
|
|
258
235
|
self.vars[key] = value
|
|
259
236
|
|
|
260
|
-
def clear_hosts_cache(self):
|
|
237
|
+
def clear_hosts_cache(self) -> None:
|
|
261
238
|
|
|
262
239
|
self._hosts_cache = None
|
|
263
240
|
for g in self.get_ancestors():
|
|
264
241
|
g._hosts_cache = None
|
|
265
242
|
|
|
266
|
-
def get_hosts(self):
|
|
243
|
+
def get_hosts(self) -> list[Host]:
|
|
267
244
|
|
|
268
245
|
if self._hosts_cache is None:
|
|
269
246
|
self._hosts_cache = self._get_hosts()
|
|
270
247
|
return self._hosts_cache
|
|
271
248
|
|
|
272
|
-
def _get_hosts(self):
|
|
249
|
+
def _get_hosts(self) -> list[Host]:
|
|
273
250
|
|
|
274
|
-
hosts = []
|
|
275
|
-
seen =
|
|
251
|
+
hosts: list[Host] = []
|
|
252
|
+
seen: set[Host] = set()
|
|
276
253
|
for kid in self.get_descendants(include_self=True, preserve_ordering=True):
|
|
277
254
|
kid_hosts = kid.hosts
|
|
278
255
|
for kk in kid_hosts:
|
|
279
256
|
if kk not in seen:
|
|
280
|
-
seen
|
|
257
|
+
seen.add(kk)
|
|
281
258
|
if self.name == 'all' and kk.implicit:
|
|
282
259
|
continue
|
|
283
260
|
hosts.append(kk)
|
|
284
261
|
return hosts
|
|
285
262
|
|
|
286
|
-
def get_vars(self):
|
|
263
|
+
def get_vars(self) -> dict[str, t.Any]:
|
|
287
264
|
return self.vars.copy()
|
|
288
265
|
|
|
289
|
-
def set_priority(self, priority):
|
|
266
|
+
def set_priority(self, priority: int | str) -> None:
|
|
290
267
|
try:
|
|
291
268
|
self.priority = int(priority)
|
|
292
269
|
except TypeError:
|
ansible/inventory/helpers.py
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
#############################################
|
|
19
19
|
from __future__ import annotations
|
|
20
20
|
|
|
21
|
+
from ansible._internal._datatag._tags import TrustedAsTemplate
|
|
21
22
|
from ansible.utils.vars import combine_vars
|
|
22
23
|
|
|
23
24
|
|
|
@@ -37,3 +38,11 @@ def get_group_vars(groups):
|
|
|
37
38
|
results = combine_vars(results, group.get_vars())
|
|
38
39
|
|
|
39
40
|
return results
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def remove_trust(value: str) -> str:
|
|
44
|
+
"""
|
|
45
|
+
Remove trust from strings which should not be trusted.
|
|
46
|
+
This exists to centralize the untagging call which facilitate patching it out in unit tests.
|
|
47
|
+
"""
|
|
48
|
+
return TrustedAsTemplate.untag(value)
|
ansible/inventory/host.py
CHANGED
|
@@ -17,28 +17,28 @@
|
|
|
17
17
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
+
import collections.abc as c
|
|
21
|
+
import typing as t
|
|
22
|
+
|
|
20
23
|
from collections.abc import Mapping, MutableMapping
|
|
21
24
|
|
|
25
|
+
from ansible.errors import AnsibleError
|
|
22
26
|
from ansible.inventory.group import Group, InventoryObjectType
|
|
23
27
|
from ansible.parsing.utils.addresses import patterns
|
|
24
|
-
from ansible.utils.
|
|
28
|
+
from ansible.utils.display import Display
|
|
29
|
+
from ansible.utils.vars import combine_vars, get_unique_id, validate_variable_name
|
|
25
30
|
|
|
31
|
+
from . import helpers # this is left as a module import to facilitate easier unit test patching
|
|
26
32
|
|
|
27
33
|
__all__ = ['Host']
|
|
28
34
|
|
|
29
35
|
|
|
30
36
|
class Host:
|
|
31
|
-
|
|
37
|
+
"""A single ansible host."""
|
|
32
38
|
base_type = InventoryObjectType.HOST
|
|
33
39
|
|
|
34
40
|
# __slots__ = [ 'name', 'vars', 'groups' ]
|
|
35
41
|
|
|
36
|
-
def __getstate__(self):
|
|
37
|
-
return self.serialize()
|
|
38
|
-
|
|
39
|
-
def __setstate__(self, data):
|
|
40
|
-
return self.deserialize(data)
|
|
41
|
-
|
|
42
42
|
def __eq__(self, other):
|
|
43
43
|
if not isinstance(other, Host):
|
|
44
44
|
return False
|
|
@@ -56,55 +56,28 @@ class Host:
|
|
|
56
56
|
def __repr__(self):
|
|
57
57
|
return self.get_name()
|
|
58
58
|
|
|
59
|
-
def
|
|
60
|
-
|
|
61
|
-
for group in self.groups:
|
|
62
|
-
groups.append(group.serialize())
|
|
63
|
-
|
|
64
|
-
return dict(
|
|
65
|
-
name=self.name,
|
|
66
|
-
vars=self.vars.copy(),
|
|
67
|
-
address=self.address,
|
|
68
|
-
uuid=self._uuid,
|
|
69
|
-
groups=groups,
|
|
70
|
-
implicit=self.implicit,
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
def deserialize(self, data):
|
|
74
|
-
self.__init__(gen_uuid=False) # used by __setstate__ to deserialize in place # pylint: disable=unnecessary-dunder-call
|
|
75
|
-
|
|
76
|
-
self.name = data.get('name')
|
|
77
|
-
self.vars = data.get('vars', dict())
|
|
78
|
-
self.address = data.get('address', '')
|
|
79
|
-
self._uuid = data.get('uuid', None)
|
|
80
|
-
self.implicit = data.get('implicit', False)
|
|
81
|
-
|
|
82
|
-
groups = data.get('groups', [])
|
|
83
|
-
for group_data in groups:
|
|
84
|
-
g = Group()
|
|
85
|
-
g.deserialize(group_data)
|
|
86
|
-
self.groups.append(g)
|
|
59
|
+
def __init__(self, name: str, port: int | str | None = None, gen_uuid: bool = True) -> None:
|
|
60
|
+
name = helpers.remove_trust(name)
|
|
87
61
|
|
|
88
|
-
|
|
62
|
+
self.vars: dict[str, t.Any] = {}
|
|
63
|
+
self.groups: list[Group] = []
|
|
64
|
+
self._uuid: str | None = None
|
|
89
65
|
|
|
90
|
-
self.
|
|
91
|
-
self.
|
|
92
|
-
self._uuid = None
|
|
93
|
-
|
|
94
|
-
self.name = name
|
|
95
|
-
self.address = name
|
|
66
|
+
self.name: str = name
|
|
67
|
+
self.address: str = name
|
|
96
68
|
|
|
97
69
|
if port:
|
|
98
70
|
self.set_variable('ansible_port', int(port))
|
|
99
71
|
|
|
100
72
|
if gen_uuid:
|
|
101
73
|
self._uuid = get_unique_id()
|
|
102
|
-
self.implicit = False
|
|
103
74
|
|
|
104
|
-
|
|
75
|
+
self.implicit: bool = False
|
|
76
|
+
|
|
77
|
+
def get_name(self) -> str:
|
|
105
78
|
return self.name
|
|
106
79
|
|
|
107
|
-
def populate_ancestors(self, additions=None):
|
|
80
|
+
def populate_ancestors(self, additions: c.Iterable[Group] | None = None) -> None:
|
|
108
81
|
# populate ancestors
|
|
109
82
|
if additions is None:
|
|
110
83
|
for group in self.groups:
|
|
@@ -114,7 +87,7 @@ class Host:
|
|
|
114
87
|
if group not in self.groups:
|
|
115
88
|
self.groups.append(group)
|
|
116
89
|
|
|
117
|
-
def add_group(self, group):
|
|
90
|
+
def add_group(self, group: Group) -> bool:
|
|
118
91
|
added = False
|
|
119
92
|
# populate ancestors first
|
|
120
93
|
for oldg in group.get_ancestors():
|
|
@@ -127,7 +100,7 @@ class Host:
|
|
|
127
100
|
added = True
|
|
128
101
|
return added
|
|
129
102
|
|
|
130
|
-
def remove_group(self, group):
|
|
103
|
+
def remove_group(self, group: Group) -> bool:
|
|
131
104
|
removed = False
|
|
132
105
|
if group in self.groups:
|
|
133
106
|
self.groups.remove(group)
|
|
@@ -143,18 +116,28 @@ class Host:
|
|
|
143
116
|
self.remove_group(oldg)
|
|
144
117
|
return removed
|
|
145
118
|
|
|
146
|
-
def set_variable(self, key, value):
|
|
119
|
+
def set_variable(self, key: str, value: t.Any) -> None:
|
|
120
|
+
key = helpers.remove_trust(key)
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
validate_variable_name(key)
|
|
124
|
+
except AnsibleError as ex:
|
|
125
|
+
Display().deprecated(msg=f'Accepting inventory variable with invalid name {key!r}.', version='2.23', help_text=ex._help_text, obj=ex.obj)
|
|
126
|
+
|
|
147
127
|
if key in self.vars and isinstance(self.vars[key], MutableMapping) and isinstance(value, Mapping):
|
|
148
128
|
self.vars = combine_vars(self.vars, {key: value})
|
|
149
129
|
else:
|
|
150
130
|
self.vars[key] = value
|
|
151
131
|
|
|
152
|
-
def get_groups(self):
|
|
132
|
+
def get_groups(self) -> list[Group]:
|
|
153
133
|
return self.groups
|
|
154
134
|
|
|
155
|
-
def get_magic_vars(self):
|
|
156
|
-
results =
|
|
157
|
-
|
|
135
|
+
def get_magic_vars(self) -> dict[str, t.Any]:
|
|
136
|
+
results: dict[str, t.Any] = dict(
|
|
137
|
+
inventory_hostname=self.name,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# FUTURE: these values should be dynamically calculated on access ala the rest of magic vars
|
|
158
141
|
if patterns['ipv4'].match(self.name) or patterns['ipv6'].match(self.name):
|
|
159
142
|
results['inventory_hostname_short'] = self.name
|
|
160
143
|
else:
|
|
@@ -164,5 +147,5 @@ class Host:
|
|
|
164
147
|
|
|
165
148
|
return results
|
|
166
149
|
|
|
167
|
-
def get_vars(self):
|
|
150
|
+
def get_vars(self) -> dict[str, t.Any]:
|
|
168
151
|
return combine_vars(self.vars, self.get_magic_vars())
|
ansible/inventory/manager.py
CHANGED
|
@@ -19,28 +19,34 @@
|
|
|
19
19
|
from __future__ import annotations
|
|
20
20
|
|
|
21
21
|
import fnmatch
|
|
22
|
+
import functools
|
|
22
23
|
import os
|
|
23
|
-
import sys
|
|
24
24
|
import re
|
|
25
25
|
import itertools
|
|
26
|
-
import
|
|
26
|
+
import typing as t
|
|
27
27
|
|
|
28
28
|
from operator import attrgetter
|
|
29
29
|
from random import shuffle
|
|
30
30
|
|
|
31
31
|
from ansible import constants as C
|
|
32
|
-
from ansible.
|
|
32
|
+
from ansible._internal import _json, _wrapt
|
|
33
|
+
from ansible._internal._json import EncryptedStringBehavior
|
|
34
|
+
from ansible.errors import AnsibleError, AnsibleOptionsError
|
|
33
35
|
from ansible.inventory.data import InventoryData
|
|
34
36
|
from ansible.module_utils.six import string_types
|
|
35
37
|
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
|
36
38
|
from ansible.parsing.utils.addresses import parse_address
|
|
37
39
|
from ansible.plugins.loader import inventory_loader
|
|
40
|
+
from ansible._internal._datatag._tags import Origin
|
|
38
41
|
from ansible.utils.helpers import deduplicate_list
|
|
39
42
|
from ansible.utils.path import unfrackpath
|
|
40
43
|
from ansible.utils.display import Display
|
|
41
44
|
from ansible.utils.vars import combine_vars
|
|
42
45
|
from ansible.vars.plugins import get_vars_from_inventory_sources
|
|
43
46
|
|
|
47
|
+
if t.TYPE_CHECKING:
|
|
48
|
+
from ansible.plugins.inventory import BaseInventoryPlugin
|
|
49
|
+
|
|
44
50
|
display = Display()
|
|
45
51
|
|
|
46
52
|
IGNORED_ALWAYS = [br"^\.", b"^host_vars$", b"^group_vars$", b"^vars_plugins$"]
|
|
@@ -50,7 +56,7 @@ IGNORED_EXTS = [b'%s$' % to_bytes(re.escape(x)) for x in C.INVENTORY_IGNORE_EXTS
|
|
|
50
56
|
IGNORED = re.compile(b'|'.join(IGNORED_ALWAYS + IGNORED_PATTERNS + IGNORED_EXTS))
|
|
51
57
|
|
|
52
58
|
PATTERN_WITH_SUBSCRIPT = re.compile(
|
|
53
|
-
r
|
|
59
|
+
r"""^
|
|
54
60
|
(.+) # A pattern expression ending with...
|
|
55
61
|
\[(?: # A [subscript] expression comprising:
|
|
56
62
|
(-?[0-9]+)| # A single positive or negative number
|
|
@@ -58,12 +64,12 @@ PATTERN_WITH_SUBSCRIPT = re.compile(
|
|
|
58
64
|
([0-9]*)
|
|
59
65
|
)\]
|
|
60
66
|
$
|
|
61
|
-
|
|
67
|
+
""", re.X
|
|
62
68
|
)
|
|
63
69
|
|
|
64
70
|
|
|
65
71
|
def order_patterns(patterns):
|
|
66
|
-
|
|
72
|
+
""" takes a list of patterns and reorders them by modifier to apply them consistently """
|
|
67
73
|
|
|
68
74
|
# FIXME: this goes away if we apply patterns incrementally or by groups
|
|
69
75
|
pattern_regular = []
|
|
@@ -125,19 +131,19 @@ def split_host_pattern(pattern):
|
|
|
125
131
|
# This mishandles IPv6 addresses, and is retained only for backwards
|
|
126
132
|
# compatibility.
|
|
127
133
|
patterns = re.findall(
|
|
128
|
-
to_text(r
|
|
134
|
+
to_text(r"""(?: # We want to match something comprising:
|
|
129
135
|
[^\s:\[\]] # (anything other than whitespace or ':[]'
|
|
130
136
|
| # ...or...
|
|
131
137
|
\[[^\]]*\] # a single complete bracketed expression)
|
|
132
138
|
)+ # occurring once or more
|
|
133
|
-
|
|
139
|
+
"""), pattern, re.X
|
|
134
140
|
)
|
|
135
141
|
|
|
136
142
|
return [p.strip() for p in patterns if p.strip()]
|
|
137
143
|
|
|
138
144
|
|
|
139
145
|
class InventoryManager(object):
|
|
140
|
-
|
|
146
|
+
""" Creates and manages inventory """
|
|
141
147
|
|
|
142
148
|
def __init__(self, loader, sources=None, parse=True, cache=True):
|
|
143
149
|
|
|
@@ -196,12 +202,12 @@ class InventoryManager(object):
|
|
|
196
202
|
def get_host(self, hostname):
|
|
197
203
|
return self._inventory.get_host(hostname)
|
|
198
204
|
|
|
199
|
-
def _fetch_inventory_plugins(self):
|
|
200
|
-
|
|
205
|
+
def _fetch_inventory_plugins(self) -> list[BaseInventoryPlugin]:
|
|
206
|
+
""" sets up loaded inventory plugins for usage """
|
|
201
207
|
|
|
202
208
|
display.vvvv('setting up inventory plugins')
|
|
203
209
|
|
|
204
|
-
plugins = []
|
|
210
|
+
plugins: list[BaseInventoryPlugin] = []
|
|
205
211
|
for name in C.INVENTORY_ENABLED:
|
|
206
212
|
plugin = inventory_loader.get(name)
|
|
207
213
|
if plugin:
|
|
@@ -215,7 +221,7 @@ class InventoryManager(object):
|
|
|
215
221
|
return plugins
|
|
216
222
|
|
|
217
223
|
def parse_sources(self, cache=False):
|
|
218
|
-
|
|
224
|
+
""" iterate over inventory sources and parse each one to populate it"""
|
|
219
225
|
|
|
220
226
|
parsed = False
|
|
221
227
|
# allow for multiple inventory parsing
|
|
@@ -243,7 +249,7 @@ class InventoryManager(object):
|
|
|
243
249
|
host.vars = combine_vars(host.vars, get_vars_from_inventory_sources(self._loader, self._sources, [host], 'inventory'))
|
|
244
250
|
|
|
245
251
|
def parse_source(self, source, cache=False):
|
|
246
|
-
|
|
252
|
+
""" Generate or update inventory for the source provided """
|
|
247
253
|
|
|
248
254
|
parsed = False
|
|
249
255
|
failures = []
|
|
@@ -276,7 +282,6 @@ class InventoryManager(object):
|
|
|
276
282
|
|
|
277
283
|
# try source with each plugin
|
|
278
284
|
for plugin in self._fetch_inventory_plugins():
|
|
279
|
-
|
|
280
285
|
plugin_name = to_text(getattr(plugin, '_load_name', getattr(plugin, '_original_path', '')))
|
|
281
286
|
display.debug(u'Attempting to use plugin %s (%s)' % (plugin_name, plugin._original_path))
|
|
282
287
|
|
|
@@ -287,9 +292,14 @@ class InventoryManager(object):
|
|
|
287
292
|
plugin_wants = False
|
|
288
293
|
|
|
289
294
|
if plugin_wants:
|
|
295
|
+
# have this tag ready to apply to errors or output; str-ify source since it is often tagged by the CLI
|
|
296
|
+
origin = Origin(description=f'<inventory plugin {plugin_name!r} with source {str(source)!r}>')
|
|
290
297
|
try:
|
|
291
|
-
|
|
292
|
-
|
|
298
|
+
inventory_wrapper = _InventoryDataWrapper(self._inventory, target_plugin=plugin, origin=origin)
|
|
299
|
+
|
|
300
|
+
# FUTURE: now that we have a wrapper around inventory, we can have it use ChainMaps to preview the in-progress inventory,
|
|
301
|
+
# but be able to roll back partial inventory failures by discarding the outermost layer
|
|
302
|
+
plugin.parse(inventory_wrapper, self._loader, source, cache=cache)
|
|
293
303
|
try:
|
|
294
304
|
plugin.update_cache_if_changed()
|
|
295
305
|
except AttributeError:
|
|
@@ -298,14 +308,17 @@ class InventoryManager(object):
|
|
|
298
308
|
parsed = True
|
|
299
309
|
display.vvv('Parsed %s inventory source with %s plugin' % (source, plugin_name))
|
|
300
310
|
break
|
|
301
|
-
except
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
failures.append({'src': source, 'plugin': plugin_name, 'exc':
|
|
305
|
-
except Exception as
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
311
|
+
except AnsibleError as ex:
|
|
312
|
+
if not ex.obj:
|
|
313
|
+
ex.obj = origin
|
|
314
|
+
failures.append({'src': source, 'plugin': plugin_name, 'exc': ex})
|
|
315
|
+
except Exception as ex:
|
|
316
|
+
# DTFIX-FUTURE: fix this error handling to correctly deal with messaging
|
|
317
|
+
try:
|
|
318
|
+
# omit line number to prevent contextual display of script or possibly sensitive info
|
|
319
|
+
raise AnsibleError(str(ex), obj=origin) from ex
|
|
320
|
+
except AnsibleError as ex:
|
|
321
|
+
failures.append({'src': source, 'plugin': plugin_name, 'exc': ex})
|
|
309
322
|
else:
|
|
310
323
|
display.vvv("%s declined parsing %s as it did not pass its verify_file() method" % (plugin_name, source))
|
|
311
324
|
|
|
@@ -319,9 +332,8 @@ class InventoryManager(object):
|
|
|
319
332
|
if failures:
|
|
320
333
|
# only if no plugin processed files should we show errors.
|
|
321
334
|
for fail in failures:
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
display.vvv(to_text(fail['tb']))
|
|
335
|
+
# `obj` should always be set
|
|
336
|
+
display.error_as_warning(msg=f'Failed to parse inventory with {fail["plugin"]!r} plugin.', exception=fail['exc'])
|
|
325
337
|
|
|
326
338
|
# final error/warning on inventory source failure
|
|
327
339
|
if C.INVENTORY_ANY_UNPARSED_IS_FAILED:
|
|
@@ -335,12 +347,12 @@ class InventoryManager(object):
|
|
|
335
347
|
return parsed
|
|
336
348
|
|
|
337
349
|
def clear_caches(self):
|
|
338
|
-
|
|
350
|
+
""" clear all caches """
|
|
339
351
|
self._hosts_patterns_cache = {}
|
|
340
352
|
self._pattern_cache = {}
|
|
341
353
|
|
|
342
354
|
def refresh_inventory(self):
|
|
343
|
-
|
|
355
|
+
""" recalculate inventory """
|
|
344
356
|
|
|
345
357
|
self.clear_caches()
|
|
346
358
|
self._inventory = InventoryData()
|
|
@@ -657,9 +669,9 @@ class InventoryManager(object):
|
|
|
657
669
|
self._pattern_cache = {}
|
|
658
670
|
|
|
659
671
|
def add_dynamic_host(self, host_info, result_item):
|
|
660
|
-
|
|
672
|
+
"""
|
|
661
673
|
Helper function to add a new host to inventory based on a task result.
|
|
662
|
-
|
|
674
|
+
"""
|
|
663
675
|
|
|
664
676
|
changed = False
|
|
665
677
|
if not result_item.get('refresh'):
|
|
@@ -697,10 +709,10 @@ class InventoryManager(object):
|
|
|
697
709
|
result_item['changed'] = changed
|
|
698
710
|
|
|
699
711
|
def add_dynamic_group(self, host, result_item):
|
|
700
|
-
|
|
712
|
+
"""
|
|
701
713
|
Helper function to add a group (if it does not exist), and to assign the
|
|
702
714
|
specified host to that group.
|
|
703
|
-
|
|
715
|
+
"""
|
|
704
716
|
|
|
705
717
|
changed = False
|
|
706
718
|
|
|
@@ -749,3 +761,36 @@ class InventoryManager(object):
|
|
|
749
761
|
self.reconcile_inventory()
|
|
750
762
|
|
|
751
763
|
result_item['changed'] = changed
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
class _InventoryDataWrapper(_wrapt.ObjectProxy):
|
|
767
|
+
"""
|
|
768
|
+
Proxy wrapper around InventoryData.
|
|
769
|
+
Allows `set_variable` calls to automatically apply template trust for plugins that don't know how.
|
|
770
|
+
"""
|
|
771
|
+
|
|
772
|
+
# declared as class attrs to signal to ObjectProxy that we want them stored on the proxy, not the wrapped value
|
|
773
|
+
_target_plugin = None
|
|
774
|
+
_default_origin = None
|
|
775
|
+
|
|
776
|
+
def __init__(self, referent: InventoryData, target_plugin: BaseInventoryPlugin, origin: Origin) -> None:
|
|
777
|
+
super().__init__(referent)
|
|
778
|
+
self._target_plugin = target_plugin
|
|
779
|
+
# fallback origin to ensure that vars are tagged with at least the file they came from
|
|
780
|
+
self._default_origin = origin
|
|
781
|
+
|
|
782
|
+
@functools.cached_property
|
|
783
|
+
def _inspector(self) -> _json.AnsibleVariableVisitor:
|
|
784
|
+
"""
|
|
785
|
+
Inventory plugins can delegate to other plugins (e.g. `auto`).
|
|
786
|
+
This hack defers sampling the target plugin's `trusted_by_default` attr until `set_variable` is called, typically inside `parse`.
|
|
787
|
+
Trust is then optionally applied based on the plugin's declared intent via `trusted_by_default`.
|
|
788
|
+
"""
|
|
789
|
+
return _json.AnsibleVariableVisitor(
|
|
790
|
+
trusted_as_template=self._target_plugin.trusted_by_default,
|
|
791
|
+
origin=self._default_origin,
|
|
792
|
+
encrypted_string_behavior=EncryptedStringBehavior.PRESERVE,
|
|
793
|
+
)
|
|
794
|
+
|
|
795
|
+
def set_variable(self, entity: str, varname: str, value: t.Any) -> None:
|
|
796
|
+
self.__wrapped__.set_variable(entity, varname, self._inspector.visit(value))
|