ansible-core 2.18.5rc1__py3-none-any.whl → 2.19.0b1__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.
- ansible/_internal/__init__.py +53 -0
- ansible/_internal/_ansiballz.py +265 -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/_captured.py +128 -0
- ansible/_internal/_errors/_handler.py +91 -0
- ansible/_internal/_errors/_utils.py +310 -0
- ansible/_internal/_json/__init__.py +160 -0
- ansible/_internal/_json/_legacy_encoder.py +34 -0
- ansible/_internal/_json/_profiles/__init__.py +0 -0
- ansible/_internal/_json/_profiles/_cache_persistence.py +55 -0
- ansible/_internal/_json/_profiles/_inventory_legacy.py +40 -0
- ansible/_internal/_json/_profiles/_legacy.py +198 -0
- ansible/_internal/_locking.py +21 -0
- ansible/_internal/_plugins/__init__.py +0 -0
- ansible/_internal/_plugins/_cache.py +57 -0
- ansible/_internal/_task.py +78 -0
- ansible/_internal/_templating/__init__.py +10 -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 +588 -0
- ansible/_internal/_templating/_errors.py +28 -0
- ansible/_internal/_templating/_jinja_bits.py +1066 -0
- ansible/_internal/_templating/_jinja_common.py +332 -0
- ansible/_internal/_templating/_jinja_patches.py +44 -0
- ansible/_internal/_templating/_jinja_plugins.py +351 -0
- ansible/_internal/_templating/_lazy_containers.py +633 -0
- ansible/_internal/_templating/_marker_behaviors.py +103 -0
- ansible/_internal/_templating/_transform.py +63 -0
- ansible/_internal/_templating/_utils.py +107 -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 +62 -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 +18 -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 +153 -89
- ansible/cli/_ssh_askpass.py +47 -0
- ansible/cli/adhoc.py +14 -7
- ansible/cli/arguments/option_helpers.py +154 -7
- ansible/cli/config.py +43 -68
- ansible/cli/console.py +10 -8
- ansible/cli/doc.py +48 -46
- ansible/cli/galaxy.py +27 -20
- ansible/cli/inventory.py +28 -26
- ansible/cli/playbook.py +4 -12
- ansible/cli/pull.py +51 -11
- ansible/cli/scripts/ansible_connection_cli_stub.py +7 -7
- ansible/cli/vault.py +12 -11
- ansible/compat/__init__.py +2 -2
- ansible/config/base.yml +165 -108
- ansible/config/manager.py +52 -49
- ansible/constants.py +3 -4
- ansible/errors/__init__.py +277 -235
- ansible/executor/interpreter_discovery.py +28 -149
- ansible/executor/module_common.py +426 -493
- 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 +202 -151
- ansible/executor/powershell/become_wrapper.ps1 +89 -144
- ansible/executor/powershell/bootstrap_wrapper.ps1 +24 -9
- ansible/executor/powershell/coverage_wrapper.ps1 +82 -135
- ansible/executor/powershell/exec_wrapper.ps1 +462 -196
- ansible/executor/powershell/module_manifest.py +417 -265
- ansible/executor/powershell/module_wrapper.ps1 +169 -186
- 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 +136 -76
- ansible/executor/stats.py +5 -5
- ansible/executor/task_executor.py +237 -236
- ansible/executor/task_queue_manager.py +62 -38
- ansible/executor/task_result.py +21 -12
- ansible/galaxy/__init__.py +2 -2
- ansible/galaxy/api.py +22 -18
- ansible/galaxy/collection/__init__.py +1 -1
- ansible/galaxy/collection/concrete_artifact_manager.py +8 -11
- ansible/galaxy/dependency_resolution/dataclasses.py +14 -4
- ansible/galaxy/dependency_resolution/providers.py +1 -1
- ansible/galaxy/dependency_resolution/reporters.py +81 -0
- ansible/galaxy/role.py +4 -8
- ansible/galaxy/token.py +28 -21
- ansible/inventory/data.py +47 -57
- ansible/inventory/group.py +44 -72
- ansible/inventory/helpers.py +9 -0
- ansible/inventory/host.py +32 -54
- ansible/inventory/manager.py +77 -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.py +133 -0
- ansible/module_utils/_internal/_concurrent/_daemon_threading.py +1 -0
- ansible/module_utils/_internal/_dataclass_annotation_patch.py +64 -0
- ansible/module_utils/_internal/_dataclass_validation.py +217 -0
- ansible/module_utils/_internal/_datatag/__init__.py +928 -0
- ansible/module_utils/_internal/_datatag/_tags.py +38 -0
- ansible/module_utils/_internal/_debugging.py +31 -0
- ansible/module_utils/_internal/_errors.py +30 -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 +410 -0
- ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py +73 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +31 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +35 -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 +50 -0
- ansible/module_utils/_internal/_patches/__init__.py +66 -0
- ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +55 -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_exec_context.py +49 -0
- ansible/module_utils/_internal/_testing.py +0 -0
- ansible/module_utils/_internal/_traceback.py +89 -0
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/api.py +1 -2
- ansible/module_utils/basic.py +154 -120
- ansible/module_utils/common/_utils.py +24 -28
- ansible/module_utils/common/collections.py +1 -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/messages.py +108 -0
- ansible/module_utils/common/parameters.py +27 -24
- ansible/module_utils/common/process.py +2 -2
- ansible/module_utils/common/respawn.py +41 -19
- 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 +86 -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 +2 -2
- ansible/module_utils/csharp/Ansible.Basic.cs +14 -11
- ansible/module_utils/csharp/Ansible.Become.cs +1 -0
- ansible/module_utils/csharp/Ansible._Async.cs +517 -0
- ansible/module_utils/datatag.py +46 -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 +1 -1
- 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 +4 -4
- 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 +1 -2
- ansible/module_utils/facts/other/ohai.py +2 -3
- ansible/module_utils/facts/system/apparmor.py +1 -2
- ansible/module_utils/facts/system/caps.py +1 -1
- 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 +9 -8
- 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 +1 -2
- 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/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 +1 -1
- ansible/module_utils/service.py +18 -21
- ansible/module_utils/splitter.py +7 -7
- ansible/module_utils/testing.py +31 -0
- ansible/module_utils/urls.py +60 -31
- ansible/modules/add_host.py +4 -4
- ansible/modules/apt.py +60 -46
- ansible/modules/apt_key.py +19 -12
- ansible/modules/apt_repository.py +19 -16
- ansible/modules/assemble.py +6 -6
- ansible/modules/assert.py +4 -4
- ansible/modules/async_status.py +10 -12
- ansible/modules/async_wrapper.py +8 -3
- ansible/modules/blockinfile.py +6 -7
- ansible/modules/command.py +10 -17
- ansible/modules/copy.py +57 -144
- ansible/modules/cron.py +20 -15
- 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 +8 -10
- ansible/modules/fail.py +4 -4
- ansible/modules/fetch.py +4 -4
- ansible/modules/file.py +174 -133
- ansible/modules/find.py +19 -17
- ansible/modules/gather_facts.py +3 -3
- ansible/modules/get_url.py +59 -53
- ansible/modules/getent.py +7 -9
- ansible/modules/git.py +28 -25
- ansible/modules/group.py +6 -6
- ansible/modules/group_by.py +4 -4
- ansible/modules/hostname.py +13 -29
- 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 +10 -10
- ansible/modules/lineinfile.py +5 -5
- ansible/modules/meta.py +4 -4
- ansible/modules/mount_facts.py +2 -2
- ansible/modules/package.py +4 -4
- ansible/modules/package_facts.py +22 -10
- ansible/modules/pause.py +6 -6
- ansible/modules/ping.py +6 -6
- ansible/modules/pip.py +10 -11
- ansible/modules/raw.py +4 -4
- ansible/modules/reboot.py +6 -6
- ansible/modules/replace.py +9 -13
- ansible/modules/rpm_key.py +7 -8
- ansible/modules/script.py +4 -4
- ansible/modules/service.py +7 -8
- 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 +6 -6
- ansible/modules/stat.py +9 -23
- ansible/modules/subversion.py +15 -15
- ansible/modules/systemd.py +6 -6
- ansible/modules/systemd_service.py +6 -6
- ansible/modules/sysvinit.py +6 -6
- ansible/modules/tempfile.py +5 -6
- ansible/modules/template.py +6 -6
- ansible/modules/unarchive.py +32 -11
- ansible/modules/uri.py +33 -26
- ansible/modules/user.py +53 -34
- ansible/modules/validate_argument_spec.py +10 -7
- ansible/modules/wait_for.py +32 -27
- ansible/modules/wait_for_connection.py +6 -6
- ansible/modules/yum_repository.py +6 -6
- ansible/parsing/ajson.py +14 -32
- ansible/parsing/dataloader.py +99 -54
- ansible/parsing/mod_args.py +28 -44
- 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/yaml.py +32 -61
- ansible/parsing/vault/__init__.py +319 -87
- 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 +36 -339
- ansible/playbook/__init__.py +1 -1
- ansible/playbook/attribute.py +8 -3
- ansible/playbook/base.py +182 -132
- 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 +6 -15
- ansible/playbook/loop_control.py +2 -2
- ansible/playbook/play.py +85 -44
- ansible/playbook/play_context.py +12 -17
- ansible/playbook/playbook_include.py +14 -15
- ansible/playbook/role/__init__.py +24 -26
- 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 +13 -8
- ansible/playbook/task.py +188 -118
- ansible/playbook/task_include.py +5 -5
- ansible/plugins/__init__.py +68 -21
- ansible/plugins/action/__init__.py +209 -176
- ansible/plugins/action/add_host.py +1 -1
- ansible/plugins/action/assemble.py +1 -1
- ansible/plugins/action/assert.py +54 -66
- ansible/plugins/action/copy.py +7 -11
- 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 +4 -5
- ansible/plugins/action/gather_facts.py +7 -6
- ansible/plugins/action/group_by.py +1 -1
- ansible/plugins/action/include_vars.py +10 -11
- ansible/plugins/action/package.py +3 -6
- ansible/plugins/action/pause.py +2 -2
- ansible/plugins/action/script.py +15 -8
- ansible/plugins/action/service.py +6 -11
- ansible/plugins/action/set_fact.py +3 -12
- ansible/plugins/action/set_stats.py +3 -8
- ansible/plugins/action/template.py +35 -59
- ansible/plugins/action/unarchive.py +1 -1
- 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 +35 -44
- 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 +141 -123
- ansible/plugins/callback/default.py +30 -23
- ansible/plugins/callback/junit.py +28 -24
- ansible/plugins/callback/minimal.py +17 -14
- ansible/plugins/callback/oneline.py +13 -7
- ansible/plugins/callback/tree.py +10 -6
- ansible/plugins/connection/__init__.py +47 -34
- ansible/plugins/connection/local.py +150 -54
- ansible/plugins/connection/paramiko_ssh.py +21 -18
- ansible/plugins/connection/psrp.py +76 -165
- ansible/plugins/connection/ssh.py +301 -78
- ansible/plugins/connection/winrm.py +58 -140
- 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 +6 -2
- 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 +218 -108
- ansible/plugins/filter/encryption.py +32 -32
- 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/regex_search.yml +1 -4
- ansible/plugins/filter/split.yml +1 -1
- ansible/plugins/filter/to_nice_yaml.yml +0 -4
- 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 +97 -77
- 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 +189 -119
- ansible/plugins/inventory/toml.py +16 -126
- ansible/plugins/inventory/yaml.py +10 -8
- ansible/plugins/list.py +3 -3
- ansible/plugins/loader.py +197 -82
- ansible/plugins/lookup/__init__.py +21 -4
- ansible/plugins/lookup/config.py +21 -35
- ansible/plugins/lookup/csvfile.py +3 -2
- 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 +86 -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 +42 -36
- ansible/plugins/lookup/together.py +0 -12
- ansible/plugins/lookup/unvault.py +1 -5
- ansible/plugins/lookup/url.py +2 -8
- ansible/plugins/lookup/vars.py +16 -24
- ansible/plugins/shell/__init__.py +2 -2
- ansible/plugins/shell/cmd.py +2 -2
- ansible/plugins/shell/powershell.py +39 -22
- ansible/plugins/shell/sh.py +3 -2
- ansible/plugins/strategy/__init__.py +94 -113
- ansible/plugins/strategy/debug.py +2 -2
- ansible/plugins/strategy/free.py +13 -28
- ansible/plugins/strategy/host_pinned.py +2 -2
- ansible/plugins/strategy/linear.py +31 -33
- ansible/plugins/terminal/__init__.py +4 -4
- ansible/plugins/test/__init__.py +7 -2
- ansible/plugins/test/core.py +54 -20
- ansible/plugins/test/files.py +1 -1
- ansible/plugins/test/mathstuff.py +3 -3
- ansible/plugins/test/uri.py +3 -3
- ansible/plugins/vars/host_group_vars.py +7 -14
- ansible/release.py +2 -2
- ansible/template/__init__.py +368 -944
- ansible/utils/__init__.py +0 -18
- ansible/utils/_ssh_agent.py +657 -0
- ansible/utils/collection_loader/__init__.py +52 -5
- ansible/utils/collection_loader/_collection_config.py +5 -6
- ansible/utils/collection_loader/_collection_finder.py +79 -93
- ansible/utils/collection_loader/_collection_meta.py +13 -8
- ansible/utils/display.py +428 -58
- ansible/utils/encrypt.py +27 -19
- ansible/utils/fqcn.py +2 -2
- ansible/utils/hashing.py +2 -2
- ansible/utils/helpers.py +2 -2
- ansible/utils/listify.py +8 -8
- ansible/utils/lock.py +2 -2
- ansible/utils/path.py +4 -4
- ansible/utils/plugin_docs.py +14 -13
- ansible/utils/sentinel.py +4 -62
- ansible/utils/singleton.py +2 -0
- ansible/utils/ssh_functions.py +1 -1
- ansible/utils/unsafe_proxy.py +23 -332
- ansible/utils/vars.py +28 -8
- ansible/utils/version.py +2 -2
- ansible/vars/clean.py +4 -4
- ansible/vars/hostvars.py +60 -90
- ansible/vars/manager.py +205 -264
- ansible/vars/reserved.py +8 -9
- ansible_core-2.19.0b1.dist-info/BSD-3-Clause.txt +28 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/METADATA +5 -4
- ansible_core-2.19.0b1.dist-info/RECORD +1070 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/WHEEL +1 -1
- 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 +1 -1
- ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
- ansible_test/_data/requirements/sanity.pylint.txt +4 -4
- 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 +1 -0
- ansible_test/_internal/ansible_util.py +2 -0
- 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 -0
- 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 +1 -0
- 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 +2 -1
- 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 +4 -0
- 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 +2 -1
- 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 +1 -0
- 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 +16 -1
- 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 +1 -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 +24 -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 +1 -0
- ansible_test/_internal/commands/units/__init__.py +1 -0
- 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 +2 -0
- 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/delegation.py +1 -0
- 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 +1 -0
- ansible_test/_internal/http.py +1 -0
- ansible_test/_internal/init.py +1 -0
- ansible_test/_internal/inventory.py +35 -3
- ansible_test/_internal/io.py +1 -0
- ansible_test/_internal/metadata.py +1 -0
- ansible_test/_internal/payload.py +1 -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 +1 -0
- ansible_test/_internal/pypi_proxy.py +6 -5
- ansible_test/_internal/python_requirements.py +1 -0
- ansible_test/_internal/ssh.py +1 -0
- ansible_test/_internal/target.py +1 -0
- ansible_test/_internal/test.py +3 -2
- ansible_test/_internal/thread.py +1 -0
- ansible_test/_internal/timeout.py +1 -0
- ansible_test/_internal/util.py +1 -0
- ansible_test/_internal/util_common.py +5 -2
- 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 +7 -5
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +7 -5
- ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +7 -5
- ansible_test/_util/controller/sanity/pylint/config/collection.cfg +3 -5
- ansible_test/_util/controller/sanity/pylint/config/default.cfg +7 -7
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -13
- 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/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 +35 -27
- 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/utils/jsonify.py +0 -36
- 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.5rc1.dist-info/RECORD +0 -992
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/Apache-License.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/COPYING +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/MIT-license.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/PSF-license.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/simplified_bsd.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/top_level.txt +0 -0
ansible/vars/manager.py
CHANGED
@@ -19,38 +19,60 @@ from __future__ import annotations
|
|
19
19
|
|
20
20
|
import os
|
21
21
|
import sys
|
22
|
+
import typing as t
|
22
23
|
|
23
24
|
from collections import defaultdict
|
24
|
-
from collections.abc import Mapping, MutableMapping
|
25
|
-
from hashlib import sha1
|
26
|
-
|
27
|
-
from jinja2.exceptions import UndefinedError
|
25
|
+
from collections.abc import Mapping, MutableMapping
|
28
26
|
|
29
27
|
from ansible import constants as C
|
30
|
-
from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleFileNotFound,
|
28
|
+
from ansible.errors import (AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleFileNotFound,
|
29
|
+
AnsibleAssertionError, AnsibleValueOmittedError)
|
31
30
|
from ansible.inventory.host import Host
|
32
31
|
from ansible.inventory.helpers import sort_groups, get_group_vars
|
33
|
-
from ansible.
|
32
|
+
from ansible.inventory.manager import InventoryManager
|
33
|
+
from ansible.module_utils.datatag import native_type_name
|
34
34
|
from ansible.module_utils.six import text_type
|
35
|
-
from ansible.
|
36
|
-
from ansible.
|
35
|
+
from ansible.module_utils.datatag import deprecate_value
|
36
|
+
from ansible.parsing.dataloader import DataLoader
|
37
|
+
from ansible._internal._templating._engine import TemplateEngine
|
38
|
+
from ansible.plugins.loader import cache_loader
|
37
39
|
from ansible.utils.display import Display
|
38
40
|
from ansible.utils.vars import combine_vars, load_extra_vars, load_options_vars
|
39
|
-
from ansible.utils.unsafe_proxy import wrap_var
|
40
41
|
from ansible.vars.clean import namespace_facts, clean_facts
|
42
|
+
from ansible.vars.hostvars import HostVars
|
41
43
|
from ansible.vars.plugins import get_vars_from_inventory_sources, get_vars_from_path
|
42
44
|
from ansible.vars.reserved import warn_if_reserved
|
43
45
|
|
46
|
+
if t.TYPE_CHECKING:
|
47
|
+
from ansible.playbook import Play
|
48
|
+
from ansible.playbook.task import Task
|
49
|
+
|
44
50
|
display = Display()
|
45
51
|
|
52
|
+
# deprecated: description='enable top-level facts deprecation' core_version='2.20'
|
53
|
+
# _DEPRECATE_TOP_LEVEL_FACT_MSG = sys.intern('Top-level facts are deprecated, use `ansible_facts` instead.')
|
54
|
+
# _DEPRECATE_TOP_LEVEL_FACT_REMOVAL_VERSION = sys.intern('2.22')
|
55
|
+
|
56
|
+
|
57
|
+
def _deprecate_top_level_fact(value: t.Any) -> t.Any:
|
58
|
+
"""
|
59
|
+
Deprecate the given top-level fact value.
|
60
|
+
The inner values are shared to aid in message de-duplication across hosts/values, and reduce intra-process memory usage.
|
61
|
+
Unique tag instances are required to achieve the correct de-duplication within a top-level templating operation.
|
62
|
+
"""
|
63
|
+
# deprecated: description='enable top-level facts deprecation' core_version='2.20'
|
64
|
+
# return deprecate_value(value, _DEPRECATE_TOP_LEVEL_FACT_MSG, removal_version=_DEPRECATE_TOP_LEVEL_FACT_REMOVAL_VERSION)
|
65
|
+
return value
|
66
|
+
|
46
67
|
|
47
68
|
def preprocess_vars(a):
|
48
|
-
|
69
|
+
"""
|
49
70
|
Ensures that vars contained in the parameter passed in are
|
50
71
|
returned as a list of dictionaries, to ensure for instance
|
51
72
|
that vars loaded from a file conform to an expected state.
|
52
|
-
|
73
|
+
"""
|
53
74
|
|
75
|
+
# FIXME: this does not properly handle omit, undefined, or dynamic structure from templated `vars` ; templating should be done earlier
|
54
76
|
if a is None:
|
55
77
|
return None
|
56
78
|
elif not isinstance(a, list):
|
@@ -60,7 +82,11 @@ def preprocess_vars(a):
|
|
60
82
|
|
61
83
|
for item in data:
|
62
84
|
if not isinstance(item, MutableMapping):
|
63
|
-
raise
|
85
|
+
raise AnsibleParserError(
|
86
|
+
message="Invalid variable file contents.",
|
87
|
+
obj=item,
|
88
|
+
help_text="Variable files must contain either a dictionary of variables, or a list of dictionaries.",
|
89
|
+
)
|
64
90
|
|
65
91
|
return data
|
66
92
|
|
@@ -70,16 +96,12 @@ class VariableManager:
|
|
70
96
|
_ALLOWED = frozenset(['plugins_by_group', 'groups_plugins_play', 'groups_plugins_inventory', 'groups_inventory',
|
71
97
|
'all_plugins_play', 'all_plugins_inventory', 'all_inventory'])
|
72
98
|
|
73
|
-
def __init__(self, loader=None, inventory=None, version_info=None):
|
74
|
-
self._nonpersistent_fact_cache = defaultdict(dict)
|
75
|
-
self._vars_cache = defaultdict(dict)
|
76
|
-
self._extra_vars = defaultdict(dict)
|
77
|
-
self._host_vars_files = defaultdict(dict)
|
78
|
-
self._group_vars_files = defaultdict(dict)
|
99
|
+
def __init__(self, loader: DataLoader | None = None, inventory: InventoryManager | None = None, version_info: dict[str, str] | None = None) -> None:
|
100
|
+
self._nonpersistent_fact_cache: defaultdict[str, dict] = defaultdict(dict)
|
101
|
+
self._vars_cache: defaultdict[str, dict] = defaultdict(dict)
|
79
102
|
self._inventory = inventory
|
80
103
|
self._loader = loader
|
81
|
-
self._hostvars = None
|
82
|
-
self._omit_token = '__omit_place_holder__%s' % sha1(os.urandom(64)).hexdigest()
|
104
|
+
self._hostvars: HostVars | None = None
|
83
105
|
|
84
106
|
self._options_vars = load_options_vars(version_info)
|
85
107
|
|
@@ -93,41 +115,12 @@ class VariableManager:
|
|
93
115
|
|
94
116
|
# load fact cache
|
95
117
|
try:
|
96
|
-
self._fact_cache =
|
97
|
-
except
|
118
|
+
self._fact_cache = cache_loader.get(C.CACHE_PLUGIN)
|
119
|
+
except Exception as ex:
|
98
120
|
# bad cache plugin is not fatal error
|
99
|
-
# fallback to
|
100
|
-
display.
|
101
|
-
self._fact_cache =
|
102
|
-
|
103
|
-
def __getstate__(self):
|
104
|
-
data = dict(
|
105
|
-
fact_cache=self._fact_cache,
|
106
|
-
np_fact_cache=self._nonpersistent_fact_cache,
|
107
|
-
vars_cache=self._vars_cache,
|
108
|
-
extra_vars=self._extra_vars,
|
109
|
-
host_vars_files=self._host_vars_files,
|
110
|
-
group_vars_files=self._group_vars_files,
|
111
|
-
omit_token=self._omit_token,
|
112
|
-
options_vars=self._options_vars,
|
113
|
-
inventory=self._inventory,
|
114
|
-
safe_basedir=self.safe_basedir,
|
115
|
-
)
|
116
|
-
return data
|
117
|
-
|
118
|
-
def __setstate__(self, data):
|
119
|
-
self._fact_cache = data.get('fact_cache', defaultdict(dict))
|
120
|
-
self._nonpersistent_fact_cache = data.get('np_fact_cache', defaultdict(dict))
|
121
|
-
self._vars_cache = data.get('vars_cache', defaultdict(dict))
|
122
|
-
self._extra_vars = data.get('extra_vars', dict())
|
123
|
-
self._host_vars_files = data.get('host_vars_files', defaultdict(dict))
|
124
|
-
self._group_vars_files = data.get('group_vars_files', defaultdict(dict))
|
125
|
-
self._omit_token = data.get('omit_token', '__omit_place_holder__%s' % sha1(os.urandom(64)).hexdigest())
|
126
|
-
self._inventory = data.get('inventory', None)
|
127
|
-
self._options_vars = data.get('options_vars', dict())
|
128
|
-
self.safe_basedir = data.get('safe_basedir', False)
|
129
|
-
self._loader = None
|
130
|
-
self._hostvars = None
|
121
|
+
# fallback to builtin memory cache plugin
|
122
|
+
display.error_as_warning(None, ex)
|
123
|
+
self._fact_cache = cache_loader.get('ansible.builtin.memory') # use FQCN to ensure the builtin version is used
|
131
124
|
|
132
125
|
@property
|
133
126
|
def extra_vars(self):
|
@@ -136,9 +129,18 @@ class VariableManager:
|
|
136
129
|
def set_inventory(self, inventory):
|
137
130
|
self._inventory = inventory
|
138
131
|
|
139
|
-
def get_vars(
|
140
|
-
|
141
|
-
|
132
|
+
def get_vars(
|
133
|
+
self,
|
134
|
+
play: Play | None = None,
|
135
|
+
host: Host | None = None,
|
136
|
+
task: Task | None = None,
|
137
|
+
include_hostvars: bool = True,
|
138
|
+
use_cache: bool = True,
|
139
|
+
_hosts: list[str] | None = None,
|
140
|
+
_hosts_all: list[str] | None = None,
|
141
|
+
stage: str = 'task',
|
142
|
+
) -> dict[str, t.Any]:
|
143
|
+
"""
|
142
144
|
Returns the variables, with optional "context" given via the parameters
|
143
145
|
for the play, host, and task (which could possibly result in different
|
144
146
|
sets of variables being returned due to the additional context).
|
@@ -146,7 +148,6 @@ class VariableManager:
|
|
146
148
|
The order of precedence is:
|
147
149
|
- play->roles->get_default_vars (if there is a play context)
|
148
150
|
- group_vars_files[host] (if there is a host context)
|
149
|
-
- host_vars_files[host] (if there is a host context)
|
150
151
|
- host->get_vars (if there is a host context)
|
151
152
|
- fact_cache[host] (if there is a host context)
|
152
153
|
- play vars (if there is a play context)
|
@@ -159,16 +160,11 @@ class VariableManager:
|
|
159
160
|
``_hosts`` and ``_hosts_all`` should be considered private args, with only internal trusted callers relying
|
160
161
|
on the functionality they provide. These arguments may be removed at a later date without a deprecation
|
161
162
|
period and without warning.
|
162
|
-
|
163
|
-
if include_delegate_to:
|
164
|
-
display.deprecated(
|
165
|
-
"`VariableManager.get_vars`'s argument `include_delegate_to` has no longer any effect.",
|
166
|
-
version="2.19",
|
167
|
-
)
|
163
|
+
"""
|
168
164
|
|
169
165
|
display.debug("in VariableManager get_vars()")
|
170
166
|
|
171
|
-
all_vars = dict()
|
167
|
+
all_vars: dict[str, t.Any] = dict()
|
172
168
|
magic_variables = self._get_magic_variables(
|
173
169
|
play=play,
|
174
170
|
host=host,
|
@@ -178,21 +174,11 @@ class VariableManager:
|
|
178
174
|
_hosts_all=_hosts_all,
|
179
175
|
)
|
180
176
|
|
181
|
-
_vars_sources = {}
|
182
|
-
|
183
177
|
def _combine_and_track(data, new_data, source):
|
184
|
-
|
185
|
-
Wrapper function to update var sources dict and call combine_vars()
|
186
|
-
|
187
|
-
See notes in the VarsWithSources docstring for caveats and limitations of the source tracking
|
188
|
-
'''
|
178
|
+
# FIXME: this no longer does any tracking, only a slight optimization for empty new_data
|
189
179
|
if new_data == {}:
|
190
180
|
return data
|
191
181
|
|
192
|
-
if C.DEFAULT_DEBUG:
|
193
|
-
# Populate var sources dict
|
194
|
-
for key in new_data:
|
195
|
-
_vars_sources[key] = source
|
196
182
|
return combine_vars(data, new_data)
|
197
183
|
|
198
184
|
# default for all cases
|
@@ -226,7 +212,7 @@ class VariableManager:
|
|
226
212
|
if host:
|
227
213
|
# THE 'all' group and the rest of groups for a host, used below
|
228
214
|
all_group = self._inventory.groups.get('all')
|
229
|
-
host_groups = sort_groups([g for g in host.get_groups() if g.name
|
215
|
+
host_groups = sort_groups([g for g in host.get_groups() if g.name != 'all'])
|
230
216
|
|
231
217
|
def _get_plugin_vars(plugin, path, entities):
|
232
218
|
data = {}
|
@@ -248,11 +234,11 @@ class VariableManager:
|
|
248
234
|
|
249
235
|
# internal functions that actually do the work
|
250
236
|
def _plugins_inventory(entities):
|
251
|
-
|
237
|
+
""" merges all entities by inventory source """
|
252
238
|
return get_vars_from_inventory_sources(self._loader, self._inventory._sources, entities, stage)
|
253
239
|
|
254
240
|
def _plugins_play(entities):
|
255
|
-
|
241
|
+
""" merges all entities adjacent to play """
|
256
242
|
data = {}
|
257
243
|
for path in basedirs:
|
258
244
|
data = _combine_and_track(data, get_vars_from_path(self._loader, path, entities, stage), "path '%s'" % path)
|
@@ -269,22 +255,22 @@ class VariableManager:
|
|
269
255
|
return _plugins_play([all_group])
|
270
256
|
|
271
257
|
def groups_inventory():
|
272
|
-
|
258
|
+
""" gets group vars from inventory """
|
273
259
|
return get_group_vars(host_groups)
|
274
260
|
|
275
261
|
def groups_plugins_inventory():
|
276
|
-
|
262
|
+
""" gets plugin sources from inventory for groups """
|
277
263
|
return _plugins_inventory(host_groups)
|
278
264
|
|
279
265
|
def groups_plugins_play():
|
280
|
-
|
266
|
+
""" gets plugin sources from play for groups """
|
281
267
|
return _plugins_play(host_groups)
|
282
268
|
|
283
269
|
def plugins_by_groups():
|
284
|
-
|
270
|
+
"""
|
285
271
|
merges all plugin sources by group,
|
286
272
|
This should be used instead, NOT in combination with the other groups_plugins* functions
|
287
|
-
|
273
|
+
"""
|
288
274
|
data = {}
|
289
275
|
for group in host_groups:
|
290
276
|
data[group] = _combine_and_track(data[group], _plugins_inventory(group), "inventory group_vars for '%s'" % group)
|
@@ -308,15 +294,20 @@ class VariableManager:
|
|
308
294
|
# finally, the facts caches for this host, if it exists
|
309
295
|
# TODO: cleaning of facts should eventually become part of taskresults instead of vars
|
310
296
|
try:
|
311
|
-
|
297
|
+
try:
|
298
|
+
facts = self._fact_cache.get(host.name)
|
299
|
+
except KeyError:
|
300
|
+
facts = {}
|
301
|
+
|
312
302
|
all_vars |= namespace_facts(facts)
|
313
303
|
|
314
304
|
# push facts to main namespace
|
315
305
|
if C.INJECT_FACTS_AS_VARS:
|
316
|
-
|
306
|
+
deprecated_facts_vars = {k: _deprecate_top_level_fact(v) for k, v in clean_facts(facts).items()}
|
307
|
+
all_vars = _combine_and_track(all_vars, deprecated_facts_vars, "facts")
|
317
308
|
else:
|
318
309
|
# always 'promote' ansible_local
|
319
|
-
all_vars = _combine_and_track(all_vars,
|
310
|
+
all_vars = _combine_and_track(all_vars, {'ansible_local': facts.get('ansible_local', {})}, "facts")
|
320
311
|
except KeyError:
|
321
312
|
pass
|
322
313
|
|
@@ -324,63 +315,68 @@ class VariableManager:
|
|
324
315
|
all_vars = _combine_and_track(all_vars, play.get_vars(), "play vars")
|
325
316
|
|
326
317
|
vars_files = play.get_vars_files()
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
except AnsibleParserError:
|
369
|
-
raise
|
370
|
-
except (UndefinedError, AnsibleUndefinedVariable):
|
371
|
-
if host is not None and self._fact_cache.get(host.name, dict()).get('module_setup') and task is not None:
|
372
|
-
raise AnsibleUndefinedVariable("an undefined variable was found when attempting to template the vars_files item '%s'"
|
373
|
-
% vars_file_item, obj=vars_file_item)
|
374
|
-
else:
|
375
|
-
# we do not have a full context here, and the missing variable could be because of that
|
376
|
-
# so just show a warning and continue
|
377
|
-
display.vvv("skipping vars_file '%s' due to an undefined variable" % vars_file_item)
|
318
|
+
|
319
|
+
for vars_file_item in vars_files:
|
320
|
+
# create a set of temporary vars here, which incorporate the extra
|
321
|
+
# and magic vars so we can properly template the vars_files entries
|
322
|
+
# NOTE: this makes them depend on host vars/facts so things like
|
323
|
+
# ansible_facts['os_distribution'] can be used, ala include_vars.
|
324
|
+
# Consider DEPRECATING this in the future, since we have include_vars ...
|
325
|
+
temp_vars = combine_vars(all_vars, self._extra_vars)
|
326
|
+
temp_vars = combine_vars(temp_vars, magic_variables)
|
327
|
+
templar = TemplateEngine(loader=self._loader, variables=temp_vars)
|
328
|
+
|
329
|
+
# we assume each item in the list is itself a list, as we
|
330
|
+
# support "conditional includes" for vars_files, which mimics
|
331
|
+
# the with_first_found mechanism.
|
332
|
+
vars_file_list = vars_file_item
|
333
|
+
if not isinstance(vars_file_list, list):
|
334
|
+
vars_file_list = [vars_file_list]
|
335
|
+
|
336
|
+
# now we iterate through the (potential) files, and break out
|
337
|
+
# as soon as we read one from the list. If none are found, we
|
338
|
+
# raise an error, which is silently ignored at this point.
|
339
|
+
try:
|
340
|
+
for vars_file in vars_file_list:
|
341
|
+
vars_file = templar.template(vars_file)
|
342
|
+
if not (isinstance(vars_file, str)):
|
343
|
+
raise AnsibleParserError(
|
344
|
+
message=f"Invalid `vars_files` value of type {native_type_name(vars_file)!r}.",
|
345
|
+
obj=vars_file,
|
346
|
+
help_text="A `vars_files` value should either be a string or list of strings.",
|
347
|
+
)
|
348
|
+
try:
|
349
|
+
play_search_stack = play.get_search_path()
|
350
|
+
found_file = self._loader.path_dwim_relative_stack(play_search_stack, 'vars', vars_file)
|
351
|
+
data = preprocess_vars(self._loader.load_from_file(found_file, unsafe=True, cache='vaulted', trusted_as_template=True))
|
352
|
+
if data is not None:
|
353
|
+
for item in data:
|
354
|
+
all_vars = _combine_and_track(all_vars, item, "play vars_files from '%s'" % vars_file)
|
355
|
+
display.vvv(f"Read `vars_file` {found_file!r}.")
|
356
|
+
break
|
357
|
+
except AnsibleFileNotFound:
|
358
|
+
# we continue on loader failures
|
378
359
|
continue
|
360
|
+
except AnsibleParserError:
|
361
|
+
raise
|
362
|
+
except AnsibleUndefinedVariable:
|
363
|
+
raise
|
364
|
+
except Exception as ex:
|
365
|
+
raise AnsibleParserError(f"Error reading `vars_files` file {vars_file!r}.", obj=vars_file) from ex
|
366
|
+
|
367
|
+
except AnsibleUndefinedVariable as ex:
|
368
|
+
if host is not None:
|
369
|
+
try:
|
370
|
+
facts = self._fact_cache.get(host.name)
|
371
|
+
except KeyError:
|
372
|
+
pass
|
373
|
+
else:
|
374
|
+
if facts.get('module_setup') and task is not None:
|
375
|
+
raise AnsibleUndefinedVariable("an undefined variable was found when attempting to template the vars_files item '%s'"
|
376
|
+
% vars_file_item, obj=vars_file_item) from ex
|
379
377
|
|
380
|
-
display.
|
381
|
-
|
382
|
-
raise AnsibleParserError("Error while reading vars files - please supply a list of file names. "
|
383
|
-
"Got '%s' of type %s" % (vars_files, type(vars_files)))
|
378
|
+
display.warning("skipping vars_file item due to an undefined variable", obj=vars_file_item)
|
379
|
+
continue
|
384
380
|
|
385
381
|
# We now merge in all exported vars from all roles in the play (very high precedence)
|
386
382
|
for role in play.roles:
|
@@ -433,17 +429,21 @@ class VariableManager:
|
|
433
429
|
all_vars['vars'] = all_vars.copy()
|
434
430
|
|
435
431
|
display.debug("done with get_vars()")
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
432
|
+
return all_vars
|
433
|
+
|
434
|
+
def _facts_gathered_for_host(self, hostname) -> bool:
|
435
|
+
try:
|
436
|
+
facts = self._fact_cache.get(hostname)
|
437
|
+
except KeyError:
|
438
|
+
facts = {}
|
439
|
+
|
440
|
+
return bool(facts.get('_ansible_facts_gathered', False))
|
441
441
|
|
442
442
|
def _get_magic_variables(self, play, host, task, include_hostvars, _hosts=None, _hosts_all=None):
|
443
|
-
|
443
|
+
"""
|
444
444
|
Returns a dictionary of so-called "magic" variables in Ansible,
|
445
445
|
which are special variables we set internally for use.
|
446
|
-
|
446
|
+
"""
|
447
447
|
|
448
448
|
variables = {}
|
449
449
|
variables['playbook_dir'] = os.path.abspath(self._loader.get_basedir())
|
@@ -480,13 +480,13 @@ class VariableManager:
|
|
480
480
|
if self._inventory is not None:
|
481
481
|
variables['groups'] = self._inventory.get_groups_dict()
|
482
482
|
if play:
|
483
|
-
templar = Templar(loader=self._loader)
|
484
|
-
if not play.finalized and templar.is_template(play.hosts):
|
485
|
-
pattern = 'all'
|
486
|
-
else:
|
487
|
-
pattern = play.hosts or 'all'
|
488
483
|
# add the list of hosts in the play, as adjusted for limit/filters
|
489
484
|
if not _hosts_all:
|
485
|
+
if not play.finalized and TemplateEngine().is_template(play.hosts):
|
486
|
+
pattern = 'all'
|
487
|
+
else:
|
488
|
+
pattern = play.hosts or 'all'
|
489
|
+
|
490
490
|
_hosts_all = [h.name for h in self._inventory.get_hosts(pattern=pattern, ignore_restrictions=True)]
|
491
491
|
if not _hosts:
|
492
492
|
_hosts = [h.name for h in self._inventory.get_hosts()]
|
@@ -495,12 +495,12 @@ class VariableManager:
|
|
495
495
|
variables['ansible_play_hosts'] = [x for x in variables['ansible_play_hosts_all'] if x not in play._removed_hosts]
|
496
496
|
variables['ansible_play_batch'] = [x for x in _hosts if x not in play._removed_hosts]
|
497
497
|
|
498
|
-
|
499
|
-
|
500
|
-
|
498
|
+
variables['play_hosts'] = deprecate_value(
|
499
|
+
value=variables['ansible_play_batch'],
|
500
|
+
msg='Use `ansible_play_batch` instead of `play_hosts`.',
|
501
|
+
removal_version='2.23',
|
502
|
+
)
|
501
503
|
|
502
|
-
# the 'omit' value allows params to be left out if the variable they are based on is undefined
|
503
|
-
variables['omit'] = self._omit_token
|
504
504
|
# Set options vars
|
505
505
|
for option, option_value in self._options_vars.items():
|
506
506
|
variables[option] = option_value
|
@@ -517,56 +517,64 @@ class VariableManager:
|
|
517
517
|
Not used directly be VariableManager, but used primarily within TaskExecutor
|
518
518
|
"""
|
519
519
|
delegated_vars = {}
|
520
|
-
delegated_host_name = None
|
521
|
-
if task.delegate_to:
|
522
|
-
delegated_host_name = templar.template(task.delegate_to, fail_on_undefined=False)
|
520
|
+
delegated_host_name = ... # sentinel value distinct from empty/None, which are errors
|
523
521
|
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
522
|
+
if task.delegate_to:
|
523
|
+
try:
|
524
|
+
delegated_host_name = templar.template(task.delegate_to)
|
525
|
+
except AnsibleValueOmittedError:
|
526
|
+
pass
|
529
527
|
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
528
|
+
# bypass for unspecified value/omit
|
529
|
+
if delegated_host_name is ...:
|
530
|
+
return delegated_vars, None
|
531
|
+
|
532
|
+
if not delegated_host_name:
|
533
|
+
raise AnsibleError('Empty hostname produced from delegate_to: "%s"' % task.delegate_to)
|
534
|
+
|
535
|
+
delegated_host = self._inventory.get_host(delegated_host_name)
|
536
|
+
if delegated_host is None:
|
537
|
+
for h in self._inventory.get_hosts(ignore_limits=True, ignore_restrictions=True):
|
538
|
+
# check if the address matches, or if both the delegated_to host
|
539
|
+
# and the current host are in the list of localhost aliases
|
540
|
+
if h.address == delegated_host_name:
|
541
|
+
delegated_host = h
|
542
|
+
break
|
543
|
+
else:
|
544
|
+
delegated_host = Host(name=delegated_host_name)
|
545
|
+
|
546
|
+
delegated_vars['ansible_delegated_vars'] = {
|
547
|
+
delegated_host_name: self.get_vars(
|
548
|
+
play=task.get_play(),
|
549
|
+
host=delegated_host,
|
550
|
+
task=task,
|
551
|
+
include_hostvars=True,
|
552
|
+
)
|
553
|
+
}
|
554
|
+
delegated_vars['ansible_delegated_vars'][delegated_host_name]['inventory_hostname'] = variables.get('inventory_hostname')
|
550
555
|
|
551
556
|
return delegated_vars, delegated_host_name
|
552
557
|
|
553
558
|
def clear_facts(self, hostname):
|
554
|
-
|
559
|
+
"""
|
555
560
|
Clears the facts for a host
|
556
|
-
|
557
|
-
|
561
|
+
"""
|
562
|
+
try:
|
563
|
+
self._fact_cache.delete(hostname)
|
564
|
+
except KeyError:
|
565
|
+
pass
|
558
566
|
|
559
567
|
def set_host_facts(self, host, facts):
|
560
|
-
|
568
|
+
"""
|
561
569
|
Sets or updates the given facts for a host in the fact cache.
|
562
|
-
|
570
|
+
"""
|
563
571
|
|
564
572
|
if not isinstance(facts, Mapping):
|
565
573
|
raise AnsibleAssertionError("the type of 'facts' to set for host_facts should be a Mapping but is a %s" % type(facts))
|
566
574
|
|
567
575
|
warn_if_reserved(facts.keys())
|
568
576
|
try:
|
569
|
-
host_cache = self._fact_cache
|
577
|
+
host_cache = self._fact_cache.get(host)
|
570
578
|
except KeyError:
|
571
579
|
# We get to set this as new
|
572
580
|
host_cache = facts
|
@@ -578,12 +586,12 @@ class VariableManager:
|
|
578
586
|
host_cache |= facts
|
579
587
|
|
580
588
|
# Save the facts back to the backing store
|
581
|
-
self._fact_cache
|
589
|
+
self._fact_cache.set(host, host_cache)
|
582
590
|
|
583
591
|
def set_nonpersistent_facts(self, host, facts):
|
584
|
-
|
592
|
+
"""
|
585
593
|
Sets or updates the given facts for a host in the fact cache.
|
586
|
-
|
594
|
+
"""
|
587
595
|
|
588
596
|
if not isinstance(facts, Mapping):
|
589
597
|
raise AnsibleAssertionError("the type of 'facts' to set for nonpersistent_facts should be a Mapping but is a %s" % type(facts))
|
@@ -602,75 +610,8 @@ class VariableManager:
|
|
602
610
|
warn_if_reserved([varname])
|
603
611
|
if host not in self._vars_cache:
|
604
612
|
self._vars_cache[host] = dict()
|
613
|
+
|
605
614
|
if varname in self._vars_cache[host] and isinstance(self._vars_cache[host][varname], MutableMapping) and isinstance(value, MutableMapping):
|
606
615
|
self._vars_cache[host] = combine_vars(self._vars_cache[host], {varname: value})
|
607
616
|
else:
|
608
617
|
self._vars_cache[host][varname] = value
|
609
|
-
|
610
|
-
|
611
|
-
class VarsWithSources(MutableMapping):
|
612
|
-
'''
|
613
|
-
Dict-like class for vars that also provides source information for each var
|
614
|
-
|
615
|
-
This class can only store the source for top-level vars. It does no tracking
|
616
|
-
on its own, just shows a debug message with the information that it is provided
|
617
|
-
when a particular var is accessed.
|
618
|
-
'''
|
619
|
-
def __init__(self, *args, **kwargs):
|
620
|
-
''' Dict-compatible constructor '''
|
621
|
-
self.data = dict(*args, **kwargs)
|
622
|
-
self.sources = {}
|
623
|
-
|
624
|
-
@classmethod
|
625
|
-
def new_vars_with_sources(cls, data, sources):
|
626
|
-
''' Alternate constructor method to instantiate class with sources '''
|
627
|
-
v = cls(data)
|
628
|
-
v.sources = sources
|
629
|
-
return v
|
630
|
-
|
631
|
-
def get_source(self, key):
|
632
|
-
return self.sources.get(key, None)
|
633
|
-
|
634
|
-
def __getitem__(self, key):
|
635
|
-
val = self.data[key]
|
636
|
-
# See notes in the VarsWithSources docstring for caveats and limitations of the source tracking
|
637
|
-
display.debug("variable '%s' from source: %s" % (key, self.sources.get(key, "unknown")))
|
638
|
-
return val
|
639
|
-
|
640
|
-
def __setitem__(self, key, value):
|
641
|
-
self.data[key] = value
|
642
|
-
|
643
|
-
def __delitem__(self, key):
|
644
|
-
del self.data[key]
|
645
|
-
|
646
|
-
def __iter__(self):
|
647
|
-
return iter(self.data)
|
648
|
-
|
649
|
-
def __len__(self):
|
650
|
-
return len(self.data)
|
651
|
-
|
652
|
-
# Prevent duplicate debug messages by defining our own __contains__ pointing at the underlying dict
|
653
|
-
def __contains__(self, key):
|
654
|
-
return self.data.__contains__(key)
|
655
|
-
|
656
|
-
def copy(self):
|
657
|
-
return VarsWithSources.new_vars_with_sources(self.data.copy(), self.sources.copy())
|
658
|
-
|
659
|
-
def __or__(self, other):
|
660
|
-
if isinstance(other, MutableMapping):
|
661
|
-
c = self.data.copy()
|
662
|
-
c.update(other)
|
663
|
-
return c
|
664
|
-
return NotImplemented
|
665
|
-
|
666
|
-
def __ror__(self, other):
|
667
|
-
if isinstance(other, MutableMapping):
|
668
|
-
c = self.__class__()
|
669
|
-
c.update(other)
|
670
|
-
c.update(self.data)
|
671
|
-
return c
|
672
|
-
return NotImplemented
|
673
|
-
|
674
|
-
def __ior__(self, other):
|
675
|
-
self.data.update(other)
|
676
|
-
return self.data
|