ansible-core 2.18.5rc1__py3-none-any.whl → 2.19.0b2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ansible/_internal/__init__.py +53 -0
- ansible/_internal/_ansiballz.py +265 -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/_captured.py +128 -0
- ansible/_internal/_errors/_handler.py +91 -0
- ansible/_internal/_errors/_utils.py +310 -0
- ansible/_internal/_json/__init__.py +203 -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 +197 -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 +345 -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 +159 -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 +62 -53
- 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 +166 -112
- 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 +161 -96
- ansible/executor/stats.py +5 -5
- ansible/executor/task_executor.py +268 -258
- ansible/executor/task_queue_manager.py +124 -90
- ansible/executor/task_result.py +183 -78
- 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 +78 -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 +152 -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/jsonify.py +5 -1
- 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 +43 -335
- 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 +31 -27
- 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 +284 -179
- ansible/plugins/callback/default.py +99 -92
- ansible/plugins/callback/junit.py +44 -39
- ansible/plugins/callback/minimal.py +28 -25
- ansible/plugins/callback/oneline.py +28 -21
- ansible/plugins/callback/tree.py +16 -11
- 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 +225 -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 +159 -184
- 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 +55 -21
- 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 +370 -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 +433 -63
- 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 +51 -8
- ansible/utils/version.py +2 -2
- ansible/vars/clean.py +5 -5
- ansible/vars/hostvars.py +60 -90
- ansible/vars/manager.py +206 -282
- ansible/vars/reserved.py +8 -9
- ansible_core-2.19.0b2.dist-info/BSD-3-Clause.txt +28 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/METADATA +5 -4
- ansible_core-2.19.0b2.dist-info/RECORD +1072 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.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/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.0b2.dist-info}/Apache-License.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/COPYING +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/MIT-license.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/PSF-license.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/simplified_bsd.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/top_level.txt +0 -0
ansible/plugins/lookup/config.py
CHANGED
@@ -83,32 +83,20 @@ _raw:
|
|
83
83
|
import ansible.plugins.loader as plugin_loader
|
84
84
|
|
85
85
|
from ansible import constants as C
|
86
|
-
from ansible.
|
87
|
-
from ansible.
|
88
|
-
from ansible.module_utils.six import string_types
|
86
|
+
from ansible.module_utils.common.sentinel import Sentinel
|
87
|
+
from ansible.errors import AnsibleError, AnsibleUndefinedConfigEntry
|
89
88
|
from ansible.plugins.lookup import LookupBase
|
90
|
-
from ansible.utils.sentinel import Sentinel
|
91
89
|
|
92
90
|
|
93
|
-
|
94
|
-
|
91
|
+
def _get_plugin_config(pname, ptype, config, variables):
|
92
|
+
# plugin creates settings on load, this is cached so not too expensive to redo
|
93
|
+
loader = getattr(plugin_loader, '%s_loader' % ptype)
|
94
|
+
p = loader.get(pname, class_only=True)
|
95
95
|
|
96
|
+
if p is None:
|
97
|
+
raise AnsibleError(f"Unable to load {ptype} plugin {pname!r}.")
|
96
98
|
|
97
|
-
|
98
|
-
try:
|
99
|
-
# plugin creates settings on load, this is cached so not too expensive to redo
|
100
|
-
loader = getattr(plugin_loader, '%s_loader' % ptype)
|
101
|
-
p = loader.get(pname, class_only=True)
|
102
|
-
if p is None:
|
103
|
-
raise AnsibleLookupError('Unable to load %s plugin "%s"' % (ptype, pname))
|
104
|
-
result, origin = C.config.get_config_value_and_origin(config, plugin_type=ptype, plugin_name=p._load_name, variables=variables)
|
105
|
-
except AnsibleLookupError:
|
106
|
-
raise
|
107
|
-
except AnsibleError as e:
|
108
|
-
msg = to_native(e)
|
109
|
-
if 'was not defined' in msg:
|
110
|
-
raise MissingSetting(msg, orig_exc=e)
|
111
|
-
raise e
|
99
|
+
result, origin = C.config.get_config_value_and_origin(config, plugin_type=ptype, plugin_name=p._load_name, variables=variables)
|
112
100
|
|
113
101
|
return result, origin
|
114
102
|
|
@@ -116,10 +104,11 @@ def _get_plugin_config(pname, ptype, config, variables):
|
|
116
104
|
def _get_global_config(config):
|
117
105
|
try:
|
118
106
|
result = getattr(C, config)
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
107
|
+
except AttributeError:
|
108
|
+
raise AnsibleUndefinedConfigEntry(f"Setting {config!r} does not exist.") from None
|
109
|
+
|
110
|
+
if callable(result):
|
111
|
+
raise ValueError(f"Invalid setting {config!r} attempted.")
|
123
112
|
|
124
113
|
return result
|
125
114
|
|
@@ -136,16 +125,13 @@ class LookupModule(LookupBase):
|
|
136
125
|
show_origin = self.get_option('show_origin')
|
137
126
|
|
138
127
|
if (ptype or pname) and not (ptype and pname):
|
139
|
-
raise
|
140
|
-
|
141
|
-
if not isinstance(missing, string_types) or missing not in ['error', 'warn', 'skip']:
|
142
|
-
raise AnsibleOptionsError('"on_missing" must be a string and one of "error", "warn" or "skip", not %s' % missing)
|
128
|
+
raise AnsibleError('Both plugin_type and plugin_name are required, cannot use one without the other.')
|
143
129
|
|
144
130
|
ret = []
|
145
131
|
|
146
132
|
for term in terms:
|
147
|
-
if not isinstance(term,
|
148
|
-
raise
|
133
|
+
if not isinstance(term, str):
|
134
|
+
raise AnsibleError(f'Invalid setting identifier, {term!r} is not a {str}, its a {type(term)}.')
|
149
135
|
|
150
136
|
result = Sentinel
|
151
137
|
origin = None
|
@@ -154,17 +140,17 @@ class LookupModule(LookupBase):
|
|
154
140
|
result, origin = _get_plugin_config(pname, ptype, term, variables)
|
155
141
|
else:
|
156
142
|
result = _get_global_config(term)
|
157
|
-
except
|
143
|
+
except AnsibleUndefinedConfigEntry:
|
158
144
|
if missing == 'error':
|
159
|
-
raise
|
145
|
+
raise
|
160
146
|
elif missing == 'warn':
|
161
|
-
self._display.warning(
|
147
|
+
self._display.warning(f"Skipping, did not find setting {term!r}.")
|
162
148
|
elif missing == 'skip':
|
163
149
|
pass # this is not needed, but added to have all 3 options stated
|
164
150
|
|
165
151
|
if result is not Sentinel:
|
166
152
|
if show_origin:
|
167
|
-
ret.append(
|
153
|
+
ret.append([result, origin])
|
168
154
|
else:
|
169
155
|
ret.append(result)
|
170
156
|
return ret
|
@@ -16,7 +16,8 @@ DOCUMENTATION = r"""
|
|
16
16
|
options:
|
17
17
|
col:
|
18
18
|
description: column to return (0 indexed).
|
19
|
-
default:
|
19
|
+
default: 1
|
20
|
+
type: int
|
20
21
|
keycol:
|
21
22
|
description: column to search in (0 indexed).
|
22
23
|
default: 0
|
@@ -164,7 +165,7 @@ class LookupModule(LookupBase):
|
|
164
165
|
|
165
166
|
for row in creader:
|
166
167
|
if len(row) and row[keycol] == key:
|
167
|
-
return row[
|
168
|
+
return row[col]
|
168
169
|
except Exception as e:
|
169
170
|
raise AnsibleError("csvfile: %s" % to_native(e))
|
170
171
|
|
ansible/plugins/lookup/dict.py
CHANGED
@@ -61,16 +61,11 @@ from ansible.plugins.lookup import LookupBase
|
|
61
61
|
class LookupModule(LookupBase):
|
62
62
|
|
63
63
|
def run(self, terms, variables=None, **kwargs):
|
64
|
-
|
65
|
-
# NOTE: can remove if with_ is removed
|
66
|
-
if not isinstance(terms, list):
|
67
|
-
terms = [terms]
|
68
|
-
|
69
64
|
results = []
|
70
65
|
for term in terms:
|
71
66
|
# Expect any type of Mapping, notably hostvars
|
72
67
|
if not isinstance(term, Mapping):
|
73
|
-
raise AnsibleError("
|
68
|
+
raise AnsibleError(f"the 'dict' lookup plugin expects a dictionary, got '{term}' of type {type(term)})")
|
74
69
|
|
75
70
|
results.extend(self._flatten_hash_to_list(term))
|
76
71
|
return results
|
ansible/plugins/lookup/env.py
CHANGED
@@ -38,10 +38,6 @@ EXAMPLES = """
|
|
38
38
|
ansible.builtin.debug:
|
39
39
|
msg: "Hello {{ lookup('ansible.builtin.env', 'UNDEFINED_VARIABLE', default='World') }}"
|
40
40
|
|
41
|
-
- name: Fail if the variable is not defined by setting default value to 'Undefined'
|
42
|
-
ansible.builtin.debug:
|
43
|
-
msg: "Hello {{ lookup('ansible.builtin.env', 'UNDEFINED_VARIABLE', default=Undefined) }}"
|
44
|
-
|
45
41
|
- name: Fail if the variable is not defined by setting default value to 'undef()'
|
46
42
|
ansible.builtin.debug:
|
47
43
|
msg: "Hello {{ lookup('ansible.builtin.env', 'UNDEFINED_VARIABLE', default=undef()) }}"
|
@@ -56,23 +52,30 @@ RETURN = """
|
|
56
52
|
|
57
53
|
import os
|
58
54
|
|
59
|
-
from jinja2.runtime import Undefined
|
60
55
|
|
61
|
-
from ansible.errors import AnsibleUndefinedVariable
|
62
56
|
from ansible.plugins.lookup import LookupBase
|
57
|
+
from ansible._internal._templating._jinja_bits import _undef, _DEFAULT_UNDEF
|
58
|
+
from ansible._internal._datatag._tags import Origin
|
63
59
|
|
64
60
|
|
65
61
|
class LookupModule(LookupBase):
|
66
|
-
|
62
|
+
accept_args_markers = True # the `default` arg can accept undefined values
|
67
63
|
|
64
|
+
def run(self, terms, variables=None, **kwargs):
|
68
65
|
self.set_options(var_options=variables, direct=kwargs)
|
69
66
|
|
70
67
|
ret = []
|
71
68
|
d = self.get_option('default')
|
69
|
+
|
72
70
|
for term in terms:
|
73
71
|
var = term.split()[0]
|
74
72
|
val = os.environ.get(var, d)
|
75
|
-
|
76
|
-
|
73
|
+
|
74
|
+
if val is _DEFAULT_UNDEF:
|
75
|
+
val = _undef(f'The environment variable {var!r} is not set.')
|
76
|
+
else:
|
77
|
+
val = Origin(description=f"<environment variable {var!r}>").try_tag(val)
|
78
|
+
|
77
79
|
ret.append(val)
|
80
|
+
|
78
81
|
return ret
|
ansible/plugins/lookup/file.py
CHANGED
@@ -25,7 +25,6 @@ DOCUMENTATION = """
|
|
25
25
|
required: False
|
26
26
|
default: False
|
27
27
|
notes:
|
28
|
-
- if read in variable context, the file can be interpreted as YAML if the content is valid to the parser.
|
29
28
|
- this lookup does not understand 'globbing', use the fileglob lookup instead.
|
30
29
|
seealso:
|
31
30
|
- ref: playbook_task_paths
|
@@ -52,9 +51,8 @@ RETURN = """
|
|
52
51
|
elements: str
|
53
52
|
"""
|
54
53
|
|
55
|
-
from ansible.errors import AnsibleError
|
54
|
+
from ansible.errors import AnsibleError
|
56
55
|
from ansible.plugins.lookup import LookupBase
|
57
|
-
from ansible.module_utils.common.text.converters import to_text
|
58
56
|
from ansible.utils.display import Display
|
59
57
|
|
60
58
|
display = Display()
|
@@ -74,8 +72,7 @@ class LookupModule(LookupBase):
|
|
74
72
|
lookupfile = self.find_file_in_search_path(variables, 'files', term, ignore_missing=True)
|
75
73
|
display.vvvv(u"File lookup using %s as file" % lookupfile)
|
76
74
|
if lookupfile:
|
77
|
-
|
78
|
-
contents = to_text(b_contents, errors='surrogate_or_strict')
|
75
|
+
contents = self._loader.get_text_file_contents(lookupfile)
|
79
76
|
if self.get_option('lstrip'):
|
80
77
|
contents = contents.lstrip()
|
81
78
|
if self.get_option('rstrip'):
|
@@ -83,8 +80,8 @@ class LookupModule(LookupBase):
|
|
83
80
|
ret.append(contents)
|
84
81
|
else:
|
85
82
|
# TODO: only add search info if abs path?
|
86
|
-
raise
|
87
|
-
except AnsibleError as
|
88
|
-
raise
|
83
|
+
raise AnsibleError("File not found. Use -vvvvv to see paths searched.")
|
84
|
+
except AnsibleError as ex:
|
85
|
+
raise AnsibleError(f"Unable to access the file {term!r}.") from ex
|
89
86
|
|
90
87
|
return ret
|
@@ -40,15 +40,16 @@ DOCUMENTATION = """
|
|
40
40
|
- When used as a template via C(lookup) or C(query), setting O(skip=True) will *not* cause the task to skip.
|
41
41
|
Tasks must handle the empty list return from the template.
|
42
42
|
- When V(False) and C(lookup) or C(query) specifies O(ignore:errors='ignore') all errors (including no file found,
|
43
|
-
but potentially others) return
|
43
|
+
but potentially others) return V(None) or an empty list respectively.
|
44
44
|
- When V(True) and C(lookup) or C(query) specifies O(ignore:errors='ignore'), no file found will return an empty
|
45
|
-
list and other potential errors return
|
45
|
+
list and other potential errors return V(None) or empty list depending on the template call
|
46
46
|
(in other words return values of C(lookup) vs C(query)).
|
47
47
|
seealso:
|
48
48
|
- ref: playbook_task_paths
|
49
49
|
description: Search paths used for relative paths/files.
|
50
50
|
"""
|
51
51
|
|
52
|
+
|
52
53
|
EXAMPLES = """
|
53
54
|
- name: Set _found_file to the first existing file, raising an error if a file is not found
|
54
55
|
ansible.builtin.set_fact:
|
@@ -137,70 +138,76 @@ RETURN = """
|
|
137
138
|
type: list
|
138
139
|
elements: path
|
139
140
|
"""
|
140
|
-
import os
|
141
|
-
|
142
|
-
from collections.abc import Mapping, Sequence
|
143
141
|
|
144
|
-
|
142
|
+
import collections.abc as c
|
143
|
+
import os
|
144
|
+
import re
|
145
|
+
import typing as t
|
145
146
|
|
146
|
-
from ansible.
|
147
|
-
from ansible.
|
147
|
+
from ansible._internal import _task
|
148
|
+
from ansible.errors import AnsibleError
|
148
149
|
from ansible.plugins.lookup import LookupBase
|
150
|
+
from ansible._internal._templating import _jinja_common
|
151
|
+
from ansible._internal._templating import _jinja_plugins
|
149
152
|
from ansible.utils.path import unfrackpath
|
153
|
+
from ansible.utils.display import Display
|
154
|
+
from ansible.module_utils.datatag import native_type_name
|
155
|
+
|
150
156
|
|
157
|
+
def _split_on(target: str, terms: str | list[str], splitters: str) -> list[str]:
|
158
|
+
termlist: list[str] = []
|
151
159
|
|
152
|
-
|
153
|
-
|
154
|
-
v = ''
|
155
|
-
for c in value:
|
156
|
-
if c in chars:
|
157
|
-
yield v
|
158
|
-
v = ''
|
159
|
-
continue
|
160
|
-
v += c
|
161
|
-
yield v
|
160
|
+
if isinstance(terms, str):
|
161
|
+
split_terms = re.split(r'[%s]' % ''.join(map(re.escape, splitters)), terms)
|
162
162
|
|
163
|
+
if split_terms == [terms]:
|
164
|
+
termlist = [terms]
|
165
|
+
else:
|
166
|
+
Display().deprecated(
|
167
|
+
msg=f'Automatic splitting of {target} on {splitters!r} is deprecated.',
|
168
|
+
help_text=f'Provide a list of paths for {target} instead.',
|
169
|
+
version='2.23',
|
170
|
+
obj=terms,
|
171
|
+
)
|
163
172
|
|
164
|
-
|
165
|
-
termlist = []
|
166
|
-
if isinstance(terms, string_types):
|
167
|
-
termlist = list(_splitter(terms, spliters))
|
173
|
+
termlist = split_terms
|
168
174
|
else:
|
169
175
|
# added since options will already listify
|
170
|
-
for
|
171
|
-
termlist.extend(_split_on(
|
176
|
+
for term in terms:
|
177
|
+
termlist.extend(_split_on(target, term, splitters))
|
178
|
+
|
172
179
|
return termlist
|
173
180
|
|
174
181
|
|
175
182
|
class LookupModule(LookupBase):
|
183
|
+
accept_args_markers = True # terms are allowed to be undefined
|
184
|
+
accept_lazy_markers = True # terms are allowed to be undefined
|
176
185
|
|
177
|
-
def _process_terms(self, terms, variables,
|
186
|
+
def _process_terms(self, terms: c.Sequence, variables: dict[str, t.Any]) -> list[str]:
|
178
187
|
|
179
188
|
total_search = []
|
180
|
-
skip = False
|
181
189
|
|
182
190
|
# can use a dict instead of list item to pass inline config
|
183
191
|
for term in terms:
|
184
|
-
if isinstance(term, Mapping):
|
192
|
+
if isinstance(term, c.Mapping):
|
185
193
|
self.set_options(var_options=variables, direct=term)
|
186
194
|
files = self.get_option('files')
|
187
|
-
|
195
|
+
files_description = "the 'files' option"
|
196
|
+
elif isinstance(term, str):
|
188
197
|
files = [term]
|
189
|
-
|
190
|
-
|
198
|
+
files_description = "files"
|
199
|
+
elif isinstance(term, c.Sequence):
|
200
|
+
partial = self._process_terms(term, variables)
|
191
201
|
total_search.extend(partial)
|
192
202
|
continue
|
193
203
|
else:
|
194
|
-
raise
|
204
|
+
raise AnsibleError(f"Invalid term supplied. A string, dict or list is required, not {native_type_name(term)!r}).")
|
195
205
|
|
196
206
|
paths = self.get_option('paths')
|
197
207
|
|
198
|
-
# NOTE: this is used as 'global' but can be set many times?!?!?
|
199
|
-
skip = self.get_option('skip')
|
200
|
-
|
201
208
|
# magic extra splitting to create lists
|
202
|
-
filelist = _split_on(files, ',;')
|
203
|
-
pathlist = _split_on(paths, ',:;')
|
209
|
+
filelist = _split_on(files_description, files, ',;')
|
210
|
+
pathlist = _split_on('the "paths" option', paths, ',:;')
|
204
211
|
|
205
212
|
# create search structure
|
206
213
|
if pathlist:
|
@@ -208,40 +215,46 @@ class LookupModule(LookupBase):
|
|
208
215
|
for fn in filelist:
|
209
216
|
f = os.path.join(path, fn)
|
210
217
|
total_search.append(f)
|
211
|
-
|
218
|
+
else:
|
212
219
|
# NOTE: this is now 'extend', previously it would clobber all options, but we deemed that a bug
|
213
220
|
total_search.extend(filelist)
|
214
|
-
else:
|
215
|
-
total_search.append(term)
|
216
221
|
|
217
|
-
return total_search
|
222
|
+
return total_search
|
223
|
+
|
224
|
+
def run(self, terms: list, variables=None, **kwargs):
|
225
|
+
if (first_marker := _jinja_common.get_first_marker_arg((), kwargs)) is not None:
|
226
|
+
first_marker.trip()
|
218
227
|
|
219
|
-
|
228
|
+
if _jinja_plugins._LookupContext.current().invoked_as_with:
|
229
|
+
# we're being invoked by TaskExecutor.get_loop_items(), special backwards compatibility behavior
|
230
|
+
terms = _recurse_terms(terms, omit_undefined=True) # recursively drop undefined values from terms for backwards compatibility
|
231
|
+
|
232
|
+
# invoked_as_with shouldn't be possible outside a TaskContext
|
233
|
+
te_action = _task.TaskContext.current().task.action # FIXME: this value has not been templated, it should be (historical problem)...
|
234
|
+
|
235
|
+
# based on the presence of `var`/`template`/`file` in the enclosing task action name, choose a subdir to search
|
236
|
+
for subdir in ['template', 'var', 'file']:
|
237
|
+
if subdir in te_action:
|
238
|
+
break
|
239
|
+
|
240
|
+
subdir += "s" # convert to the matching directory name
|
241
|
+
else:
|
242
|
+
terms = _recurse_terms(terms, omit_undefined=False) # undefined values are only omitted when invoked using `with`
|
243
|
+
|
244
|
+
subdir = None
|
220
245
|
|
221
246
|
self.set_options(var_options=variables, direct=kwargs)
|
222
247
|
|
223
248
|
if not terms:
|
224
249
|
terms = self.get_option('files')
|
225
250
|
|
226
|
-
total_search
|
251
|
+
total_search = self._process_terms(terms, variables)
|
227
252
|
|
228
253
|
# NOTE: during refactor noticed that the 'using a dict' as term
|
229
254
|
# is designed to only work with 'one' otherwise inconsistencies will appear.
|
230
255
|
# see other notes below.
|
231
256
|
|
232
|
-
# actually search
|
233
|
-
subdir = getattr(self, '_subdir', 'files')
|
234
|
-
|
235
|
-
path = None
|
236
257
|
for fn in total_search:
|
237
|
-
|
238
|
-
try:
|
239
|
-
fn = self._templar.template(fn)
|
240
|
-
except (AnsibleUndefinedVariable, UndefinedError):
|
241
|
-
# NOTE: backwards compat ff behaviour is to ignore errors when vars are undefined.
|
242
|
-
# moved here from task_executor.
|
243
|
-
continue
|
244
|
-
|
245
258
|
# get subdir if set by task executor, default to files otherwise
|
246
259
|
path = self.find_file_in_search_path(variables, subdir, fn, ignore_missing=True)
|
247
260
|
|
@@ -249,8 +262,26 @@ class LookupModule(LookupBase):
|
|
249
262
|
if path is not None:
|
250
263
|
return [unfrackpath(path, follow=False)]
|
251
264
|
|
265
|
+
skip = self.get_option('skip')
|
266
|
+
|
252
267
|
# if we get here, no file was found
|
253
268
|
if skip:
|
254
269
|
# NOTE: global skip won't matter, only last 'skip' value in dict term
|
255
270
|
return []
|
256
|
-
|
271
|
+
|
272
|
+
raise AnsibleError("No file was found when using first_found.")
|
273
|
+
|
274
|
+
|
275
|
+
def _recurse_terms(o: t.Any, omit_undefined: bool) -> t.Any:
|
276
|
+
"""Recurse through supported container types, optionally omitting undefined markers and tripping all remaining markers, returning the result."""
|
277
|
+
match o:
|
278
|
+
case dict():
|
279
|
+
return {k: _recurse_terms(v, omit_undefined) for k, v in o.items() if not (omit_undefined and isinstance(v, _jinja_common.UndefinedMarker))}
|
280
|
+
case list():
|
281
|
+
return [_recurse_terms(v, omit_undefined) for v in o if not (omit_undefined and isinstance(v, _jinja_common.UndefinedMarker))]
|
282
|
+
case tuple():
|
283
|
+
return tuple(_recurse_terms(v, omit_undefined) for v in o if not (omit_undefined and isinstance(v, _jinja_common.UndefinedMarker)))
|
284
|
+
case _jinja_common.Marker():
|
285
|
+
o.trip()
|
286
|
+
case _:
|
287
|
+
return o
|
@@ -33,19 +33,10 @@ RETURN = """
|
|
33
33
|
elements: list
|
34
34
|
"""
|
35
35
|
|
36
|
-
from ansible.errors import AnsibleError
|
37
36
|
from ansible.plugins.lookup import LookupBase
|
38
37
|
|
39
38
|
|
40
39
|
class LookupModule(LookupBase):
|
41
|
-
|
42
|
-
def __init__(self, basedir=None, **kwargs):
|
43
|
-
self.basedir = basedir
|
44
|
-
|
45
|
-
def run(self, terms, variables, **kwargs):
|
46
|
-
|
47
|
-
if not isinstance(terms, list):
|
48
|
-
raise AnsibleError("with_indexed_items expects a list")
|
49
|
-
|
40
|
+
def run(self, terms, variables=None, **kwargs):
|
50
41
|
items = self._flatten(terms)
|
51
42
|
return list(zip(range(len(items)), items))
|
ansible/plugins/lookup/ini.py
CHANGED
@@ -92,13 +92,13 @@ from io import StringIO
|
|
92
92
|
from collections import defaultdict
|
93
93
|
from collections.abc import MutableSequence
|
94
94
|
|
95
|
-
from ansible.errors import
|
96
|
-
from ansible.module_utils.common.text.converters import
|
95
|
+
from ansible.errors import AnsibleError
|
96
|
+
from ansible.module_utils.common.text.converters import to_native
|
97
97
|
from ansible.plugins.lookup import LookupBase
|
98
98
|
|
99
99
|
|
100
100
|
def _parse_params(term, paramvals):
|
101
|
-
|
101
|
+
"""Safely split parameter term to preserve spaces"""
|
102
102
|
|
103
103
|
# TODO: deprecate this method
|
104
104
|
valid_keys = paramvals.keys()
|
@@ -161,6 +161,7 @@ class LookupModule(LookupBase):
|
|
161
161
|
if '=' in term or ' ' in term.strip():
|
162
162
|
self._deprecate_inline_kv()
|
163
163
|
params = _parse_params(term, paramvals)
|
164
|
+
param = None
|
164
165
|
try:
|
165
166
|
updated_key = False
|
166
167
|
updated_options = False
|
@@ -168,7 +169,7 @@ class LookupModule(LookupBase):
|
|
168
169
|
if '=' in param:
|
169
170
|
name, value = param.split('=')
|
170
171
|
if name not in paramvals:
|
171
|
-
raise
|
172
|
+
raise AnsibleError(f"{name!r} is not a valid option.")
|
172
173
|
self.set_option(name, value)
|
173
174
|
updated_options = True
|
174
175
|
elif key == term:
|
@@ -177,11 +178,11 @@ class LookupModule(LookupBase):
|
|
177
178
|
updated_key = True
|
178
179
|
if updated_options:
|
179
180
|
paramvals = self.get_options()
|
180
|
-
except ValueError as
|
181
|
+
except ValueError as ex:
|
181
182
|
# bad params passed
|
182
|
-
raise
|
183
|
+
raise ValueError(f"Could not use {param!r} from {params!r}.") from ex
|
183
184
|
if not updated_key:
|
184
|
-
raise
|
185
|
+
raise ValueError(f"No key to look up was provided as first term within string inline options: {term}")
|
185
186
|
# only passed options in inline string
|
186
187
|
|
187
188
|
# TODO: look to use cache to avoid redoing this for every term if they use same file
|
@@ -195,25 +196,25 @@ class LookupModule(LookupBase):
|
|
195
196
|
config.write(u'[java_properties]\n')
|
196
197
|
paramvals['section'] = 'java_properties'
|
197
198
|
|
198
|
-
|
199
|
-
contents, show_data = self._loader._get_file_contents(path)
|
200
|
-
contents = to_text(contents, errors='surrogate_or_strict', encoding=paramvals['encoding'])
|
199
|
+
contents = self._loader.get_text_file_contents(path, encoding=paramvals['encoding'])
|
201
200
|
config.write(contents)
|
202
201
|
config.seek(0, os.SEEK_SET)
|
203
202
|
|
204
203
|
try:
|
205
204
|
self.cp.read_file(config)
|
206
|
-
except configparser.DuplicateOptionError as
|
207
|
-
raise
|
205
|
+
except configparser.DuplicateOptionError as ex:
|
206
|
+
raise ValueError(f"Duplicate option in {paramvals['file']!r}.") from ex
|
208
207
|
|
209
208
|
try:
|
210
209
|
var = self.get_value(key, paramvals['section'], paramvals['default'], paramvals['re'])
|
211
210
|
except configparser.NoSectionError:
|
212
|
-
raise
|
211
|
+
raise ValueError(f"No section {paramvals['section']!r} in {paramvals['file']!r}.") from None
|
212
|
+
|
213
213
|
if var is not None:
|
214
214
|
if isinstance(var, MutableSequence):
|
215
215
|
for v in var:
|
216
216
|
ret.append(v)
|
217
217
|
else:
|
218
218
|
ret.append(var)
|
219
|
+
|
219
220
|
return ret
|
ansible/plugins/lookup/items.py
CHANGED
ansible/plugins/lookup/lines.py
CHANGED
@@ -16,6 +16,9 @@ DOCUMENTATION = """
|
|
16
16
|
description: command(s) to run
|
17
17
|
required: True
|
18
18
|
notes:
|
19
|
+
- The given commands are passed to a shell for execution, therefore all variables that are part of the commands and
|
20
|
+
come from a remote/untrusted source MUST be sanitized using the P(ansible.builtin.quote#filter) filter to avoid
|
21
|
+
shell injection vulnerabilities. See the example section.
|
19
22
|
- Like all lookups, this runs on the Ansible controller and is unaffected by other keywords such as 'become'.
|
20
23
|
If you need to use different permissions, you must change the command or run Ansible as another user.
|
21
24
|
- Alternatively, you can use a shell/command task that runs against localhost and registers the result.
|
@@ -27,6 +30,10 @@ EXAMPLES = """
|
|
27
30
|
ansible.builtin.debug: msg="{{ item }} is an output line from running cat on /etc/motd"
|
28
31
|
with_lines: cat /etc/motd
|
29
32
|
|
33
|
+
- name: Always use quote filter to make sure your variables are safe to use with shell
|
34
|
+
ansible.builtin.debug: msg="{{ item }} is an output line from running given command"
|
35
|
+
with_lines: "cat {{ file_name | quote }}"
|
36
|
+
|
30
37
|
- name: More useful example of looping over a command result
|
31
38
|
ansible.builtin.shell: "/usr/bin/frobnicate {{ item }}"
|
32
39
|
with_lines:
|
@@ -49,7 +56,7 @@ from ansible.module_utils.common.text.converters import to_text
|
|
49
56
|
|
50
57
|
class LookupModule(LookupBase):
|
51
58
|
|
52
|
-
def run(self, terms, variables, **kwargs):
|
59
|
+
def run(self, terms, variables=None, **kwargs):
|
53
60
|
|
54
61
|
ret = []
|
55
62
|
for term in terms:
|
ansible/plugins/lookup/list.py
CHANGED
@@ -37,7 +37,7 @@ from ansible.errors import AnsibleError
|
|
37
37
|
|
38
38
|
class LookupModule(LookupBase):
|
39
39
|
|
40
|
-
def run(self, terms, **kwargs):
|
40
|
+
def run(self, terms, variables=None, **kwargs):
|
41
41
|
if not isinstance(terms, Sequence):
|
42
42
|
raise AnsibleError("with_list expects a list")
|
43
43
|
return terms
|
ansible/plugins/lookup/nested.py
CHANGED
@@ -46,32 +46,16 @@ RETURN = """
|
|
46
46
|
type: list
|
47
47
|
"""
|
48
48
|
|
49
|
-
from jinja2.exceptions import UndefinedError
|
50
49
|
|
51
|
-
from ansible.errors import AnsibleError
|
50
|
+
from ansible.errors import AnsibleError
|
52
51
|
from ansible.plugins.lookup import LookupBase
|
53
|
-
from ansible.utils.listify import listify_lookup_plugin_terms
|
54
52
|
|
55
53
|
|
56
54
|
class LookupModule(LookupBase):
|
57
|
-
|
58
|
-
def _lookup_variables(self, terms, variables):
|
59
|
-
results = []
|
60
|
-
for x in terms:
|
61
|
-
try:
|
62
|
-
intermediate = listify_lookup_plugin_terms(x, templar=self._templar, fail_on_undefined=True)
|
63
|
-
except UndefinedError as e:
|
64
|
-
raise AnsibleUndefinedVariable("One of the nested variables was undefined. The error was: %s" % e)
|
65
|
-
results.append(intermediate)
|
66
|
-
return results
|
67
|
-
|
68
55
|
def run(self, terms, variables=None, **kwargs):
|
69
|
-
|
70
|
-
terms = self._lookup_variables(terms, variables)
|
71
|
-
|
72
56
|
my_list = terms[:]
|
73
57
|
my_list.reverse()
|
74
|
-
|
58
|
+
|
75
59
|
if len(my_list) == 0:
|
76
60
|
raise AnsibleError("with_nested requires at least one element in the nested list")
|
77
61
|
result = my_list.pop()
|