ansible-core 2.18.7rc1__py3-none-any.whl → 2.19.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ansible-core might be problematic. Click here for more details.
- ansible/_internal/__init__.py +53 -0
- ansible/_internal/_ansiballz/__init__.py +0 -0
- ansible/_internal/_ansiballz/_builder.py +101 -0
- ansible/_internal/_ansiballz/_wrapper.py +262 -0
- ansible/_internal/_collection_proxy.py +47 -0
- ansible/_internal/_datatag/__init__.py +0 -0
- ansible/_internal/_datatag/_tags.py +130 -0
- ansible/_internal/_datatag/_utils.py +19 -0
- ansible/_internal/_datatag/_wrappers.py +33 -0
- ansible/_internal/_errors/__init__.py +0 -0
- ansible/_internal/_errors/_alarm_timeout.py +66 -0
- ansible/_internal/_errors/_captured.py +123 -0
- ansible/_internal/_errors/_error_factory.py +89 -0
- ansible/_internal/_errors/_error_utils.py +240 -0
- ansible/_internal/_errors/_handler.py +91 -0
- ansible/_internal/_errors/_task_timeout.py +28 -0
- ansible/_internal/_event_formatting.py +127 -0
- ansible/_internal/_json/__init__.py +214 -0
- ansible/_internal/_json/_legacy_encoder.py +34 -0
- ansible/_internal/_json/_profiles/__init__.py +0 -0
- ansible/_internal/_json/_profiles/_cache_persistence.py +57 -0
- ansible/_internal/_json/_profiles/_inventory_legacy.py +40 -0
- ansible/_internal/_json/_profiles/_legacy.py +189 -0
- ansible/_internal/_locking.py +21 -0
- ansible/_internal/_plugins/__init__.py +0 -0
- ansible/_internal/_plugins/_cache.py +57 -0
- ansible/_internal/_ssh/__init__.py +0 -0
- ansible/_internal/_ssh/_agent_launch.py +91 -0
- ansible/_internal/_ssh/_ssh_agent.py +619 -0
- ansible/_internal/_task.py +78 -0
- ansible/_internal/_templating/__init__.py +12 -0
- ansible/_internal/_templating/_access.py +86 -0
- ansible/_internal/_templating/_chain_templar.py +63 -0
- ansible/_internal/_templating/_datatag.py +95 -0
- ansible/_internal/_templating/_engine.py +592 -0
- ansible/_internal/_templating/_errors.py +28 -0
- ansible/_internal/_templating/_jinja_bits.py +1106 -0
- ansible/_internal/_templating/_jinja_common.py +323 -0
- ansible/_internal/_templating/_jinja_patches.py +44 -0
- ansible/_internal/_templating/_jinja_plugins.py +375 -0
- ansible/_internal/_templating/_lazy_containers.py +633 -0
- ansible/_internal/_templating/_marker_behaviors.py +103 -0
- ansible/_internal/_templating/_template_vars.py +72 -0
- ansible/_internal/_templating/_transform.py +70 -0
- ansible/_internal/_templating/_utils.py +108 -0
- ansible/_internal/_testing.py +26 -0
- ansible/_internal/_wrapt.py +1052 -0
- ansible/_internal/_yaml/__init__.py +0 -0
- ansible/_internal/_yaml/_constructor.py +240 -0
- ansible/_internal/_yaml/_dumper.py +70 -0
- ansible/_internal/_yaml/_errors.py +166 -0
- ansible/_internal/_yaml/_loader.py +66 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/README.md +11 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/debug.py +36 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/apply_trust.py +19 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py +27 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/finalize.py +16 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/origin.py +18 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.py +24 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.yml +33 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/tag_names.py +16 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +17 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +49 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.py +21 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.yml +2 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.py +15 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.yml +19 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.py +18 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.yml +19 -0
- ansible/cli/__init__.py +93 -104
- ansible/cli/_ssh_askpass.py +54 -0
- ansible/cli/adhoc.py +20 -10
- ansible/cli/arguments/option_helpers.py +163 -10
- ansible/cli/config.py +43 -68
- ansible/cli/console.py +13 -11
- ansible/cli/doc.py +134 -77
- ansible/cli/galaxy.py +27 -20
- ansible/cli/inventory.py +28 -28
- ansible/cli/playbook.py +4 -12
- ansible/cli/pull.py +6 -3
- ansible/cli/scripts/ansible_connection_cli_stub.py +7 -7
- ansible/cli/vault.py +12 -11
- ansible/compat/__init__.py +2 -2
- ansible/compat/importlib_resources.py +9 -12
- ansible/config/base.yml +218 -133
- ansible/config/manager.py +220 -159
- ansible/constants.py +2 -65
- ansible/errors/__init__.py +350 -256
- ansible/executor/interpreter_discovery.py +28 -149
- ansible/executor/module_common.py +480 -514
- ansible/executor/play_iterator.py +22 -27
- ansible/executor/playbook_executor.py +11 -11
- ansible/executor/powershell/async_watchdog.ps1 +97 -102
- ansible/executor/powershell/async_wrapper.ps1 +204 -153
- ansible/executor/powershell/become_wrapper.ps1 +107 -144
- ansible/executor/powershell/bootstrap_wrapper.ps1 +46 -9
- ansible/executor/powershell/coverage_wrapper.ps1 +91 -135
- ansible/executor/powershell/exec_wrapper.ps1 +675 -196
- ansible/executor/powershell/module_manifest.py +469 -265
- ansible/executor/powershell/module_wrapper.ps1 +195 -186
- ansible/executor/powershell/powershell_expand_user.ps1 +20 -0
- ansible/executor/powershell/powershell_mkdtemp.ps1 +17 -0
- ansible/executor/powershell/psrp_fetch_file.ps1 +41 -0
- ansible/executor/powershell/psrp_put_file.ps1 +122 -0
- ansible/executor/powershell/winrm_fetch_file.ps1 +46 -0
- ansible/executor/powershell/winrm_put_file.ps1 +36 -0
- ansible/executor/process/worker.py +139 -149
- ansible/executor/stats.py +5 -5
- ansible/executor/task_executor.py +270 -297
- ansible/executor/task_queue_manager.py +135 -137
- ansible/executor/task_result.py +182 -79
- ansible/galaxy/__init__.py +2 -2
- ansible/galaxy/api.py +26 -25
- ansible/galaxy/collection/__init__.py +6 -14
- ansible/galaxy/collection/concrete_artifact_manager.py +12 -21
- ansible/galaxy/dependency_resolution/dataclasses.py +14 -4
- ansible/galaxy/dependency_resolution/providers.py +4 -4
- ansible/galaxy/dependency_resolution/reporters.py +81 -0
- ansible/galaxy/role.py +6 -10
- ansible/galaxy/token.py +28 -21
- ansible/inventory/data.py +47 -57
- ansible/inventory/group.py +50 -73
- ansible/inventory/helpers.py +9 -0
- ansible/inventory/host.py +37 -54
- ansible/inventory/manager.py +79 -34
- ansible/keyword_desc.yml +1 -1
- ansible/module_utils/_internal/__init__.py +55 -0
- ansible/module_utils/_internal/_ambient_context.py +58 -0
- ansible/module_utils/_internal/_ansiballz/__init__.py +0 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/__init__.py +0 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/_coverage.py +45 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/_pydevd.py +62 -0
- ansible/module_utils/_internal/_ansiballz/_loader.py +81 -0
- ansible/module_utils/_internal/_ansiballz/_respawn.py +32 -0
- ansible/module_utils/_internal/_ansiballz/_respawn_wrapper.py +23 -0
- ansible/module_utils/_internal/_concurrent/_daemon_threading.py +1 -0
- ansible/module_utils/_internal/_dataclass_validation.py +217 -0
- ansible/module_utils/_internal/_datatag/__init__.py +961 -0
- ansible/module_utils/_internal/_datatag/_tags.py +16 -0
- ansible/module_utils/_internal/_debugging.py +31 -0
- ansible/module_utils/_internal/_deprecator.py +157 -0
- ansible/module_utils/_internal/_errors.py +101 -0
- ansible/module_utils/_internal/_event_utils.py +61 -0
- ansible/module_utils/_internal/_json/__init__.py +63 -0
- ansible/module_utils/_internal/_json/_legacy_encoder.py +26 -0
- ansible/module_utils/_internal/_json/_profiles/__init__.py +428 -0
- ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py +73 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +33 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +37 -0
- ansible/module_utils/_internal/_json/_profiles/_module_modern_c2m.py +35 -0
- ansible/module_utils/_internal/_json/_profiles/_module_modern_m2c.py +33 -0
- ansible/module_utils/_internal/_json/_profiles/_tagless.py +52 -0
- ansible/module_utils/_internal/_messages.py +130 -0
- ansible/module_utils/_internal/_patches/__init__.py +66 -0
- ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +53 -0
- ansible/module_utils/_internal/_patches/_socket_patch.py +34 -0
- ansible/module_utils/_internal/_patches/_sys_intern_patch.py +34 -0
- ansible/module_utils/_internal/_plugin_info.py +38 -0
- ansible/module_utils/_internal/_stack.py +22 -0
- ansible/module_utils/_internal/_testing.py +0 -0
- ansible/module_utils/_internal/_text_utils.py +6 -0
- ansible/module_utils/_internal/_traceback.py +92 -0
- ansible/module_utils/_internal/_validation.py +14 -0
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/api.py +1 -2
- ansible/module_utils/basic.py +303 -202
- ansible/module_utils/common/_utils.py +24 -28
- ansible/module_utils/common/arg_spec.py +8 -3
- ansible/module_utils/common/collections.py +7 -2
- ansible/module_utils/common/dict_transformations.py +2 -2
- ansible/module_utils/common/file.py +2 -2
- ansible/module_utils/common/json.py +90 -84
- ansible/module_utils/common/locale.py +2 -2
- ansible/module_utils/common/parameters.py +27 -24
- ansible/module_utils/common/process.py +2 -3
- ansible/module_utils/common/respawn.py +11 -33
- ansible/module_utils/common/sentinel.py +66 -0
- ansible/module_utils/common/sys_info.py +8 -8
- ansible/module_utils/common/text/converters.py +16 -37
- ansible/module_utils/common/validation.py +35 -24
- ansible/module_utils/common/warnings.py +143 -25
- ansible/module_utils/common/yaml.py +29 -3
- ansible/module_utils/compat/datetime.py +33 -21
- ansible/module_utils/compat/paramiko.py +21 -10
- ansible/module_utils/compat/typing.py +6 -5
- ansible/module_utils/connection.py +10 -13
- ansible/module_utils/csharp/Ansible.Basic.cs +15 -12
- ansible/module_utils/csharp/Ansible.Become.cs +1 -0
- ansible/module_utils/csharp/Ansible.Privilege.cs +2 -2
- ansible/module_utils/csharp/Ansible._Async.cs +517 -0
- ansible/module_utils/datatag.py +49 -0
- ansible/module_utils/distro/__init__.py +2 -2
- ansible/module_utils/facts/ansible_collector.py +4 -5
- ansible/module_utils/facts/collector.py +13 -14
- ansible/module_utils/facts/compat.py +4 -4
- ansible/module_utils/facts/default_collectors.py +1 -1
- ansible/module_utils/facts/hardware/aix.py +34 -0
- ansible/module_utils/facts/hardware/base.py +2 -2
- ansible/module_utils/facts/hardware/darwin.py +1 -3
- ansible/module_utils/facts/hardware/freebsd.py +2 -2
- ansible/module_utils/facts/hardware/linux.py +5 -5
- ansible/module_utils/facts/namespace.py +1 -1
- ansible/module_utils/facts/network/base.py +1 -1
- ansible/module_utils/facts/network/fc_wwn.py +1 -2
- ansible/module_utils/facts/network/iscsi.py +1 -2
- ansible/module_utils/facts/network/nvme.py +1 -2
- ansible/module_utils/facts/other/facter.py +2 -3
- ansible/module_utils/facts/other/ohai.py +2 -3
- ansible/module_utils/facts/sysctl.py +4 -6
- ansible/module_utils/facts/system/apparmor.py +1 -2
- ansible/module_utils/facts/system/caps.py +3 -3
- ansible/module_utils/facts/system/chroot.py +1 -2
- ansible/module_utils/facts/system/cmdline.py +1 -2
- ansible/module_utils/facts/system/date_time.py +5 -3
- ansible/module_utils/facts/system/distribution.py +27 -13
- ansible/module_utils/facts/system/dns.py +1 -1
- ansible/module_utils/facts/system/env.py +1 -2
- ansible/module_utils/facts/system/fips.py +7 -20
- ansible/module_utils/facts/system/loadavg.py +1 -2
- ansible/module_utils/facts/system/local.py +2 -3
- ansible/module_utils/facts/system/lsb.py +1 -2
- ansible/module_utils/facts/system/pkg_mgr.py +1 -2
- ansible/module_utils/facts/system/platform.py +1 -2
- ansible/module_utils/facts/system/python.py +1 -2
- ansible/module_utils/facts/system/selinux.py +1 -1
- ansible/module_utils/facts/system/service_mgr.py +1 -2
- ansible/module_utils/facts/system/ssh_pub_keys.py +1 -1
- ansible/module_utils/facts/system/systemd.py +1 -1
- ansible/module_utils/facts/system/user.py +1 -2
- ansible/module_utils/facts/utils.py +3 -3
- ansible/module_utils/facts/virtual/base.py +1 -1
- ansible/module_utils/facts/virtual/linux.py +3 -3
- ansible/module_utils/facts/virtual/sunos.py +3 -15
- ansible/module_utils/facts/virtual/sysctl.py +3 -16
- ansible/module_utils/json_utils.py +2 -2
- ansible/module_utils/parsing/convert_bool.py +7 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.CommandUtil.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.WebRequest.psm1 +1 -1
- ansible/module_utils/service.py +21 -31
- ansible/module_utils/splitter.py +7 -7
- ansible/module_utils/testing.py +31 -0
- ansible/module_utils/urls.py +64 -35
- ansible/modules/add_host.py +4 -4
- ansible/modules/apt.py +69 -49
- ansible/modules/apt_key.py +19 -12
- ansible/modules/apt_repository.py +32 -51
- ansible/modules/assemble.py +16 -14
- ansible/modules/assert.py +4 -4
- ansible/modules/async_status.py +24 -24
- ansible/modules/async_wrapper.py +20 -25
- ansible/modules/blockinfile.py +6 -7
- ansible/modules/command.py +13 -20
- ansible/modules/copy.py +60 -147
- ansible/modules/cron.py +24 -21
- ansible/modules/deb822_repository.py +8 -9
- ansible/modules/debconf.py +5 -5
- ansible/modules/debug.py +4 -4
- ansible/modules/dnf.py +8 -8
- ansible/modules/dnf5.py +39 -13
- ansible/modules/dpkg_selections.py +4 -4
- ansible/modules/expect.py +13 -15
- ansible/modules/fail.py +4 -4
- ansible/modules/fetch.py +4 -4
- ansible/modules/file.py +184 -144
- ansible/modules/find.py +22 -20
- ansible/modules/gather_facts.py +3 -3
- ansible/modules/get_url.py +77 -54
- ansible/modules/getent.py +7 -9
- ansible/modules/git.py +38 -38
- ansible/modules/group.py +6 -6
- ansible/modules/group_by.py +4 -4
- ansible/modules/hostname.py +15 -32
- ansible/modules/import_playbook.py +6 -6
- ansible/modules/import_role.py +6 -6
- ansible/modules/import_tasks.py +6 -6
- ansible/modules/include_role.py +6 -6
- ansible/modules/include_tasks.py +6 -6
- ansible/modules/include_vars.py +6 -6
- ansible/modules/iptables.py +86 -73
- ansible/modules/known_hosts.py +22 -24
- ansible/modules/lineinfile.py +5 -5
- ansible/modules/meta.py +4 -4
- ansible/modules/mount_facts.py +2 -2
- ansible/modules/package.py +10 -4
- ansible/modules/package_facts.py +22 -10
- ansible/modules/pause.py +6 -6
- ansible/modules/ping.py +6 -6
- ansible/modules/pip.py +21 -26
- ansible/modules/raw.py +6 -6
- ansible/modules/reboot.py +6 -6
- ansible/modules/replace.py +10 -14
- ansible/modules/rpm_key.py +7 -8
- ansible/modules/script.py +4 -4
- ansible/modules/service.py +10 -17
- ansible/modules/service_facts.py +87 -10
- ansible/modules/set_fact.py +5 -5
- ansible/modules/set_stats.py +4 -4
- ansible/modules/setup.py +2 -2
- ansible/modules/shell.py +6 -6
- ansible/modules/slurp.py +16 -19
- ansible/modules/stat.py +15 -31
- ansible/modules/subversion.py +15 -15
- ansible/modules/systemd.py +7 -7
- ansible/modules/systemd_service.py +7 -7
- ansible/modules/sysvinit.py +9 -9
- ansible/modules/tempfile.py +5 -6
- ansible/modules/template.py +6 -6
- ansible/modules/unarchive.py +38 -17
- ansible/modules/uri.py +33 -26
- ansible/modules/user.py +45 -32
- ansible/modules/validate_argument_spec.py +10 -7
- ansible/modules/wait_for.py +70 -60
- ansible/modules/wait_for_connection.py +6 -6
- ansible/modules/yum_repository.py +10 -9
- ansible/parsing/ajson.py +17 -37
- ansible/parsing/dataloader.py +99 -54
- ansible/parsing/mod_args.py +62 -60
- ansible/parsing/plugin_docs.py +21 -86
- ansible/parsing/quoting.py +1 -1
- ansible/parsing/splitter.py +27 -12
- ansible/parsing/utils/addresses.py +24 -24
- ansible/parsing/utils/jsonify.py +5 -1
- ansible/parsing/utils/yaml.py +32 -61
- ansible/parsing/vault/__init__.py +327 -99
- ansible/parsing/yaml/__init__.py +0 -18
- ansible/parsing/yaml/dumper.py +6 -120
- ansible/parsing/yaml/loader.py +6 -39
- ansible/parsing/yaml/objects.py +43 -335
- ansible/playbook/__init__.py +1 -1
- ansible/playbook/attribute.py +8 -3
- ansible/playbook/base.py +187 -134
- ansible/playbook/block.py +26 -24
- ansible/playbook/collectionsearch.py +1 -15
- ansible/playbook/conditional.py +3 -77
- ansible/playbook/handler.py +8 -2
- ansible/playbook/helpers.py +41 -53
- ansible/playbook/included_file.py +32 -26
- ansible/playbook/loop_control.py +2 -2
- ansible/playbook/play.py +85 -44
- ansible/playbook/play_context.py +14 -17
- ansible/playbook/playbook_include.py +27 -62
- ansible/playbook/role/__init__.py +64 -49
- ansible/playbook/role/definition.py +15 -17
- ansible/playbook/role/include.py +2 -4
- ansible/playbook/role/metadata.py +10 -11
- ansible/playbook/role_include.py +3 -3
- ansible/playbook/taggable.py +28 -12
- ansible/playbook/task.py +192 -121
- ansible/playbook/task_include.py +5 -5
- ansible/plugins/__init__.py +58 -26
- ansible/plugins/action/__init__.py +188 -186
- ansible/plugins/action/add_host.py +2 -2
- ansible/plugins/action/assemble.py +11 -18
- ansible/plugins/action/assert.py +55 -67
- ansible/plugins/action/async_status.py +7 -2
- ansible/plugins/action/copy.py +14 -17
- ansible/plugins/action/debug.py +37 -31
- ansible/plugins/action/dnf.py +3 -4
- ansible/plugins/action/fail.py +1 -1
- ansible/plugins/action/fetch.py +7 -8
- ansible/plugins/action/gather_facts.py +13 -14
- ansible/plugins/action/group_by.py +1 -1
- ansible/plugins/action/include_vars.py +10 -11
- ansible/plugins/action/package.py +8 -14
- ansible/plugins/action/pause.py +2 -2
- ansible/plugins/action/script.py +27 -38
- ansible/plugins/action/service.py +9 -18
- ansible/plugins/action/set_fact.py +3 -12
- ansible/plugins/action/set_stats.py +3 -8
- ansible/plugins/action/template.py +47 -67
- ansible/plugins/action/unarchive.py +6 -16
- ansible/plugins/action/uri.py +9 -20
- ansible/plugins/action/validate_argument_spec.py +5 -5
- ansible/plugins/action/wait_for_connection.py +1 -1
- ansible/plugins/become/__init__.py +31 -8
- ansible/plugins/become/runas.py +71 -0
- ansible/plugins/become/su.py +13 -8
- ansible/plugins/become/sudo.py +19 -0
- ansible/plugins/cache/__init__.py +52 -63
- ansible/plugins/cache/base.py +8 -0
- ansible/plugins/cache/jsonfile.py +10 -16
- ansible/plugins/cache/memory.py +6 -12
- ansible/plugins/callback/__init__.py +294 -201
- ansible/plugins/callback/default.py +99 -95
- ansible/plugins/callback/junit.py +44 -43
- ansible/plugins/callback/minimal.py +28 -25
- ansible/plugins/callback/oneline.py +34 -21
- ansible/plugins/callback/tree.py +27 -16
- ansible/plugins/connection/__init__.py +47 -34
- ansible/plugins/connection/local.py +156 -60
- ansible/plugins/connection/paramiko_ssh.py +34 -24
- ansible/plugins/connection/psrp.py +76 -165
- ansible/plugins/connection/ssh.py +326 -86
- ansible/plugins/connection/winrm.py +62 -141
- ansible/plugins/doc_fragments/action_common_attributes.py +14 -14
- ansible/plugins/doc_fragments/action_core.py +6 -6
- ansible/plugins/doc_fragments/backup.py +2 -2
- ansible/plugins/doc_fragments/checksum_common.py +27 -0
- ansible/plugins/doc_fragments/constructed.py +8 -4
- ansible/plugins/doc_fragments/decrypt.py +2 -2
- ansible/plugins/doc_fragments/default_callback.py +2 -2
- ansible/plugins/doc_fragments/files.py +2 -2
- ansible/plugins/doc_fragments/inventory_cache.py +2 -2
- ansible/plugins/doc_fragments/result_format_callback.py +2 -2
- ansible/plugins/doc_fragments/return_common.py +2 -2
- ansible/plugins/doc_fragments/template_common.py +4 -4
- ansible/plugins/doc_fragments/url.py +17 -1
- ansible/plugins/doc_fragments/url_windows.py +2 -2
- ansible/plugins/doc_fragments/validate.py +2 -2
- ansible/plugins/doc_fragments/vars_plugin_staging.py +2 -2
- ansible/plugins/filter/__init__.py +6 -2
- ansible/plugins/filter/b64decode.yml +22 -0
- ansible/plugins/filter/b64encode.yml +22 -0
- ansible/plugins/filter/bool.yml +11 -4
- ansible/plugins/filter/core.py +245 -120
- ansible/plugins/filter/encryption.py +42 -34
- ansible/plugins/filter/flatten.yml +3 -2
- ansible/plugins/filter/human_to_bytes.yml +1 -1
- ansible/plugins/filter/mathstuff.py +30 -37
- ansible/plugins/filter/password_hash.yml +8 -0
- ansible/plugins/filter/pow.yml +1 -1
- ansible/plugins/filter/regex_search.yml +1 -4
- ansible/plugins/filter/root.yml +1 -1
- ansible/plugins/filter/split.yml +1 -1
- ansible/plugins/filter/strftime.yml +3 -3
- ansible/plugins/filter/to_nice_yaml.yml +0 -4
- ansible/plugins/filter/to_uuid.yml +1 -1
- ansible/plugins/filter/to_yaml.yml +0 -4
- ansible/plugins/filter/unvault.yml +1 -1
- ansible/plugins/filter/urls.py +1 -1
- ansible/plugins/filter/urlsplit.py +8 -9
- ansible/plugins/filter/vault.yml +14 -9
- ansible/plugins/filter/win_basename.yml +6 -1
- ansible/plugins/filter/win_dirname.yml +5 -0
- ansible/plugins/inventory/__init__.py +107 -86
- ansible/plugins/inventory/advanced_host_list.py +7 -5
- ansible/plugins/inventory/auto.py +11 -4
- ansible/plugins/inventory/constructed.py +21 -24
- ansible/plugins/inventory/generator.py +16 -11
- ansible/plugins/inventory/host_list.py +7 -5
- ansible/plugins/inventory/ini.py +78 -44
- ansible/plugins/inventory/script.py +190 -120
- ansible/plugins/inventory/toml.py +16 -126
- ansible/plugins/inventory/yaml.py +10 -8
- ansible/plugins/list.py +72 -19
- ansible/plugins/loader.py +383 -198
- ansible/plugins/lookup/__init__.py +21 -4
- ansible/plugins/lookup/config.py +21 -35
- ansible/plugins/lookup/csvfile.py +19 -73
- ansible/plugins/lookup/dict.py +1 -6
- ansible/plugins/lookup/env.py +12 -9
- ansible/plugins/lookup/file.py +5 -8
- ansible/plugins/lookup/first_found.py +87 -55
- ansible/plugins/lookup/indexed_items.py +1 -10
- ansible/plugins/lookup/ini.py +14 -13
- ansible/plugins/lookup/items.py +1 -1
- ansible/plugins/lookup/lines.py +8 -1
- ansible/plugins/lookup/list.py +1 -1
- ansible/plugins/lookup/nested.py +2 -18
- ansible/plugins/lookup/password.py +5 -5
- ansible/plugins/lookup/pipe.py +5 -7
- ansible/plugins/lookup/sequence.py +18 -8
- ansible/plugins/lookup/subelements.py +1 -4
- ansible/plugins/lookup/template.py +47 -36
- ansible/plugins/lookup/together.py +0 -12
- ansible/plugins/lookup/unvault.py +1 -5
- ansible/plugins/lookup/url.py +4 -10
- ansible/plugins/lookup/vars.py +16 -24
- ansible/plugins/shell/__init__.py +58 -4
- ansible/plugins/shell/cmd.py +2 -2
- ansible/plugins/shell/powershell.py +106 -31
- ansible/plugins/shell/sh.py +13 -7
- ansible/plugins/strategy/__init__.py +168 -193
- ansible/plugins/strategy/debug.py +2 -2
- ansible/plugins/strategy/free.py +16 -31
- ansible/plugins/strategy/host_pinned.py +2 -2
- ansible/plugins/strategy/linear.py +41 -41
- ansible/plugins/terminal/__init__.py +4 -4
- ansible/plugins/test/__init__.py +7 -2
- ansible/plugins/test/core.py +75 -35
- ansible/plugins/test/files.py +1 -1
- ansible/plugins/test/finished.yml +1 -1
- ansible/plugins/test/mathstuff.py +3 -3
- ansible/plugins/test/uri.py +5 -8
- ansible/plugins/vars/host_group_vars.py +7 -14
- ansible/release.py +2 -2
- ansible/template/__init__.py +353 -943
- ansible/utils/__init__.py +0 -18
- ansible/utils/collection_loader/__init__.py +54 -5
- ansible/utils/collection_loader/_collection_config.py +5 -6
- ansible/utils/collection_loader/_collection_finder.py +82 -96
- ansible/utils/collection_loader/_collection_meta.py +15 -8
- ansible/utils/display.py +485 -73
- ansible/utils/encrypt.py +27 -19
- ansible/utils/fqcn.py +2 -2
- ansible/utils/galaxy.py +2 -2
- ansible/utils/hashing.py +8 -10
- ansible/utils/helpers.py +2 -2
- ansible/utils/listify.py +10 -8
- ansible/utils/lock.py +2 -2
- ansible/utils/path.py +10 -12
- ansible/utils/plugin_docs.py +16 -14
- ansible/utils/py3compat.py +2 -7
- ansible/utils/sentinel.py +4 -62
- ansible/utils/singleton.py +2 -0
- ansible/utils/ssh_functions.py +6 -2
- ansible/utils/unsafe_proxy.py +23 -332
- ansible/utils/vars.py +55 -8
- ansible/utils/version.py +2 -2
- ansible/vars/clean.py +5 -5
- ansible/vars/hostvars.py +60 -90
- ansible/vars/manager.py +220 -285
- ansible/vars/plugins.py +4 -4
- ansible/vars/reserved.py +13 -12
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/METADATA +4 -3
- ansible_core-2.19.0.dist-info/RECORD +1097 -0
- ansible_core-2.19.0.dist-info/licenses/licenses/BSD-3-Clause.txt +28 -0
- ansible_test/_data/completion/docker.txt +7 -7
- ansible_test/_data/completion/remote.txt +6 -6
- ansible_test/_data/completion/windows.txt +1 -0
- ansible_test/_data/requirements/ansible.txt +2 -2
- ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
- ansible_test/_data/requirements/sanity.changelog.txt +2 -2
- ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
- ansible_test/_data/requirements/sanity.pep8.txt +1 -1
- ansible_test/_data/requirements/sanity.pylint.txt +5 -5
- ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
- ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
- ansible_test/_data/requirements/units.txt +1 -0
- ansible_test/_internal/__init__.py +6 -0
- ansible_test/_internal/ansible_util.py +3 -1
- ansible_test/_internal/become.py +1 -0
- ansible_test/_internal/bootstrap.py +1 -0
- ansible_test/_internal/cache.py +1 -0
- ansible_test/_internal/cgroup.py +1 -0
- ansible_test/_internal/ci/__init__.py +1 -0
- ansible_test/_internal/ci/azp.py +1 -0
- ansible_test/_internal/ci/local.py +1 -0
- ansible_test/_internal/classification/__init__.py +1 -0
- ansible_test/_internal/classification/common.py +1 -0
- ansible_test/_internal/classification/csharp.py +1 -0
- ansible_test/_internal/classification/powershell.py +1 -0
- ansible_test/_internal/classification/python.py +1 -0
- ansible_test/_internal/cli/__init__.py +1 -0
- ansible_test/_internal/cli/actions.py +1 -0
- ansible_test/_internal/cli/argparsing/__init__.py +1 -0
- ansible_test/_internal/cli/argparsing/actions.py +1 -0
- ansible_test/_internal/cli/argparsing/argcompletion.py +1 -0
- ansible_test/_internal/cli/argparsing/parsers.py +1 -0
- ansible_test/_internal/cli/commands/__init__.py +11 -5
- ansible_test/_internal/cli/commands/coverage/__init__.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/__init__.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/__init__.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/combine.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/expand.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/filter.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/generate.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/missing.py +1 -0
- ansible_test/_internal/cli/commands/coverage/combine.py +1 -0
- ansible_test/_internal/cli/commands/coverage/erase.py +1 -0
- ansible_test/_internal/cli/commands/coverage/html.py +1 -0
- ansible_test/_internal/cli/commands/coverage/report.py +1 -0
- ansible_test/_internal/cli/commands/coverage/xml.py +1 -0
- ansible_test/_internal/cli/commands/env.py +1 -0
- ansible_test/_internal/cli/commands/integration/__init__.py +1 -0
- ansible_test/_internal/cli/commands/integration/network.py +1 -0
- ansible_test/_internal/cli/commands/integration/posix.py +1 -0
- ansible_test/_internal/cli/commands/integration/windows.py +1 -0
- ansible_test/_internal/cli/commands/sanity.py +9 -0
- ansible_test/_internal/cli/commands/shell.py +1 -0
- ansible_test/_internal/cli/commands/units.py +1 -0
- ansible_test/_internal/cli/compat.py +1 -0
- ansible_test/_internal/cli/completers.py +1 -0
- ansible_test/_internal/cli/converters.py +1 -0
- ansible_test/_internal/cli/environments.py +52 -5
- ansible_test/_internal/cli/epilog.py +1 -0
- ansible_test/_internal/cli/parsers/__init__.py +1 -0
- ansible_test/_internal/cli/parsers/base_argument_parsers.py +1 -0
- ansible_test/_internal/cli/parsers/helpers.py +1 -0
- ansible_test/_internal/cli/parsers/host_config_parsers.py +1 -0
- ansible_test/_internal/cli/parsers/key_value_parsers.py +1 -0
- ansible_test/_internal/cli/parsers/value_parsers.py +1 -0
- ansible_test/_internal/commands/__init__.py +1 -0
- ansible_test/_internal/commands/coverage/__init__.py +3 -2
- ansible_test/_internal/commands/coverage/analyze/__init__.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/__init__.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/combine.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/expand.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/filter.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/generate.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/missing.py +1 -0
- ansible_test/_internal/commands/coverage/combine.py +2 -1
- ansible_test/_internal/commands/coverage/erase.py +1 -0
- ansible_test/_internal/commands/coverage/html.py +1 -0
- ansible_test/_internal/commands/coverage/report.py +1 -0
- ansible_test/_internal/commands/coverage/xml.py +1 -0
- ansible_test/_internal/commands/env/__init__.py +2 -0
- ansible_test/_internal/commands/integration/__init__.py +22 -5
- ansible_test/_internal/commands/integration/cloud/__init__.py +1 -0
- ansible_test/_internal/commands/integration/cloud/acme.py +2 -1
- ansible_test/_internal/commands/integration/cloud/aws.py +1 -0
- ansible_test/_internal/commands/integration/cloud/azure.py +1 -0
- ansible_test/_internal/commands/integration/cloud/cs.py +1 -0
- ansible_test/_internal/commands/integration/cloud/digitalocean.py +1 -0
- ansible_test/_internal/commands/integration/cloud/galaxy.py +3 -2
- ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -0
- ansible_test/_internal/commands/integration/cloud/httptester.py +3 -2
- ansible_test/_internal/commands/integration/cloud/nios.py +2 -1
- ansible_test/_internal/commands/integration/cloud/opennebula.py +1 -0
- ansible_test/_internal/commands/integration/cloud/openshift.py +1 -0
- ansible_test/_internal/commands/integration/cloud/scaleway.py +1 -0
- ansible_test/_internal/commands/integration/cloud/vcenter.py +1 -0
- ansible_test/_internal/commands/integration/cloud/vultr.py +1 -0
- ansible_test/_internal/commands/integration/coverage.py +8 -2
- ansible_test/_internal/commands/integration/filters.py +1 -0
- ansible_test/_internal/commands/integration/network.py +1 -0
- ansible_test/_internal/commands/integration/posix.py +1 -0
- ansible_test/_internal/commands/integration/windows.py +1 -0
- ansible_test/_internal/commands/sanity/__init__.py +19 -2
- ansible_test/_internal/commands/sanity/ansible_doc.py +1 -0
- ansible_test/_internal/commands/sanity/bin_symlinks.py +1 -0
- ansible_test/_internal/commands/sanity/compile.py +1 -0
- ansible_test/_internal/commands/sanity/ignores.py +1 -0
- ansible_test/_internal/commands/sanity/import.py +1 -0
- ansible_test/_internal/commands/sanity/integration_aliases.py +12 -0
- ansible_test/_internal/commands/sanity/pep8.py +1 -0
- ansible_test/_internal/commands/sanity/pslint.py +1 -0
- ansible_test/_internal/commands/sanity/pylint.py +25 -26
- ansible_test/_internal/commands/sanity/shellcheck.py +1 -0
- ansible_test/_internal/commands/sanity/validate_modules.py +1 -0
- ansible_test/_internal/commands/sanity/yamllint.py +1 -0
- ansible_test/_internal/commands/shell/__init__.py +44 -4
- ansible_test/_internal/commands/units/__init__.py +5 -1
- ansible_test/_internal/compat/__init__.py +1 -0
- ansible_test/_internal/compat/packaging.py +1 -0
- ansible_test/_internal/compat/yaml.py +1 -0
- ansible_test/_internal/completion.py +1 -0
- ansible_test/_internal/config.py +23 -13
- ansible_test/_internal/connections.py +1 -0
- ansible_test/_internal/constants.py +1 -0
- ansible_test/_internal/containers.py +1 -0
- ansible_test/_internal/content_config.py +1 -0
- ansible_test/_internal/core_ci.py +1 -0
- ansible_test/_internal/coverage_util.py +11 -10
- ansible_test/_internal/data.py +1 -0
- ansible_test/_internal/debugging.py +166 -0
- ansible_test/_internal/delegation.py +22 -13
- ansible_test/_internal/dev/__init__.py +1 -0
- ansible_test/_internal/dev/container_probe.py +1 -0
- ansible_test/_internal/diff.py +3 -2
- ansible_test/_internal/docker_util.py +2 -1
- ansible_test/_internal/encoding.py +1 -0
- ansible_test/_internal/executor.py +1 -0
- ansible_test/_internal/git.py +1 -0
- ansible_test/_internal/host_configs.py +1 -0
- ansible_test/_internal/host_profiles.py +260 -16
- ansible_test/_internal/http.py +1 -0
- ansible_test/_internal/init.py +1 -0
- ansible_test/_internal/inventory.py +39 -3
- ansible_test/_internal/io.py +1 -0
- ansible_test/_internal/metadata.py +95 -4
- ansible_test/_internal/payload.py +1 -0
- ansible_test/_internal/processes.py +80 -0
- ansible_test/_internal/provider/__init__.py +1 -0
- ansible_test/_internal/provider/layout/__init__.py +1 -0
- ansible_test/_internal/provider/layout/ansible.py +1 -0
- ansible_test/_internal/provider/layout/collection.py +1 -0
- ansible_test/_internal/provider/layout/unsupported.py +1 -0
- ansible_test/_internal/provider/source/__init__.py +1 -0
- ansible_test/_internal/provider/source/git.py +1 -0
- ansible_test/_internal/provider/source/installed.py +1 -0
- ansible_test/_internal/provider/source/unsupported.py +1 -0
- ansible_test/_internal/provider/source/unversioned.py +1 -0
- ansible_test/_internal/provisioning.py +11 -4
- ansible_test/_internal/pypi_proxy.py +6 -5
- ansible_test/_internal/python_requirements.py +28 -0
- ansible_test/_internal/ssh.py +2 -5
- ansible_test/_internal/target.py +9 -0
- ansible_test/_internal/test.py +3 -2
- ansible_test/_internal/thread.py +3 -1
- ansible_test/_internal/timeout.py +2 -1
- ansible_test/_internal/util.py +41 -12
- ansible_test/_internal/util_common.py +18 -5
- ansible_test/_internal/venv.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/changelog/sphinx.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/changelog.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/empty-init.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/line-endings.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-assert.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-get-exception.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-illegal-filenames.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-smart-quotes.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/replace-urlopen.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +28 -1
- ansible_test/_util/controller/sanity/code-smell/shebang.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/symlinks.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/use-argspec-type-path.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/use-compat-six.py +1 -0
- ansible_test/_util/controller/sanity/integration-aliases/yaml_to_json.py +2 -1
- ansible_test/_util/controller/sanity/pep8/current-ignore.txt +4 -0
- ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +8 -5
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +8 -5
- ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +8 -5
- ansible_test/_util/controller/sanity/pylint/config/collection.cfg +4 -5
- ansible_test/_util/controller/sanity/pylint/config/default.cfg +8 -7
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +541 -0
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_comment.py +137 -0
- ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +1 -0
- ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +1 -8
- ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +1 -8
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +55 -28
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +12 -5
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +13 -2
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -0
- ansible_test/_util/controller/sanity/yamllint/yamllinter.py +35 -17
- ansible_test/_util/controller/tools/collection_detail.py +1 -0
- ansible_test/_util/controller/tools/yaml_to_json.py +2 -1
- ansible_test/_util/target/injector/python.py +8 -0
- ansible_test/_util/target/pytest/plugins/ansible_forked.py +6 -1
- ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py +2 -1
- ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +1 -0
- ansible_test/_util/target/sanity/compile/compile.py +1 -0
- ansible_test/_util/target/sanity/import/importer.py +15 -16
- ansible_test/_util/target/setup/bootstrap.sh +9 -20
- ansible_test/_util/target/setup/probe_cgroups.py +1 -0
- ansible_test/_util/target/setup/quiet_pip.py +1 -0
- ansible_test/_util/target/setup/requirements.py +38 -36
- ansible_test/_util/target/tools/virtualenvcheck.py +2 -1
- ansible_test/_util/target/tools/yamlcheck.py +2 -1
- ansible/compat/selectors.py +0 -32
- ansible/errors/yaml_strings.py +0 -138
- ansible/executor/action_write_locks.py +0 -44
- ansible/executor/discovery/python_target.py +0 -47
- ansible/executor/powershell/module_powershell_wrapper.ps1 +0 -86
- ansible/executor/powershell/module_script_wrapper.ps1 +0 -22
- ansible/module_utils/compat/importlib.py +0 -26
- ansible/module_utils/compat/selectors.py +0 -32
- ansible/module_utils/pycompat24.py +0 -73
- ansible/parsing/yaml/constructor.py +0 -178
- ansible/template/native_helpers.py +0 -251
- ansible/template/template.py +0 -43
- ansible/template/vars.py +0 -77
- ansible/utils/native_jinja.py +0 -11
- ansible/vars/fact_cache.py +0 -71
- ansible_core-2.18.7rc1.dist-info/RECORD +0 -992
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +0 -411
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/WHEEL +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/top_level.txt +0 -0
|
@@ -7,32 +7,42 @@ import os
|
|
|
7
7
|
import time
|
|
8
8
|
import json
|
|
9
9
|
import pathlib
|
|
10
|
-
import signal
|
|
11
10
|
import subprocess
|
|
12
11
|
import sys
|
|
12
|
+
|
|
13
13
|
import traceback
|
|
14
|
+
import typing as t
|
|
14
15
|
|
|
15
16
|
from ansible import constants as C
|
|
16
17
|
from ansible.cli import scripts
|
|
17
|
-
from ansible.errors import
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
from ansible.errors import (
|
|
19
|
+
AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleTaskError,
|
|
20
|
+
AnsibleValueOmittedError,
|
|
21
|
+
)
|
|
22
|
+
from ansible.executor.task_result import _RawTaskResult
|
|
23
|
+
from ansible._internal._datatag import _utils
|
|
24
|
+
from ansible.module_utils._internal import _messages
|
|
25
|
+
from ansible.module_utils.datatag import native_type_name, deprecator_from_collection_name
|
|
26
|
+
from ansible._internal._datatag._tags import TrustedAsTemplate
|
|
20
27
|
from ansible.module_utils.parsing.convert_bool import boolean
|
|
21
|
-
from ansible.module_utils.six import binary_type
|
|
22
28
|
from ansible.module_utils.common.text.converters import to_text, to_native
|
|
23
29
|
from ansible.module_utils.connection import write_to_stream
|
|
24
30
|
from ansible.module_utils.six import string_types
|
|
25
|
-
from ansible.playbook.conditional import Conditional
|
|
26
31
|
from ansible.playbook.task import Task
|
|
27
32
|
from ansible.plugins import get_plugin_class
|
|
28
33
|
from ansible.plugins.loader import become_loader, cliconf_loader, connection_loader, httpapi_loader, netconf_loader, terminal_loader
|
|
34
|
+
from ansible._internal._templating._jinja_plugins import _invoke_lookup, _DirectCall
|
|
35
|
+
from ansible._internal._templating._engine import TemplateEngine
|
|
29
36
|
from ansible.template import Templar
|
|
30
37
|
from ansible.utils.collection_loader import AnsibleCollectionConfig
|
|
31
|
-
from ansible.utils.
|
|
32
|
-
from ansible.utils.unsafe_proxy import to_unsafe_text, wrap_var
|
|
33
|
-
from ansible.vars.clean import namespace_facts, clean_facts
|
|
34
|
-
from ansible.utils.display import Display
|
|
38
|
+
from ansible.utils.display import Display, _DeferredWarningContext
|
|
35
39
|
from ansible.utils.vars import combine_vars
|
|
40
|
+
from ansible.vars.clean import namespace_facts, clean_facts
|
|
41
|
+
from ansible.vars.manager import _deprecate_top_level_fact
|
|
42
|
+
from ansible._internal._errors import _captured, _task_timeout, _error_utils
|
|
43
|
+
|
|
44
|
+
if t.TYPE_CHECKING:
|
|
45
|
+
from ansible.executor.task_queue_manager import FinalQueue
|
|
36
46
|
|
|
37
47
|
display = Display()
|
|
38
48
|
|
|
@@ -42,78 +52,37 @@ RETURN_VARS = [x for x in C.MAGIC_VARIABLE_MAPPING.items() if 'become' not in x
|
|
|
42
52
|
__all__ = ['TaskExecutor']
|
|
43
53
|
|
|
44
54
|
|
|
45
|
-
class TaskTimeoutError(BaseException):
|
|
46
|
-
def __init__(self, message="", frame=None):
|
|
47
|
-
|
|
48
|
-
if frame is not None:
|
|
49
|
-
orig = frame
|
|
50
|
-
root = pathlib.Path(__file__).parent
|
|
51
|
-
while not pathlib.Path(frame.f_code.co_filename).is_relative_to(root):
|
|
52
|
-
frame = frame.f_back
|
|
53
|
-
|
|
54
|
-
self.frame = 'Interrupted at %s called from %s' % (orig, frame)
|
|
55
|
-
|
|
56
|
-
super(TaskTimeoutError, self).__init__(message)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def task_timeout(signum, frame):
|
|
60
|
-
raise TaskTimeoutError(frame=frame)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def remove_omit(task_args, omit_token):
|
|
64
|
-
'''
|
|
65
|
-
Remove args with a value equal to the ``omit_token`` recursively
|
|
66
|
-
to align with now having suboptions in the argument_spec
|
|
67
|
-
'''
|
|
68
|
-
|
|
69
|
-
if not isinstance(task_args, dict):
|
|
70
|
-
return task_args
|
|
71
|
-
|
|
72
|
-
new_args = {}
|
|
73
|
-
for i in task_args.items():
|
|
74
|
-
if i[1] == omit_token:
|
|
75
|
-
continue
|
|
76
|
-
elif isinstance(i[1], dict):
|
|
77
|
-
new_args[i[0]] = remove_omit(i[1], omit_token)
|
|
78
|
-
elif isinstance(i[1], list):
|
|
79
|
-
new_args[i[0]] = [remove_omit(v, omit_token) for v in i[1]]
|
|
80
|
-
else:
|
|
81
|
-
new_args[i[0]] = i[1]
|
|
82
|
-
|
|
83
|
-
return new_args
|
|
84
|
-
|
|
85
|
-
|
|
86
55
|
class TaskExecutor:
|
|
87
56
|
|
|
88
|
-
|
|
57
|
+
"""
|
|
89
58
|
This is the main worker class for the executor pipeline, which
|
|
90
59
|
handles loading an action plugin to actually dispatch the task to
|
|
91
60
|
a given host. This class roughly corresponds to the old Runner()
|
|
92
61
|
class.
|
|
93
|
-
|
|
62
|
+
"""
|
|
94
63
|
|
|
95
|
-
def __init__(self, host, task, job_vars, play_context,
|
|
64
|
+
def __init__(self, host, task: Task, job_vars, play_context, loader, shared_loader_obj, final_q: FinalQueue, variable_manager):
|
|
96
65
|
self._host = host
|
|
97
66
|
self._task = task
|
|
98
67
|
self._job_vars = job_vars
|
|
99
68
|
self._play_context = play_context
|
|
100
|
-
self._new_stdin = new_stdin
|
|
101
69
|
self._loader = loader
|
|
102
70
|
self._shared_loader_obj = shared_loader_obj
|
|
103
71
|
self._connection = None
|
|
104
72
|
self._final_q = final_q
|
|
105
73
|
self._variable_manager = variable_manager
|
|
106
74
|
self._loop_eval_error = None
|
|
75
|
+
self._task_templar = TemplateEngine(loader=self._loader, variables=self._job_vars)
|
|
107
76
|
|
|
108
77
|
self._task.squash()
|
|
109
78
|
|
|
110
79
|
def run(self):
|
|
111
|
-
|
|
80
|
+
"""
|
|
112
81
|
The main executor entrypoint, where we determine if the specified
|
|
113
82
|
task requires looping and either runs the task with self._run_loop()
|
|
114
83
|
or self._execute(). After that, the returned results are parsed and
|
|
115
84
|
returned as a dict.
|
|
116
|
-
|
|
85
|
+
"""
|
|
117
86
|
|
|
118
87
|
display.debug("in run() - task %s" % self._task._uuid)
|
|
119
88
|
|
|
@@ -135,10 +104,14 @@ class TaskExecutor:
|
|
|
135
104
|
# loop through the item results and set the global changed/failed/skipped result flags based on any item.
|
|
136
105
|
res['skipped'] = True
|
|
137
106
|
for item in item_results:
|
|
107
|
+
if item.get('_ansible_no_log'):
|
|
108
|
+
res.update(_ansible_no_log=True) # ensure no_log processing recognizes at least one item needs to be censored
|
|
109
|
+
|
|
138
110
|
if 'changed' in item and item['changed'] and not res.get('changed'):
|
|
139
111
|
res['changed'] = True
|
|
140
112
|
if res['skipped'] and ('skipped' not in item or ('skipped' in item and not item['skipped'])):
|
|
141
113
|
res['skipped'] = False
|
|
114
|
+
# FIXME: normalize `failed` to a bool, warn if the action/module used non-bool
|
|
142
115
|
if 'failed' in item and item['failed']:
|
|
143
116
|
item_ignore = item.pop('_ansible_ignore_errors')
|
|
144
117
|
if not res.get('failed'):
|
|
@@ -165,6 +138,7 @@ class TaskExecutor:
|
|
|
165
138
|
res[array] = res[array] + item[array]
|
|
166
139
|
del item[array]
|
|
167
140
|
|
|
141
|
+
# FIXME: normalize `failed` to a bool, warn if the action/module used non-bool
|
|
168
142
|
if not res.get('failed', False):
|
|
169
143
|
res['msg'] = 'All items completed'
|
|
170
144
|
if res['skipped']:
|
|
@@ -173,43 +147,23 @@ class TaskExecutor:
|
|
|
173
147
|
res = dict(changed=False, skipped=True, skipped_reason='No items in the list', results=[])
|
|
174
148
|
else:
|
|
175
149
|
display.debug("calling self._execute()")
|
|
176
|
-
res = self._execute()
|
|
150
|
+
res = self._execute(self._task_templar, self._job_vars)
|
|
177
151
|
display.debug("_execute() done")
|
|
178
152
|
|
|
179
153
|
# make sure changed is set in the result, if it's not present
|
|
180
154
|
if 'changed' not in res:
|
|
181
155
|
res['changed'] = False
|
|
182
156
|
|
|
183
|
-
def _clean_res(res, errors='surrogate_or_strict'):
|
|
184
|
-
if isinstance(res, binary_type):
|
|
185
|
-
return to_unsafe_text(res, errors=errors)
|
|
186
|
-
elif isinstance(res, dict):
|
|
187
|
-
for k in res:
|
|
188
|
-
try:
|
|
189
|
-
res[k] = _clean_res(res[k], errors=errors)
|
|
190
|
-
except UnicodeError:
|
|
191
|
-
if k == 'diff':
|
|
192
|
-
# If this is a diff, substitute a replacement character if the value
|
|
193
|
-
# is undecodable as utf8. (Fix #21804)
|
|
194
|
-
display.warning("We were unable to decode all characters in the module return data."
|
|
195
|
-
" Replaced some in an effort to return as much as possible")
|
|
196
|
-
res[k] = _clean_res(res[k], errors='surrogate_then_replace')
|
|
197
|
-
else:
|
|
198
|
-
raise
|
|
199
|
-
elif isinstance(res, list):
|
|
200
|
-
for idx, item in enumerate(res):
|
|
201
|
-
res[idx] = _clean_res(item, errors=errors)
|
|
202
|
-
return res
|
|
203
|
-
|
|
204
|
-
display.debug("dumping result to json")
|
|
205
|
-
res = _clean_res(res)
|
|
206
|
-
display.debug("done dumping result, returning")
|
|
207
157
|
return res
|
|
208
|
-
except
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
158
|
+
except Exception as ex:
|
|
159
|
+
result = _error_utils.result_dict_from_exception(ex)
|
|
160
|
+
|
|
161
|
+
self._task.update_result_no_log(self._task_templar, result)
|
|
162
|
+
|
|
163
|
+
if not isinstance(ex, AnsibleError):
|
|
164
|
+
result.update(msg=f'Unexpected failure during task execution: {result["msg"]}')
|
|
165
|
+
|
|
166
|
+
return result
|
|
213
167
|
finally:
|
|
214
168
|
try:
|
|
215
169
|
self._connection.close()
|
|
@@ -218,11 +172,11 @@ class TaskExecutor:
|
|
|
218
172
|
except Exception as e:
|
|
219
173
|
display.debug(u"error closing connection: %s" % to_text(e))
|
|
220
174
|
|
|
221
|
-
def _get_loop_items(self):
|
|
222
|
-
|
|
175
|
+
def _get_loop_items(self) -> list[t.Any] | None:
|
|
176
|
+
"""
|
|
223
177
|
Loads a lookup plugin to handle the with_* portion of a task (if specified),
|
|
224
178
|
and returns the items result.
|
|
225
|
-
|
|
179
|
+
"""
|
|
226
180
|
|
|
227
181
|
# get search path for this task to pass to lookup plugins
|
|
228
182
|
self._job_vars['ansible_search_path'] = self._task.get_search_path()
|
|
@@ -231,49 +185,51 @@ class TaskExecutor:
|
|
|
231
185
|
if self._loader.get_basedir() not in self._job_vars['ansible_search_path']:
|
|
232
186
|
self._job_vars['ansible_search_path'].append(self._loader.get_basedir())
|
|
233
187
|
|
|
234
|
-
templar = Templar(loader=self._loader, variables=self._job_vars)
|
|
235
188
|
items = None
|
|
236
189
|
if self._task.loop_with:
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
190
|
+
templar = self._task_templar
|
|
191
|
+
terms = self._task.loop
|
|
192
|
+
|
|
193
|
+
if isinstance(terms, str):
|
|
194
|
+
terms = templar.resolve_to_container(_utils.str_problematic_strip(terms))
|
|
195
|
+
|
|
196
|
+
if not isinstance(terms, list):
|
|
197
|
+
terms = [terms]
|
|
198
|
+
|
|
199
|
+
@_DirectCall.mark
|
|
200
|
+
def invoke_lookup() -> t.Any:
|
|
201
|
+
"""Scope-capturing wrapper around _invoke_lookup to avoid functools.partial obscuring its usage from type-checking tools."""
|
|
202
|
+
return _invoke_lookup(
|
|
203
|
+
plugin_name=self._task.loop_with,
|
|
204
|
+
lookup_terms=terms,
|
|
205
|
+
lookup_kwargs=dict(wantlist=True),
|
|
206
|
+
invoked_as_with=True,
|
|
207
|
+
)
|
|
246
208
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
break
|
|
251
|
-
setattr(mylookup, '_subdir', subdir + 's')
|
|
252
|
-
|
|
253
|
-
# run lookup
|
|
254
|
-
items = wrap_var(mylookup.run(terms=loop_terms, variables=self._job_vars, wantlist=True))
|
|
255
|
-
else:
|
|
256
|
-
raise AnsibleError("Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % self._task.loop_with)
|
|
209
|
+
# Smuggle a special wrapped lookup invocation in as a local variable for its exclusive use when being evaluated as `with_(lookup)`.
|
|
210
|
+
# This value will not be visible to other users of this templar or its `available_variables`.
|
|
211
|
+
items = templar.evaluate_expression(expression=TrustedAsTemplate().tag("invoke_lookup()"), local_variables=dict(invoke_lookup=invoke_lookup))
|
|
257
212
|
|
|
258
213
|
elif self._task.loop is not None:
|
|
259
|
-
items =
|
|
214
|
+
items = self._task_templar.template(self._task.loop)
|
|
215
|
+
|
|
260
216
|
if not isinstance(items, list):
|
|
261
217
|
raise AnsibleError(
|
|
262
|
-
"
|
|
263
|
-
"
|
|
264
|
-
|
|
218
|
+
f"The `loop` value must resolve to a 'list', not {native_type_name(items)!r}.",
|
|
219
|
+
help_text="Provide a list of items/templates, or a template resolving to a list.",
|
|
220
|
+
obj=self._task.loop,
|
|
265
221
|
)
|
|
266
222
|
|
|
267
223
|
return items
|
|
268
224
|
|
|
269
|
-
def _run_loop(self, items):
|
|
270
|
-
|
|
225
|
+
def _run_loop(self, items: list[t.Any]) -> list[dict[str, t.Any]]:
|
|
226
|
+
"""
|
|
271
227
|
Runs the task with the loop items specified and collates the result
|
|
272
228
|
into an array named 'results' which is inserted into the final result
|
|
273
229
|
along with the item for which the loop ran.
|
|
274
|
-
|
|
230
|
+
"""
|
|
275
231
|
task_vars = self._job_vars
|
|
276
|
-
templar =
|
|
232
|
+
templar = TemplateEngine(loader=self._loader, variables=task_vars)
|
|
277
233
|
|
|
278
234
|
self._task.loop_control.post_validate(templar=templar)
|
|
279
235
|
|
|
@@ -282,17 +238,20 @@ class TaskExecutor:
|
|
|
282
238
|
loop_pause = self._task.loop_control.pause
|
|
283
239
|
extended = self._task.loop_control.extended
|
|
284
240
|
extended_allitems = self._task.loop_control.extended_allitems
|
|
241
|
+
|
|
285
242
|
# ensure we always have a label
|
|
286
|
-
label = self._task.loop_control.label or
|
|
243
|
+
label = self._task.loop_control.label or templar.variable_name_as_template(loop_var)
|
|
287
244
|
|
|
288
245
|
if loop_var in task_vars:
|
|
289
|
-
display.warning(
|
|
290
|
-
|
|
291
|
-
|
|
246
|
+
display.warning(
|
|
247
|
+
msg=f"The loop variable {loop_var!r} is already in use.",
|
|
248
|
+
help_text="You should set the `loop_var` value in the `loop_control` option for the task "
|
|
249
|
+
"to something else to avoid variable collisions and unexpected behavior.",
|
|
250
|
+
obj=loop_var,
|
|
251
|
+
)
|
|
292
252
|
|
|
293
253
|
ran_once = False
|
|
294
254
|
task_fields = None
|
|
295
|
-
no_log = False
|
|
296
255
|
items_len = len(items)
|
|
297
256
|
results = []
|
|
298
257
|
for item_index, item in enumerate(items):
|
|
@@ -332,7 +291,7 @@ class TaskExecutor:
|
|
|
332
291
|
ran_once = True
|
|
333
292
|
|
|
334
293
|
try:
|
|
335
|
-
tmp_task = self._task.copy(exclude_parent=True, exclude_tasks=True)
|
|
294
|
+
tmp_task: Task = self._task.copy(exclude_parent=True, exclude_tasks=True)
|
|
336
295
|
tmp_task._parent = self._task._parent
|
|
337
296
|
tmp_play_context = self._play_context.copy()
|
|
338
297
|
except AnsibleParserError as e:
|
|
@@ -341,9 +300,11 @@ class TaskExecutor:
|
|
|
341
300
|
|
|
342
301
|
# now we swap the internal task and play context with their copies,
|
|
343
302
|
# execute, and swap them back so we can do the next iteration cleanly
|
|
303
|
+
# NB: this swap-a-dee-doo confuses some type checkers about the type of tmp_task/self._task
|
|
344
304
|
(self._task, tmp_task) = (tmp_task, self._task)
|
|
345
305
|
(self._play_context, tmp_play_context) = (tmp_play_context, self._play_context)
|
|
346
|
-
|
|
306
|
+
|
|
307
|
+
res = self._execute(templar=templar, variables=task_vars)
|
|
347
308
|
|
|
348
309
|
if self._task.register:
|
|
349
310
|
# Ensure per loop iteration results are registered in case `_execute()`
|
|
@@ -355,9 +316,6 @@ class TaskExecutor:
|
|
|
355
316
|
(self._task, tmp_task) = (tmp_task, self._task)
|
|
356
317
|
(self._play_context, tmp_play_context) = (tmp_play_context, self._play_context)
|
|
357
318
|
|
|
358
|
-
# update 'general no_log' based on specific no_log
|
|
359
|
-
no_log = no_log or tmp_task.no_log
|
|
360
|
-
|
|
361
319
|
# now update the result with the item info, and append the result
|
|
362
320
|
# to the list of results
|
|
363
321
|
res[loop_var] = item
|
|
@@ -385,13 +343,14 @@ class TaskExecutor:
|
|
|
385
343
|
if self._connection and not isinstance(self._connection, string_types):
|
|
386
344
|
task_fields['connection'] = getattr(self._connection, 'ansible_name')
|
|
387
345
|
|
|
388
|
-
tr =
|
|
389
|
-
self._host
|
|
390
|
-
self._task
|
|
391
|
-
res,
|
|
346
|
+
tr = _RawTaskResult(
|
|
347
|
+
host=self._host,
|
|
348
|
+
task=self._task,
|
|
349
|
+
return_data=res,
|
|
392
350
|
task_fields=task_fields,
|
|
393
351
|
)
|
|
394
352
|
|
|
353
|
+
# FIXME: normalize `failed` to a bool, warn if the action/module used non-bool
|
|
395
354
|
if tr.is_failed() or tr.is_unreachable():
|
|
396
355
|
self._final_q.send_callback('v2_runner_item_on_failed', tr)
|
|
397
356
|
elif tr.is_skipped():
|
|
@@ -406,11 +365,14 @@ class TaskExecutor:
|
|
|
406
365
|
|
|
407
366
|
# break loop if break_when conditions are met
|
|
408
367
|
if self._task.loop_control and self._task.loop_control.break_when:
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
368
|
+
break_when = self._task.loop_control.get_validated_value(
|
|
369
|
+
'break_when',
|
|
370
|
+
self._task.loop_control.fattributes.get('break_when'),
|
|
371
|
+
self._task.loop_control.break_when,
|
|
372
|
+
templar,
|
|
412
373
|
)
|
|
413
|
-
|
|
374
|
+
|
|
375
|
+
if self._task._resolve_conditional(break_when, task_vars):
|
|
414
376
|
# delete loop vars before exiting loop
|
|
415
377
|
del task_vars[loop_var]
|
|
416
378
|
break
|
|
@@ -432,7 +394,6 @@ class TaskExecutor:
|
|
|
432
394
|
if var in task_vars and var not in self._job_vars:
|
|
433
395
|
del task_vars[var]
|
|
434
396
|
|
|
435
|
-
self._task.no_log = no_log
|
|
436
397
|
# NOTE: run_once cannot contain loop vars because it's templated earlier also
|
|
437
398
|
# This is saving the post-validated field from the last loop so the strategy can use the templated value post task execution
|
|
438
399
|
self._task.run_once = task_fields.get('run_once')
|
|
@@ -448,21 +409,49 @@ class TaskExecutor:
|
|
|
448
409
|
# At the point this is executed it is safe to mutate self._task,
|
|
449
410
|
# since `self._task` is either a copy referred to by `tmp_task` in `_run_loop`
|
|
450
411
|
# or just a singular non-looped task
|
|
451
|
-
if delegated_host_name:
|
|
452
|
-
self._task.delegate_to = delegated_host_name
|
|
453
|
-
variables.update(delegated_vars)
|
|
454
412
|
|
|
455
|
-
|
|
456
|
-
|
|
413
|
+
self._task.delegate_to = delegated_host_name # always override, since a templated result could be an omit (-> None)
|
|
414
|
+
variables.update(delegated_vars)
|
|
415
|
+
|
|
416
|
+
def _execute(self, templar: TemplateEngine, variables: dict[str, t.Any]) -> dict[str, t.Any]:
|
|
417
|
+
result: dict[str, t.Any]
|
|
418
|
+
|
|
419
|
+
with _DeferredWarningContext(variables=variables) as warning_ctx:
|
|
420
|
+
try:
|
|
421
|
+
# DTFIX-FUTURE: improve error handling to prioritize the earliest exception, turning the remaining ones into warnings
|
|
422
|
+
result = self._execute_internal(templar, variables)
|
|
423
|
+
self._apply_task_result_compat(result, warning_ctx)
|
|
424
|
+
_captured.AnsibleActionCapturedError.maybe_raise_on_result(result)
|
|
425
|
+
except (Exception, _task_timeout.TaskTimeoutError) as ex: # TaskTimeoutError is BaseException
|
|
426
|
+
try:
|
|
427
|
+
raise AnsibleTaskError(obj=self._task.get_ds()) from ex
|
|
428
|
+
except AnsibleTaskError as atex:
|
|
429
|
+
result = _error_utils.result_dict_from_exception(atex, accept_result_contribution=True)
|
|
430
|
+
result.setdefault('changed', False)
|
|
431
|
+
|
|
432
|
+
self._task.update_result_no_log(templar, result)
|
|
433
|
+
|
|
434
|
+
# The warnings/deprecations in the result have already been captured in the _DeferredWarningContext by _apply_task_result_compat.
|
|
435
|
+
# The captured warnings/deprecations are a superset of the ones from the result, and may have been converted from a dict to a dataclass.
|
|
436
|
+
# These are then used to supersede the entries in the result.
|
|
437
|
+
|
|
438
|
+
result.pop('warnings', None)
|
|
439
|
+
result.pop('deprecations', None)
|
|
440
|
+
|
|
441
|
+
if warnings := warning_ctx.get_warnings():
|
|
442
|
+
result.update(warnings=warnings)
|
|
443
|
+
|
|
444
|
+
if deprecation_warnings := warning_ctx.get_deprecation_warnings():
|
|
445
|
+
result.update(deprecations=deprecation_warnings)
|
|
446
|
+
|
|
447
|
+
return result
|
|
448
|
+
|
|
449
|
+
def _execute_internal(self, templar: TemplateEngine, variables: dict[str, t.Any]) -> dict[str, t.Any]:
|
|
450
|
+
"""
|
|
457
451
|
The primary workhorse of the executor system, this runs the task
|
|
458
452
|
on the specified host (which may be the delegated_to host) and handles
|
|
459
453
|
the retry/until and block rescue/always execution
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
if variables is None:
|
|
463
|
-
variables = self._job_vars
|
|
464
|
-
|
|
465
|
-
templar = Templar(loader=self._loader, variables=variables)
|
|
454
|
+
"""
|
|
466
455
|
|
|
467
456
|
self._calculate_delegate_to(templar, variables)
|
|
468
457
|
|
|
@@ -498,18 +487,13 @@ class TaskExecutor:
|
|
|
498
487
|
# skipping this task during the conditional evaluation step
|
|
499
488
|
context_validation_error = e
|
|
500
489
|
|
|
501
|
-
no_log = self._play_context.no_log
|
|
502
|
-
|
|
503
490
|
# Evaluate the conditional (if any) for this task, which we do before running
|
|
504
491
|
# the final task post-validation. We do this before the post validation due to
|
|
505
492
|
# the fact that the conditional may specify that the task be skipped due to a
|
|
506
493
|
# variable not being present which would otherwise cause validation to fail
|
|
507
494
|
try:
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
display.debug("when evaluation is False, skipping this task")
|
|
511
|
-
return dict(changed=False, skipped=True, skip_reason='Conditional result was False',
|
|
512
|
-
false_condition=false_condition, _ansible_no_log=no_log)
|
|
495
|
+
if not self._task._resolve_conditional(self._task.when, tempvars, result_context=(rc := t.cast(dict[str, t.Any], {}))):
|
|
496
|
+
return dict(changed=False, skipped=True, skip_reason='Conditional result was False') | rc
|
|
513
497
|
except AnsibleError as e:
|
|
514
498
|
# loop error takes precedence
|
|
515
499
|
if self._loop_eval_error is not None:
|
|
@@ -525,22 +509,27 @@ class TaskExecutor:
|
|
|
525
509
|
|
|
526
510
|
# if we ran into an error while setting up the PlayContext, raise it now, unless is known issue with delegation
|
|
527
511
|
# and undefined vars (correct values are in cvars later on and connection plugins, if still error, blows up there)
|
|
512
|
+
|
|
513
|
+
# DTFIX-FUTURE: this should probably be declaratively handled in post_validate (or better, get rid of play_context)
|
|
528
514
|
if context_validation_error is not None:
|
|
529
515
|
raiseit = True
|
|
530
516
|
if self._task.delegate_to:
|
|
531
|
-
if isinstance(context_validation_error,
|
|
532
|
-
raiseit = False
|
|
533
|
-
elif isinstance(context_validation_error, AnsibleParserError):
|
|
517
|
+
if isinstance(context_validation_error, AnsibleParserError):
|
|
534
518
|
# parser error, might be cause by undef too
|
|
535
|
-
|
|
536
|
-
if isinstance(orig_exc, AnsibleUndefinedVariable):
|
|
519
|
+
if isinstance(context_validation_error.__cause__, AnsibleUndefinedVariable):
|
|
537
520
|
raiseit = False
|
|
521
|
+
elif isinstance(context_validation_error, AnsibleUndefinedVariable):
|
|
522
|
+
# DTFIX-FUTURE: should not be possible to hit this now (all are AnsibleFieldAttributeError)?
|
|
523
|
+
raiseit = False
|
|
538
524
|
if raiseit:
|
|
539
525
|
raise context_validation_error # pylint: disable=raising-bad-type
|
|
540
526
|
|
|
541
527
|
# set templar to use temp variables until loop is evaluated
|
|
542
528
|
templar.available_variables = tempvars
|
|
543
529
|
|
|
530
|
+
# Now we do final validation on the task, which sets all fields to their final values.
|
|
531
|
+
self._task.post_validate(templar=templar)
|
|
532
|
+
|
|
544
533
|
# if this task is a TaskInclude, we just return now with a success code so the
|
|
545
534
|
# main thread can expand the task list for the given host
|
|
546
535
|
if self._task.action in C._ACTION_INCLUDE_TASKS:
|
|
@@ -549,7 +538,6 @@ class TaskExecutor:
|
|
|
549
538
|
if not include_file:
|
|
550
539
|
return dict(failed=True, msg="No include file was specified to the include")
|
|
551
540
|
|
|
552
|
-
include_file = templar.template(include_file)
|
|
553
541
|
return dict(include=include_file, include_args=include_args)
|
|
554
542
|
|
|
555
543
|
# if this task is a IncludeRole, we just return now with a success code so the main thread can expand the task list for the given host
|
|
@@ -557,32 +545,9 @@ class TaskExecutor:
|
|
|
557
545
|
include_args = self._task.args.copy()
|
|
558
546
|
return dict(include_args=include_args)
|
|
559
547
|
|
|
560
|
-
# Now we do final validation on the task, which sets all fields to their final values.
|
|
561
|
-
try:
|
|
562
|
-
self._task.post_validate(templar=templar)
|
|
563
|
-
except AnsibleError:
|
|
564
|
-
raise
|
|
565
|
-
except Exception:
|
|
566
|
-
return dict(changed=False, failed=True, _ansible_no_log=no_log, exception=to_text(traceback.format_exc()))
|
|
567
|
-
if '_variable_params' in self._task.args:
|
|
568
|
-
variable_params = self._task.args.pop('_variable_params')
|
|
569
|
-
if isinstance(variable_params, dict):
|
|
570
|
-
if C.INJECT_FACTS_AS_VARS:
|
|
571
|
-
display.warning("Using a variable for a task's 'args' is unsafe in some situations "
|
|
572
|
-
"(see https://docs.ansible.com/ansible/devel/reference_appendices/faq.html#argsplat-unsafe)")
|
|
573
|
-
variable_params.update(self._task.args)
|
|
574
|
-
self._task.args = variable_params
|
|
575
|
-
else:
|
|
576
|
-
# if we didn't get a dict, it means there's garbage remaining after k=v parsing, just give up
|
|
577
|
-
# see https://github.com/ansible/ansible/issues/79862
|
|
578
|
-
raise AnsibleError(f"invalid or malformed argument: '{variable_params}'")
|
|
579
|
-
|
|
580
|
-
# update no_log to task value, now that we have it templated
|
|
581
|
-
no_log = self._task.no_log
|
|
582
|
-
|
|
583
548
|
# free tempvars up, not used anymore, cvars and vars_copy should be mainly used after this point
|
|
584
549
|
# updating the original 'variables' at the end
|
|
585
|
-
tempvars
|
|
550
|
+
del tempvars
|
|
586
551
|
|
|
587
552
|
# setup cvars copy, used for all connection related templating
|
|
588
553
|
if self._task.delegate_to:
|
|
@@ -634,23 +599,7 @@ class TaskExecutor:
|
|
|
634
599
|
cvars['ansible_python_interpreter'] = sys.executable
|
|
635
600
|
|
|
636
601
|
# get handler
|
|
637
|
-
self._handler,
|
|
638
|
-
|
|
639
|
-
if module_context is not None:
|
|
640
|
-
module_defaults_fqcn = module_context.resolved_fqcn
|
|
641
|
-
else:
|
|
642
|
-
module_defaults_fqcn = self._task.resolved_action
|
|
643
|
-
|
|
644
|
-
# Apply default params for action/module, if present
|
|
645
|
-
self._task.args = get_action_args_with_defaults(
|
|
646
|
-
module_defaults_fqcn, self._task.args, self._task.module_defaults, templar,
|
|
647
|
-
action_groups=self._task._parent._play._action_groups
|
|
648
|
-
)
|
|
649
|
-
|
|
650
|
-
# And filter out any fields which were set to default(omit), and got the omit token value
|
|
651
|
-
omit_token = variables.get('omit')
|
|
652
|
-
if omit_token is not None:
|
|
653
|
-
self._task.args = remove_omit(self._task.args, omit_token)
|
|
602
|
+
self._handler, _module_context = self._get_action_handler_with_module_context(templar=templar)
|
|
654
603
|
|
|
655
604
|
retries = 1 # includes the default actual run + retries set by user/default
|
|
656
605
|
if self._task.retries is not None:
|
|
@@ -667,30 +616,12 @@ class TaskExecutor:
|
|
|
667
616
|
for attempt in range(1, retries + 1):
|
|
668
617
|
display.debug("running the handler")
|
|
669
618
|
try:
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
signal.alarm(self._task.timeout)
|
|
673
|
-
result = self._handler.run(task_vars=vars_copy)
|
|
674
|
-
except (AnsibleActionFail, AnsibleActionSkip) as e:
|
|
675
|
-
return e.result
|
|
676
|
-
except AnsibleConnectionFailure as e:
|
|
677
|
-
return dict(unreachable=True, msg=to_text(e))
|
|
678
|
-
except TaskTimeoutError as e:
|
|
679
|
-
msg = 'The %s action failed to execute in the expected time frame (%d) and was terminated' % (self._task.action, self._task.timeout)
|
|
680
|
-
return dict(failed=True, msg=msg, timedout={'frame': e.frame, 'period': self._task.timeout})
|
|
619
|
+
with _task_timeout.TaskTimeoutError.alarm_timeout(self._task.timeout):
|
|
620
|
+
result = self._handler.run(task_vars=vars_copy)
|
|
681
621
|
finally:
|
|
682
|
-
if self._task.timeout:
|
|
683
|
-
signal.alarm(0)
|
|
684
|
-
old_sig = signal.signal(signal.SIGALRM, old_sig)
|
|
685
622
|
self._handler.cleanup()
|
|
686
623
|
display.debug("handler run complete")
|
|
687
624
|
|
|
688
|
-
# propagate no log to result- the action can set this, so only overwrite it with the task's value if missing or falsey
|
|
689
|
-
result["_ansible_no_log"] = bool(no_log or result.get('_ansible_no_log', False))
|
|
690
|
-
|
|
691
|
-
if self._task.action not in C._ACTION_WITH_CLEAN_FACTS:
|
|
692
|
-
result = wrap_var(result)
|
|
693
|
-
|
|
694
625
|
# update the local copy of vars with the registered value, if specified,
|
|
695
626
|
# or any facts which may have been generated by the module execution
|
|
696
627
|
if self._task.register:
|
|
@@ -702,37 +633,23 @@ class TaskExecutor:
|
|
|
702
633
|
if result.get('failed'):
|
|
703
634
|
self._final_q.send_callback(
|
|
704
635
|
'v2_runner_on_async_failed',
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
636
|
+
_RawTaskResult(
|
|
637
|
+
host=self._host,
|
|
638
|
+
task=self._task,
|
|
639
|
+
return_data=result,
|
|
640
|
+
task_fields=self._task.dump_attrs(),
|
|
641
|
+
),
|
|
642
|
+
)
|
|
709
643
|
else:
|
|
710
644
|
self._final_q.send_callback(
|
|
711
645
|
'v2_runner_on_async_ok',
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
# helper methods for use below in evaluating changed/failed_when
|
|
721
|
-
def _evaluate_changed_when_result(result):
|
|
722
|
-
if self._task.changed_when is not None and self._task.changed_when:
|
|
723
|
-
cond = Conditional(loader=self._loader)
|
|
724
|
-
cond.when = self._task.changed_when
|
|
725
|
-
result['changed'] = cond.evaluate_conditional(templar, vars_copy)
|
|
726
|
-
|
|
727
|
-
def _evaluate_failed_when_result(result):
|
|
728
|
-
if self._task.failed_when:
|
|
729
|
-
cond = Conditional(loader=self._loader)
|
|
730
|
-
cond.when = self._task.failed_when
|
|
731
|
-
failed_when_result = cond.evaluate_conditional(templar, vars_copy)
|
|
732
|
-
result['failed_when_result'] = result['failed'] = failed_when_result
|
|
733
|
-
else:
|
|
734
|
-
failed_when_result = False
|
|
735
|
-
return failed_when_result
|
|
646
|
+
_RawTaskResult(
|
|
647
|
+
host=self._host,
|
|
648
|
+
task=self._task,
|
|
649
|
+
return_data=result,
|
|
650
|
+
task_fields=self._task.dump_attrs(),
|
|
651
|
+
),
|
|
652
|
+
)
|
|
736
653
|
|
|
737
654
|
if 'ansible_facts' in result and self._task.action not in C._ACTION_DEBUG:
|
|
738
655
|
if self._task.action in C._ACTION_WITH_CLEAN_FACTS:
|
|
@@ -745,10 +662,11 @@ class TaskExecutor:
|
|
|
745
662
|
vars_copy.update(result['ansible_facts'])
|
|
746
663
|
else:
|
|
747
664
|
# TODO: cleaning of facts should eventually become part of taskresults instead of vars
|
|
748
|
-
af =
|
|
665
|
+
af = result['ansible_facts']
|
|
749
666
|
vars_copy['ansible_facts'] = combine_vars(vars_copy.get('ansible_facts', {}), namespace_facts(af))
|
|
750
667
|
if C.INJECT_FACTS_AS_VARS:
|
|
751
|
-
|
|
668
|
+
cleaned_toplevel = {k: _deprecate_top_level_fact(v) for k, v in clean_facts(af).items()}
|
|
669
|
+
vars_copy.update(cleaned_toplevel)
|
|
752
670
|
|
|
753
671
|
# set the failed property if it was missing.
|
|
754
672
|
if 'failed' not in result:
|
|
@@ -766,9 +684,6 @@ class TaskExecutor:
|
|
|
766
684
|
if 'changed' not in result:
|
|
767
685
|
result['changed'] = False
|
|
768
686
|
|
|
769
|
-
if self._task.action not in C._ACTION_WITH_CLEAN_FACTS:
|
|
770
|
-
result = wrap_var(result)
|
|
771
|
-
|
|
772
687
|
# re-update the local copy of vars with the registered value, if specified,
|
|
773
688
|
# or any facts which may have been generated by the module execution
|
|
774
689
|
# This gives changed/failed_when access to additional recently modified
|
|
@@ -781,18 +696,30 @@ class TaskExecutor:
|
|
|
781
696
|
if 'skipped' not in result:
|
|
782
697
|
condname = 'changed'
|
|
783
698
|
|
|
699
|
+
# DTFIX-FUTURE: error normalization has not yet occurred; this means that the expressions used for until/failed_when/changed_when/break_when
|
|
700
|
+
# and when (for loops on the second and later iterations) cannot see the normalized error shapes. This, and the current impl of the expression
|
|
701
|
+
# handling here causes a number of problems:
|
|
702
|
+
# * any error in one of the post-task exec expressions is silently ignored and detail lost (eg: `failed_when: syntax ERROR @$123`)
|
|
703
|
+
# * they cannot reliably access error/warning details, since many of those details are inaccessible until the error normalization occurs
|
|
704
|
+
# * error normalization includes `msg` if present, and supplies `unknown error` if not; this leads to screwy results on True failed_when if
|
|
705
|
+
# `msg` is present, eg: `{debug: {}, failed_when: True` -> "Task failed: Action failed: Hello world!"
|
|
706
|
+
# * detail about failed_when is lost; any error details from the task could potentially be grafted in/preserved if error normalization was done
|
|
707
|
+
|
|
784
708
|
try:
|
|
785
|
-
|
|
709
|
+
if self._task.changed_when is not None and self._task.changed_when:
|
|
710
|
+
result['changed'] = self._task._resolve_conditional(self._task.changed_when, vars_copy)
|
|
711
|
+
|
|
786
712
|
condname = 'failed'
|
|
787
|
-
|
|
713
|
+
|
|
714
|
+
if self._task.failed_when:
|
|
715
|
+
result['failed_when_result'] = result['failed'] = self._task._resolve_conditional(self._task.failed_when, vars_copy)
|
|
716
|
+
|
|
788
717
|
except AnsibleError as e:
|
|
789
718
|
result['failed'] = True
|
|
790
719
|
result['%s_when_result' % condname] = to_text(e)
|
|
791
720
|
|
|
792
721
|
if retries > 1:
|
|
793
|
-
|
|
794
|
-
cond.when = self._task.until or [not result['failed']]
|
|
795
|
-
if cond.evaluate_conditional(templar, vars_copy):
|
|
722
|
+
if self._task._resolve_conditional(self._task.until or [not result['failed']], vars_copy):
|
|
796
723
|
break
|
|
797
724
|
else:
|
|
798
725
|
# no conditional check, or it failed, so sleep for the specified time
|
|
@@ -802,12 +729,12 @@ class TaskExecutor:
|
|
|
802
729
|
display.debug('Retrying task, attempt %d of %d' % (attempt, retries))
|
|
803
730
|
self._final_q.send_callback(
|
|
804
731
|
'v2_runner_retry',
|
|
805
|
-
|
|
806
|
-
self._host
|
|
807
|
-
self._task
|
|
808
|
-
result,
|
|
732
|
+
_RawTaskResult(
|
|
733
|
+
host=self._host,
|
|
734
|
+
task=self._task,
|
|
735
|
+
return_data=result,
|
|
809
736
|
task_fields=self._task.dump_attrs()
|
|
810
|
-
)
|
|
737
|
+
),
|
|
811
738
|
)
|
|
812
739
|
time.sleep(delay)
|
|
813
740
|
self._handler = self._get_action_handler(templar=templar)
|
|
@@ -817,9 +744,6 @@ class TaskExecutor:
|
|
|
817
744
|
result['attempts'] = retries - 1
|
|
818
745
|
result['failed'] = True
|
|
819
746
|
|
|
820
|
-
if self._task.action not in C._ACTION_WITH_CLEAN_FACTS:
|
|
821
|
-
result = wrap_var(result)
|
|
822
|
-
|
|
823
747
|
# do the final update of the local variables here, for both registered
|
|
824
748
|
# values and any facts which may have been created
|
|
825
749
|
if self._task.register:
|
|
@@ -830,10 +754,12 @@ class TaskExecutor:
|
|
|
830
754
|
variables.update(result['ansible_facts'])
|
|
831
755
|
else:
|
|
832
756
|
# TODO: cleaning of facts should eventually become part of taskresults instead of vars
|
|
833
|
-
af =
|
|
757
|
+
af = result['ansible_facts']
|
|
834
758
|
variables['ansible_facts'] = combine_vars(variables.get('ansible_facts', {}), namespace_facts(af))
|
|
835
759
|
if C.INJECT_FACTS_AS_VARS:
|
|
836
|
-
|
|
760
|
+
# DTFIX-FUTURE: why is this happening twice, esp since we're post-fork and these will be discarded?
|
|
761
|
+
cleaned_toplevel = {k: _deprecate_top_level_fact(v) for k, v in clean_facts(af).items()}
|
|
762
|
+
variables.update(cleaned_toplevel)
|
|
837
763
|
|
|
838
764
|
# save the notification target in the result, if it was specified, as
|
|
839
765
|
# this task may be running in a loop in which case the notification
|
|
@@ -858,10 +784,53 @@ class TaskExecutor:
|
|
|
858
784
|
display.debug("attempt loop complete, returning result")
|
|
859
785
|
return result
|
|
860
786
|
|
|
787
|
+
@staticmethod
|
|
788
|
+
def _apply_task_result_compat(result: dict[str, t.Any], warning_ctx: _DeferredWarningContext) -> None:
|
|
789
|
+
"""Apply backward-compatibility mutations to the supplied task result."""
|
|
790
|
+
if warnings := result.get('warnings'):
|
|
791
|
+
if isinstance(warnings, list):
|
|
792
|
+
for warning in warnings:
|
|
793
|
+
if not isinstance(warning, _messages.WarningSummary):
|
|
794
|
+
# translate non-WarningMessageDetail messages
|
|
795
|
+
warning = _messages.WarningSummary(
|
|
796
|
+
event=_messages.Event(
|
|
797
|
+
msg=str(warning),
|
|
798
|
+
),
|
|
799
|
+
)
|
|
800
|
+
|
|
801
|
+
warning_ctx.capture(warning)
|
|
802
|
+
else:
|
|
803
|
+
display.warning(f"Task result `warnings` was {type(warnings)} instead of {list}.")
|
|
804
|
+
|
|
805
|
+
if deprecations := result.get('deprecations'):
|
|
806
|
+
if isinstance(deprecations, list):
|
|
807
|
+
for deprecation in deprecations:
|
|
808
|
+
if not isinstance(deprecation, _messages.DeprecationSummary):
|
|
809
|
+
# translate non-DeprecationSummary message dicts
|
|
810
|
+
try:
|
|
811
|
+
if (collection_name := deprecation.pop('collection_name', ...)) is not ...:
|
|
812
|
+
# deprecated: description='enable the deprecation message for collection_name' core_version='2.23'
|
|
813
|
+
# CAUTION: This deprecation cannot be enabled until the replacement (deprecator) has been documented, and the schema finalized.
|
|
814
|
+
# self.deprecated('The `collection_name` key in the `deprecations` dictionary is deprecated.', version='2.27')
|
|
815
|
+
deprecation.update(deprecator=deprecator_from_collection_name(collection_name))
|
|
816
|
+
|
|
817
|
+
deprecation = _messages.DeprecationSummary(
|
|
818
|
+
event=_messages.Event(
|
|
819
|
+
msg=deprecation.pop('msg'),
|
|
820
|
+
),
|
|
821
|
+
**deprecation,
|
|
822
|
+
)
|
|
823
|
+
except Exception as ex:
|
|
824
|
+
display.error_as_warning("Task result `deprecations` contained an invalid item.", exception=ex)
|
|
825
|
+
|
|
826
|
+
warning_ctx.capture(deprecation)
|
|
827
|
+
else:
|
|
828
|
+
display.warning(f"Task result `deprecations` was {type(deprecations)} instead of {list}.")
|
|
829
|
+
|
|
861
830
|
def _poll_async_result(self, result, templar, task_vars=None):
|
|
862
|
-
|
|
831
|
+
"""
|
|
863
832
|
Polls for the specified JID to be complete
|
|
864
|
-
|
|
833
|
+
"""
|
|
865
834
|
|
|
866
835
|
if task_vars is None:
|
|
867
836
|
task_vars = self._job_vars
|
|
@@ -891,7 +860,7 @@ class TaskExecutor:
|
|
|
891
860
|
connection=self._connection,
|
|
892
861
|
play_context=self._play_context,
|
|
893
862
|
loader=self._loader,
|
|
894
|
-
templar=templar,
|
|
863
|
+
templar=Templar._from_template_engine(templar),
|
|
895
864
|
shared_loader_obj=self._shared_loader_obj,
|
|
896
865
|
)
|
|
897
866
|
|
|
@@ -903,12 +872,12 @@ class TaskExecutor:
|
|
|
903
872
|
async_result = async_handler.run(task_vars=task_vars)
|
|
904
873
|
# We do not bail out of the loop in cases where the failure
|
|
905
874
|
# is associated with a parsing error. The async_runner can
|
|
906
|
-
# have issues which result in a half-written/
|
|
875
|
+
# have issues which result in a half-written/unparsable result
|
|
907
876
|
# file on disk, which manifests to the user as a timeout happening
|
|
908
877
|
# before it's time to timeout.
|
|
909
|
-
if (
|
|
910
|
-
|
|
911
|
-
|
|
878
|
+
if (async_result.get('finished', False) or
|
|
879
|
+
(async_result.get('failed', False) and async_result.get('_ansible_parsed', False)) or
|
|
880
|
+
async_result.get('skipped', False)):
|
|
912
881
|
break
|
|
913
882
|
except Exception as e:
|
|
914
883
|
# Connections can raise exceptions during polling (eg, network bounce, reboot); these should be non-fatal.
|
|
@@ -929,19 +898,19 @@ class TaskExecutor:
|
|
|
929
898
|
time_left -= self._task.poll
|
|
930
899
|
self._final_q.send_callback(
|
|
931
900
|
'v2_runner_on_async_poll',
|
|
932
|
-
|
|
933
|
-
self._host
|
|
934
|
-
async_task
|
|
935
|
-
async_result,
|
|
901
|
+
_RawTaskResult(
|
|
902
|
+
host=self._host,
|
|
903
|
+
task=async_task,
|
|
904
|
+
return_data=async_result,
|
|
936
905
|
task_fields=async_task.dump_attrs(),
|
|
937
906
|
),
|
|
938
907
|
)
|
|
939
908
|
|
|
940
|
-
if
|
|
909
|
+
if not async_result.get('finished', False):
|
|
941
910
|
if async_result.get('_ansible_parsed'):
|
|
942
911
|
return dict(failed=True, msg="async task did not complete within the requested time - %ss" % self._task.async_val, async_result=async_result)
|
|
943
912
|
else:
|
|
944
|
-
return dict(failed=True, msg="async task produced
|
|
913
|
+
return dict(failed=True, msg="async task produced unparsable results", async_result=async_result)
|
|
945
914
|
else:
|
|
946
915
|
# If the async task finished, automatically cleanup the temporary
|
|
947
916
|
# status file left behind.
|
|
@@ -961,7 +930,7 @@ class TaskExecutor:
|
|
|
961
930
|
connection=self._connection,
|
|
962
931
|
play_context=self._play_context,
|
|
963
932
|
loader=self._loader,
|
|
964
|
-
templar=templar,
|
|
933
|
+
templar=Templar._from_template_engine(templar),
|
|
965
934
|
shared_loader_obj=self._shared_loader_obj,
|
|
966
935
|
)
|
|
967
936
|
cleanup_handler.run(task_vars=task_vars)
|
|
@@ -977,10 +946,10 @@ class TaskExecutor:
|
|
|
977
946
|
return become
|
|
978
947
|
|
|
979
948
|
def _get_connection(self, cvars, templar, current_connection):
|
|
980
|
-
|
|
949
|
+
"""
|
|
981
950
|
Reads the connection property for the host, and returns the
|
|
982
951
|
correct connection object from the list of connection plugins
|
|
983
|
-
|
|
952
|
+
"""
|
|
984
953
|
|
|
985
954
|
self._play_context.connection = current_connection
|
|
986
955
|
|
|
@@ -992,7 +961,7 @@ class TaskExecutor:
|
|
|
992
961
|
connection, plugin_load_context = self._shared_loader_obj.connection_loader.get_with_context(
|
|
993
962
|
conn_type,
|
|
994
963
|
self._play_context,
|
|
995
|
-
|
|
964
|
+
new_stdin=None, # No longer used, kept for backwards compat for plugins that explicitly accept this as an arg
|
|
996
965
|
task_uuid=self._task._uuid,
|
|
997
966
|
ansible_playbook_pid=to_text(os.getppid())
|
|
998
967
|
)
|
|
@@ -1058,7 +1027,11 @@ class TaskExecutor:
|
|
|
1058
1027
|
options = {}
|
|
1059
1028
|
for k in option_vars:
|
|
1060
1029
|
if k in variables:
|
|
1061
|
-
|
|
1030
|
+
try:
|
|
1031
|
+
options[k] = templar.template(variables[k])
|
|
1032
|
+
except AnsibleValueOmittedError:
|
|
1033
|
+
pass
|
|
1034
|
+
|
|
1062
1035
|
# TODO move to task method?
|
|
1063
1036
|
plugin.set_options(task_keys=task_keys, var_options=options)
|
|
1064
1037
|
|
|
@@ -1124,15 +1097,15 @@ class TaskExecutor:
|
|
|
1124
1097
|
return varnames
|
|
1125
1098
|
|
|
1126
1099
|
def _get_action_handler(self, templar):
|
|
1127
|
-
|
|
1100
|
+
"""
|
|
1128
1101
|
Returns the correct action plugin to handle the requestion task action
|
|
1129
|
-
|
|
1102
|
+
"""
|
|
1130
1103
|
return self._get_action_handler_with_module_context(templar)[0]
|
|
1131
1104
|
|
|
1132
|
-
def _get_action_handler_with_module_context(self, templar):
|
|
1133
|
-
|
|
1105
|
+
def _get_action_handler_with_module_context(self, templar: TemplateEngine):
|
|
1106
|
+
"""
|
|
1134
1107
|
Returns the correct action plugin to handle the requestion task action and the module context
|
|
1135
|
-
|
|
1108
|
+
"""
|
|
1136
1109
|
module_collection, separator, module_name = self._task.action.rpartition(".")
|
|
1137
1110
|
module_prefix = module_name.split('_')[0]
|
|
1138
1111
|
if module_collection:
|
|
@@ -1156,7 +1129,7 @@ class TaskExecutor:
|
|
|
1156
1129
|
# let action plugin override module, fallback to 'normal' action plugin otherwise
|
|
1157
1130
|
elif self._shared_loader_obj.action_loader.has_plugin(self._task.action, collection_list=collections):
|
|
1158
1131
|
handler_name = self._task.action
|
|
1159
|
-
elif
|
|
1132
|
+
elif module_prefix in C.NETWORK_GROUP_MODULES and self._shared_loader_obj.action_loader.has_plugin(network_action, collection_list=collections):
|
|
1160
1133
|
handler_name = network_action
|
|
1161
1134
|
display.vvvv("Using network group action {handler} for {action}".format(handler=handler_name,
|
|
1162
1135
|
action=self._task.action),
|
|
@@ -1191,7 +1164,7 @@ class TaskExecutor:
|
|
|
1191
1164
|
connection=self._connection,
|
|
1192
1165
|
play_context=self._play_context,
|
|
1193
1166
|
loader=self._loader,
|
|
1194
|
-
templar=templar,
|
|
1167
|
+
templar=Templar._from_template_engine(templar),
|
|
1195
1168
|
shared_loader_obj=self._shared_loader_obj,
|
|
1196
1169
|
collection_list=collections
|
|
1197
1170
|
)
|
|
@@ -1206,9 +1179,9 @@ CLI_STUB_NAME = 'ansible_connection_cli_stub.py'
|
|
|
1206
1179
|
|
|
1207
1180
|
|
|
1208
1181
|
def start_connection(play_context, options, task_uuid):
|
|
1209
|
-
|
|
1182
|
+
"""
|
|
1210
1183
|
Starts the persistent connection
|
|
1211
|
-
|
|
1184
|
+
"""
|
|
1212
1185
|
|
|
1213
1186
|
env = os.environ.copy()
|
|
1214
1187
|
env.update({
|