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
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
8
|
import base64
|
|
9
|
+
import contextlib
|
|
9
10
|
import json
|
|
10
11
|
import os
|
|
11
12
|
import re
|
|
@@ -13,29 +14,42 @@ import secrets
|
|
|
13
14
|
import shlex
|
|
14
15
|
import stat
|
|
15
16
|
import tempfile
|
|
17
|
+
import typing as t
|
|
16
18
|
|
|
17
19
|
from abc import ABC, abstractmethod
|
|
18
20
|
from collections.abc import Sequence
|
|
19
21
|
|
|
20
22
|
from ansible import constants as C
|
|
23
|
+
from ansible._internal._errors import _captured, _error_utils
|
|
21
24
|
from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleActionSkip, AnsibleActionFail, AnsibleAuthenticationFailure
|
|
22
|
-
from ansible.executor.module_common import modify_module
|
|
25
|
+
from ansible.executor.module_common import modify_module, _BuiltModule
|
|
23
26
|
from ansible.executor.interpreter_discovery import discover_interpreter, InterpreterDiscoveryRequiredError
|
|
27
|
+
from ansible.module_utils._internal import _traceback
|
|
24
28
|
from ansible.module_utils.common.arg_spec import ArgumentSpecValidator
|
|
25
29
|
from ansible.module_utils.errors import UnsupportedError
|
|
26
30
|
from ansible.module_utils.json_utils import _filter_non_json_lines
|
|
31
|
+
from ansible.module_utils.common.json import Direction, get_module_encoder, get_module_decoder
|
|
27
32
|
from ansible.module_utils.six import binary_type, string_types, text_type
|
|
28
33
|
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
|
|
29
|
-
from ansible.parsing.utils.jsonify import jsonify
|
|
30
34
|
from ansible.release import __version__
|
|
31
35
|
from ansible.utils.collection_loader import resource_from_fqcr
|
|
32
36
|
from ansible.utils.display import Display
|
|
33
|
-
from ansible.utils.unsafe_proxy import wrap_var, AnsibleUnsafeText
|
|
34
37
|
from ansible.vars.clean import remove_internal_keys
|
|
35
38
|
from ansible.utils.plugin_docs import get_versioned_doclink
|
|
39
|
+
from ansible import _internal
|
|
40
|
+
from ansible._internal._templating import _engine
|
|
41
|
+
|
|
42
|
+
from .. import _AnsiblePluginInfoMixin
|
|
36
43
|
|
|
37
44
|
display = Display()
|
|
38
45
|
|
|
46
|
+
if t.TYPE_CHECKING:
|
|
47
|
+
from ansible.parsing.dataloader import DataLoader
|
|
48
|
+
from ansible.playbook.play_context import PlayContext
|
|
49
|
+
from ansible.playbook.task import Task
|
|
50
|
+
from ansible.plugins.connection import ConnectionBase
|
|
51
|
+
from ansible.template import Templar
|
|
52
|
+
|
|
39
53
|
|
|
40
54
|
def _validate_utf8_json(d):
|
|
41
55
|
if isinstance(d, text_type):
|
|
@@ -49,14 +63,13 @@ def _validate_utf8_json(d):
|
|
|
49
63
|
_validate_utf8_json(o)
|
|
50
64
|
|
|
51
65
|
|
|
52
|
-
class ActionBase(ABC):
|
|
53
|
-
|
|
54
|
-
'''
|
|
66
|
+
class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
67
|
+
"""
|
|
55
68
|
This class is the base class for all action plugins, and defines
|
|
56
69
|
code common to all actions. The base class handles the connection
|
|
57
70
|
by putting/getting files and executing commands based on the current
|
|
58
71
|
action in use.
|
|
59
|
-
|
|
72
|
+
"""
|
|
60
73
|
|
|
61
74
|
# A set of valid arguments
|
|
62
75
|
_VALID_ARGS = frozenset([]) # type: frozenset[str]
|
|
@@ -67,28 +80,30 @@ class ActionBase(ABC):
|
|
|
67
80
|
_requires_connection = True
|
|
68
81
|
_supports_check_mode = True
|
|
69
82
|
_supports_async = False
|
|
83
|
+
supports_raw_params = False
|
|
70
84
|
|
|
71
|
-
def __init__(self, task, connection, play_context, loader, templar, shared_loader_obj):
|
|
85
|
+
def __init__(self, task: Task, connection: ConnectionBase, play_context: PlayContext, loader: DataLoader, templar: Templar, shared_loader_obj=None):
|
|
72
86
|
self._task = task
|
|
73
87
|
self._connection = connection
|
|
74
88
|
self._play_context = play_context
|
|
75
89
|
self._loader = loader
|
|
76
90
|
self._templar = templar
|
|
77
|
-
|
|
91
|
+
|
|
92
|
+
from ansible.plugins import loader as plugin_loaders # avoid circular global import since PluginLoader needs ActionBase
|
|
93
|
+
|
|
94
|
+
self._shared_loader_obj = plugin_loaders # shared_loader_obj was just a ref to `ansible.plugins.loader` anyway; this lets us inherit its type
|
|
78
95
|
self._cleanup_remote_tmp = False
|
|
79
96
|
|
|
80
97
|
# interpreter discovery state
|
|
81
|
-
self._discovered_interpreter_key = None
|
|
98
|
+
self._discovered_interpreter_key: str | None = None
|
|
82
99
|
self._discovered_interpreter = False
|
|
83
|
-
self.
|
|
84
|
-
self._discovery_warnings = []
|
|
85
|
-
self._used_interpreter = None
|
|
100
|
+
self._used_interpreter: str | None = None
|
|
86
101
|
|
|
87
102
|
# Backwards compat: self._display isn't really needed, just import the global display and use that.
|
|
88
103
|
self._display = display
|
|
89
104
|
|
|
90
105
|
@abstractmethod
|
|
91
|
-
def run(self, tmp=None, task_vars=None):
|
|
106
|
+
def run(self, tmp: str | None = None, task_vars: dict[str, t.Any] | None = None) -> dict[str, t.Any]:
|
|
92
107
|
""" Action Plugins should implement this method to perform their
|
|
93
108
|
tasks. Everything else in this base class is a helper method for the
|
|
94
109
|
action plugin to do that.
|
|
@@ -104,14 +119,13 @@ class ActionBase(ABC):
|
|
|
104
119
|
|
|
105
120
|
* Module parameters. These are stored in self._task.args
|
|
106
121
|
"""
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
result = {}
|
|
122
|
+
# does not default to {'changed': False, 'failed': False}, as it used to break async
|
|
123
|
+
result: dict[str, t.Any] = {}
|
|
110
124
|
|
|
111
125
|
if tmp is not None:
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
126
|
+
display.warning('ActionModule.run() no longer honors the tmp parameter. Action'
|
|
127
|
+
' plugins should set self._connection._shell.tmpdir to share'
|
|
128
|
+
' the tmpdir.')
|
|
115
129
|
del tmp
|
|
116
130
|
|
|
117
131
|
if self._task.async_val and not self._supports_async:
|
|
@@ -177,7 +191,7 @@ class ActionBase(ABC):
|
|
|
177
191
|
if isinstance(error, UnsupportedError):
|
|
178
192
|
msg = f"Unsupported parameters for ({self._load_name}) module: {msg}"
|
|
179
193
|
|
|
180
|
-
raise AnsibleActionFail(msg)
|
|
194
|
+
raise AnsibleActionFail(msg, obj=self._task.args)
|
|
181
195
|
|
|
182
196
|
return validation_result, new_module_args
|
|
183
197
|
|
|
@@ -193,6 +207,28 @@ class ActionBase(ABC):
|
|
|
193
207
|
if force or not self._task.async_val:
|
|
194
208
|
self._remove_tmp_path(self._connection._shell.tmpdir)
|
|
195
209
|
|
|
210
|
+
@classmethod
|
|
211
|
+
@contextlib.contextmanager
|
|
212
|
+
@_internal.experimental
|
|
213
|
+
def get_finalize_task_args_context(cls) -> t.Any:
|
|
214
|
+
"""
|
|
215
|
+
EXPERIMENTAL: Unstable API subject to change at any time without notice.
|
|
216
|
+
Wraps task arg finalization with (optional) stateful context.
|
|
217
|
+
The context manager is entered during `Task.post_validate_args, and may yield a single value to be passed
|
|
218
|
+
as `context` to Task.finalize_task_arg for each task arg.
|
|
219
|
+
"""
|
|
220
|
+
yield None
|
|
221
|
+
|
|
222
|
+
@classmethod
|
|
223
|
+
@_internal.experimental
|
|
224
|
+
def finalize_task_arg(cls, name: str, value: t.Any, templar: _engine.TemplateEngine, context: t.Any) -> t.Any:
|
|
225
|
+
"""
|
|
226
|
+
EXPERIMENTAL: Unstable API subject to change at any time without notice.
|
|
227
|
+
Called for each task arg to allow for custom templating.
|
|
228
|
+
The optional `context` value is sourced from `Task.get_finalize_task_args_context`.
|
|
229
|
+
"""
|
|
230
|
+
return templar.template(value)
|
|
231
|
+
|
|
196
232
|
def get_plugin_option(self, plugin, option, default=None):
|
|
197
233
|
"""Helper to get an option from a plugin without having to use
|
|
198
234
|
the try/except dance everywhere to set a default
|
|
@@ -218,11 +254,11 @@ class ActionBase(ABC):
|
|
|
218
254
|
return True
|
|
219
255
|
return False
|
|
220
256
|
|
|
221
|
-
def _configure_module(self, module_name, module_args, task_vars):
|
|
222
|
-
|
|
257
|
+
def _configure_module(self, module_name, module_args, task_vars) -> tuple[_BuiltModule, str]:
|
|
258
|
+
"""
|
|
223
259
|
Handles the loading and templating of the module code through the
|
|
224
260
|
modify_module() function.
|
|
225
|
-
|
|
261
|
+
"""
|
|
226
262
|
if self._task.delegate_to:
|
|
227
263
|
use_vars = task_vars.get('ansible_delegated_vars')[self._task.delegate_to]
|
|
228
264
|
else:
|
|
@@ -276,38 +312,29 @@ class ActionBase(ABC):
|
|
|
276
312
|
raise AnsibleError("The module %s was not found in configured module paths" % (module_name))
|
|
277
313
|
|
|
278
314
|
# insert shared code and arguments into the module
|
|
279
|
-
final_environment =
|
|
315
|
+
final_environment: dict[str, t.Any] = {}
|
|
280
316
|
self._compute_environment_string(final_environment)
|
|
281
317
|
|
|
282
|
-
become_kwargs = {}
|
|
283
|
-
if self._connection.become:
|
|
284
|
-
become_kwargs['become'] = True
|
|
285
|
-
become_kwargs['become_method'] = self._connection.become.name
|
|
286
|
-
become_kwargs['become_user'] = self._connection.become.get_option('become_user',
|
|
287
|
-
playcontext=self._play_context)
|
|
288
|
-
become_kwargs['become_password'] = self._connection.become.get_option('become_pass',
|
|
289
|
-
playcontext=self._play_context)
|
|
290
|
-
become_kwargs['become_flags'] = self._connection.become.get_option('become_flags',
|
|
291
|
-
playcontext=self._play_context)
|
|
292
|
-
|
|
293
318
|
# modify_module will exit early if interpreter discovery is required; re-run after if necessary
|
|
294
|
-
for
|
|
319
|
+
for _dummy in (1, 2):
|
|
295
320
|
try:
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
321
|
+
module_bits = modify_module(
|
|
322
|
+
module_name=module_name,
|
|
323
|
+
module_path=module_path,
|
|
324
|
+
module_args=module_args,
|
|
325
|
+
templar=self._templar,
|
|
326
|
+
task_vars=use_vars,
|
|
327
|
+
module_compression=C.config.get_config_value('DEFAULT_MODULE_COMPRESSION', variables=task_vars),
|
|
328
|
+
async_timeout=self._task.async_val,
|
|
329
|
+
environment=final_environment,
|
|
330
|
+
remote_is_local=bool(getattr(self._connection, '_remote_is_local', False)),
|
|
331
|
+
become_plugin=self._connection.become,
|
|
332
|
+
)
|
|
333
|
+
|
|
304
334
|
break
|
|
305
335
|
except InterpreterDiscoveryRequiredError as idre:
|
|
306
|
-
self._discovered_interpreter =
|
|
307
|
-
|
|
308
|
-
interpreter_name=idre.interpreter_name,
|
|
309
|
-
discovery_mode=idre.discovery_mode,
|
|
310
|
-
task_vars=use_vars))
|
|
336
|
+
self._discovered_interpreter = discover_interpreter(action=self, interpreter_name=idre.interpreter_name,
|
|
337
|
+
discovery_mode=idre.discovery_mode, task_vars=use_vars)
|
|
311
338
|
|
|
312
339
|
# update the local task_vars with the discovered interpreter (which might be None);
|
|
313
340
|
# we'll propagate back to the controller in the task result
|
|
@@ -327,12 +354,12 @@ class ActionBase(ABC):
|
|
|
327
354
|
else:
|
|
328
355
|
task_vars['ansible_delegated_vars'][self._task.delegate_to]['ansible_facts'][discovered_key] = self._discovered_interpreter
|
|
329
356
|
|
|
330
|
-
return
|
|
357
|
+
return module_bits, module_path
|
|
331
358
|
|
|
332
359
|
def _compute_environment_string(self, raw_environment_out=None):
|
|
333
|
-
|
|
360
|
+
"""
|
|
334
361
|
Builds the environment string to be used when executing the remote task.
|
|
335
|
-
|
|
362
|
+
"""
|
|
336
363
|
|
|
337
364
|
final_environment = dict()
|
|
338
365
|
if self._task.environment is not None:
|
|
@@ -363,52 +390,28 @@ class ActionBase(ABC):
|
|
|
363
390
|
return self._connection._shell.env_prefix(**final_environment)
|
|
364
391
|
|
|
365
392
|
def _early_needs_tmp_path(self):
|
|
366
|
-
|
|
393
|
+
"""
|
|
367
394
|
Determines if a tmp path should be created before the action is executed.
|
|
368
|
-
|
|
395
|
+
"""
|
|
369
396
|
|
|
370
397
|
return getattr(self, 'TRANSFERS_FILES', False)
|
|
371
398
|
|
|
372
|
-
def _is_pipelining_enabled(self, module_style, wrap_async=False):
|
|
373
|
-
|
|
374
|
-
Determines if we are required and can do pipelining
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
try:
|
|
378
|
-
is_enabled = self._connection.get_option('pipelining')
|
|
379
|
-
except (KeyError, AttributeError, ValueError):
|
|
380
|
-
is_enabled = self._play_context.pipelining
|
|
381
|
-
|
|
382
|
-
# winrm supports async pipeline
|
|
383
|
-
# TODO: make other class property 'has_async_pipelining' to separate cases
|
|
384
|
-
always_pipeline = self._connection.always_pipeline_modules
|
|
385
|
-
|
|
386
|
-
# su does not work with pipelining
|
|
387
|
-
# TODO: add has_pipelining class prop to become plugins
|
|
388
|
-
become_exception = (self._connection.become.name if self._connection.become else '') != 'su'
|
|
389
|
-
|
|
390
|
-
# any of these require a true
|
|
391
|
-
conditions = [
|
|
392
|
-
self._connection.has_pipelining, # connection class supports it
|
|
393
|
-
is_enabled or always_pipeline, # enabled via config or forced via connection (eg winrm)
|
|
394
|
-
module_style == "new", # old style modules do not support pipelining
|
|
395
|
-
not C.DEFAULT_KEEP_REMOTE_FILES, # user wants remote files
|
|
396
|
-
not wrap_async or always_pipeline, # async does not normally support pipelining unless it does (eg winrm)
|
|
397
|
-
become_exception,
|
|
398
|
-
]
|
|
399
|
-
|
|
400
|
-
return all(conditions)
|
|
399
|
+
def _is_pipelining_enabled(self, module_style: str, wrap_async: bool = False) -> bool:
|
|
400
|
+
"""
|
|
401
|
+
Determines if we are required and can do pipelining, only 'new' style modules can support pipelining
|
|
402
|
+
"""
|
|
403
|
+
return bool(module_style == 'new' and self._connection.is_pipelining_enabled(wrap_async))
|
|
401
404
|
|
|
402
405
|
def _get_admin_users(self):
|
|
403
|
-
|
|
406
|
+
"""
|
|
404
407
|
Returns a list of admin users that are configured for the current shell
|
|
405
408
|
plugin
|
|
406
|
-
|
|
409
|
+
"""
|
|
407
410
|
|
|
408
411
|
return self.get_shell_option('admin_users', ['root'])
|
|
409
412
|
|
|
410
413
|
def _get_remote_addr(self, tvars):
|
|
411
|
-
|
|
414
|
+
""" consistently get the 'remote_address' for the action plugin """
|
|
412
415
|
remote_addr = tvars.get('delegated_vars', {}).get('ansible_host', tvars.get('ansible_host', tvars.get('inventory_hostname', None)))
|
|
413
416
|
for variation in ('remote_addr', 'host'):
|
|
414
417
|
try:
|
|
@@ -422,7 +425,7 @@ class ActionBase(ABC):
|
|
|
422
425
|
return remote_addr
|
|
423
426
|
|
|
424
427
|
def _get_remote_user(self):
|
|
425
|
-
|
|
428
|
+
""" consistently get the 'remote_user' for the action plugin """
|
|
426
429
|
# TODO: use 'current user running ansible' as fallback when moving away from play_context
|
|
427
430
|
# pwd.getpwuid(os.getuid()).pw_name
|
|
428
431
|
remote_user = None
|
|
@@ -437,10 +440,10 @@ class ActionBase(ABC):
|
|
|
437
440
|
return remote_user
|
|
438
441
|
|
|
439
442
|
def _is_become_unprivileged(self):
|
|
440
|
-
|
|
443
|
+
"""
|
|
441
444
|
The user is not the same as the connection user and is not part of the
|
|
442
445
|
shell configured admin users
|
|
443
|
-
|
|
446
|
+
"""
|
|
444
447
|
# if we don't use become then we know we aren't switching to a
|
|
445
448
|
# different unprivileged user
|
|
446
449
|
if not self._connection.become:
|
|
@@ -454,9 +457,9 @@ class ActionBase(ABC):
|
|
|
454
457
|
return bool(become_user and become_user not in admin_users + [remote_user])
|
|
455
458
|
|
|
456
459
|
def _make_tmp_path(self, remote_user=None):
|
|
457
|
-
|
|
460
|
+
"""
|
|
458
461
|
Create and return a temporary path on a remote box.
|
|
459
|
-
|
|
462
|
+
"""
|
|
460
463
|
|
|
461
464
|
# Network connection plugins (network_cli, netconf, etc.) execute on the controller, rather than the remote host.
|
|
462
465
|
# As such, we want to avoid using remote_user for paths as remote_user may not line up with the local user
|
|
@@ -470,8 +473,8 @@ class ActionBase(ABC):
|
|
|
470
473
|
|
|
471
474
|
become_unprivileged = self._is_become_unprivileged()
|
|
472
475
|
basefile = self._connection._shell._generate_temp_dir_name()
|
|
473
|
-
cmd = self._connection._shell.
|
|
474
|
-
result = self._low_level_execute_command(cmd, sudoable=False)
|
|
476
|
+
cmd = self._connection._shell._mkdtemp2(basefile=basefile, system=become_unprivileged, tmpdir=tmpdir)
|
|
477
|
+
result = self._low_level_execute_command(cmd.command, in_data=cmd.input_data, sudoable=False)
|
|
475
478
|
|
|
476
479
|
# error handling on this seems a little aggressive?
|
|
477
480
|
if result['rc'] != 0:
|
|
@@ -517,11 +520,11 @@ class ActionBase(ABC):
|
|
|
517
520
|
return rc
|
|
518
521
|
|
|
519
522
|
def _should_remove_tmp_path(self, tmp_path):
|
|
520
|
-
|
|
523
|
+
"""Determine if temporary path should be deleted or kept by user request/config"""
|
|
521
524
|
return tmp_path and self._cleanup_remote_tmp and not C.DEFAULT_KEEP_REMOTE_FILES and "-tmp-" in tmp_path
|
|
522
525
|
|
|
523
526
|
def _remove_tmp_path(self, tmp_path, force=False):
|
|
524
|
-
|
|
527
|
+
"""Remove a temporary path we created. """
|
|
525
528
|
|
|
526
529
|
if tmp_path is None and self._connection._shell.tmpdir:
|
|
527
530
|
tmp_path = self._connection._shell.tmpdir
|
|
@@ -556,18 +559,19 @@ class ActionBase(ABC):
|
|
|
556
559
|
self._connection.put_file(local_path, remote_path)
|
|
557
560
|
return remote_path
|
|
558
561
|
|
|
559
|
-
def _transfer_data(self, remote_path, data):
|
|
560
|
-
|
|
562
|
+
def _transfer_data(self, remote_path: str | bytes, data: str | bytes) -> str | bytes:
|
|
563
|
+
"""
|
|
561
564
|
Copies the module data out to the temporary module path.
|
|
562
|
-
|
|
565
|
+
"""
|
|
563
566
|
|
|
564
|
-
if isinstance(data,
|
|
565
|
-
data =
|
|
567
|
+
if isinstance(data, str):
|
|
568
|
+
data = data.encode(errors='surrogateescape')
|
|
569
|
+
elif not isinstance(data, bytes):
|
|
570
|
+
raise TypeError('data must be either a string or bytes')
|
|
566
571
|
|
|
567
572
|
afd, afile = tempfile.mkstemp(dir=C.DEFAULT_LOCAL_TMP)
|
|
568
573
|
afo = os.fdopen(afd, 'wb')
|
|
569
574
|
try:
|
|
570
|
-
data = to_bytes(data, errors='surrogate_or_strict')
|
|
571
575
|
afo.write(data)
|
|
572
576
|
except Exception as e:
|
|
573
577
|
raise AnsibleError("failure writing module data to temporary file for transfer: %s" % to_native(e))
|
|
@@ -802,41 +806,41 @@ class ActionBase(ABC):
|
|
|
802
806
|
to_native(res['stderr']), become_link))
|
|
803
807
|
|
|
804
808
|
def _remote_chmod(self, paths, mode, sudoable=False):
|
|
805
|
-
|
|
809
|
+
"""
|
|
806
810
|
Issue a remote chmod command
|
|
807
|
-
|
|
811
|
+
"""
|
|
808
812
|
cmd = self._connection._shell.chmod(paths, mode)
|
|
809
813
|
res = self._low_level_execute_command(cmd, sudoable=sudoable)
|
|
810
814
|
return res
|
|
811
815
|
|
|
812
816
|
def _remote_chown(self, paths, user, sudoable=False):
|
|
813
|
-
|
|
817
|
+
"""
|
|
814
818
|
Issue a remote chown command
|
|
815
|
-
|
|
819
|
+
"""
|
|
816
820
|
cmd = self._connection._shell.chown(paths, user)
|
|
817
821
|
res = self._low_level_execute_command(cmd, sudoable=sudoable)
|
|
818
822
|
return res
|
|
819
823
|
|
|
820
824
|
def _remote_chgrp(self, paths, group, sudoable=False):
|
|
821
|
-
|
|
825
|
+
"""
|
|
822
826
|
Issue a remote chgrp command
|
|
823
|
-
|
|
827
|
+
"""
|
|
824
828
|
cmd = self._connection._shell.chgrp(paths, group)
|
|
825
829
|
res = self._low_level_execute_command(cmd, sudoable=sudoable)
|
|
826
830
|
return res
|
|
827
831
|
|
|
828
832
|
def _remote_set_user_facl(self, paths, user, mode, sudoable=False):
|
|
829
|
-
|
|
833
|
+
"""
|
|
830
834
|
Issue a remote call to setfacl
|
|
831
|
-
|
|
835
|
+
"""
|
|
832
836
|
cmd = self._connection._shell.set_user_facl(paths, user, mode)
|
|
833
837
|
res = self._low_level_execute_command(cmd, sudoable=sudoable)
|
|
834
838
|
return res
|
|
835
839
|
|
|
836
840
|
def _execute_remote_stat(self, path, all_vars, follow, tmp=None, checksum=True):
|
|
837
|
-
|
|
841
|
+
"""
|
|
838
842
|
Get information from remote file.
|
|
839
|
-
|
|
843
|
+
"""
|
|
840
844
|
if tmp is not None:
|
|
841
845
|
display.warning('_execute_remote_stat no longer honors the tmp parameter. Action'
|
|
842
846
|
' plugins should set self._connection._shell.tmpdir to share'
|
|
@@ -876,7 +880,7 @@ class ActionBase(ABC):
|
|
|
876
880
|
return mystat['stat']
|
|
877
881
|
|
|
878
882
|
def _remote_expand_user(self, path, sudoable=True, pathsep=None):
|
|
879
|
-
|
|
883
|
+
""" takes a remote path and performs tilde/$HOME expansion on the remote host """
|
|
880
884
|
|
|
881
885
|
# We only expand ~/path and ~username/path
|
|
882
886
|
if not path.startswith('~'):
|
|
@@ -901,8 +905,8 @@ class ActionBase(ABC):
|
|
|
901
905
|
expand_path = '~%s' % (self._get_remote_user() or '')
|
|
902
906
|
|
|
903
907
|
# use shell to construct appropriate command and execute
|
|
904
|
-
cmd = self._connection._shell.
|
|
905
|
-
data = self._low_level_execute_command(cmd, sudoable=False)
|
|
908
|
+
cmd = self._connection._shell._expand_user2(expand_path)
|
|
909
|
+
data = self._low_level_execute_command(cmd.command, in_data=cmd.input_data, sudoable=False)
|
|
906
910
|
|
|
907
911
|
try:
|
|
908
912
|
initial_fragment = data['stdout'].strip().splitlines()[-1]
|
|
@@ -930,9 +934,9 @@ class ActionBase(ABC):
|
|
|
930
934
|
return expanded
|
|
931
935
|
|
|
932
936
|
def _strip_success_message(self, data):
|
|
933
|
-
|
|
937
|
+
"""
|
|
934
938
|
Removes the BECOME-SUCCESS message from the data.
|
|
935
|
-
|
|
939
|
+
"""
|
|
936
940
|
if data.strip().startswith('BECOME-SUCCESS-'):
|
|
937
941
|
data = re.sub(r'^((\r)?\n)?BECOME-SUCCESS.*(\r)?\n', '', data)
|
|
938
942
|
return data
|
|
@@ -972,9 +976,6 @@ class ActionBase(ABC):
|
|
|
972
976
|
# let module know about filesystems that selinux treats specially
|
|
973
977
|
module_args['_ansible_selinux_special_fs'] = C.DEFAULT_SELINUX_SPECIAL_FS
|
|
974
978
|
|
|
975
|
-
# what to do when parameter values are converted to strings
|
|
976
|
-
module_args['_ansible_string_conversion_action'] = C.STRING_CONVERSION_ACTION
|
|
977
|
-
|
|
978
979
|
# give the module the socket for persistent connections
|
|
979
980
|
module_args['_ansible_socket'] = getattr(self._connection, 'socket_path')
|
|
980
981
|
if not module_args['_ansible_socket']:
|
|
@@ -998,14 +999,16 @@ class ActionBase(ABC):
|
|
|
998
999
|
# tells the module to ignore options that are not in its argspec.
|
|
999
1000
|
module_args['_ansible_ignore_unknown_opts'] = ignore_unknown_opts
|
|
1000
1001
|
|
|
1001
|
-
# allow user to insert string to add context to remote
|
|
1002
|
+
# allow user to insert string to add context to remote logging
|
|
1002
1003
|
module_args['_ansible_target_log_info'] = C.config.get_config_value('TARGET_LOG_INFO', variables=task_vars)
|
|
1003
1004
|
|
|
1005
|
+
module_args['_ansible_tracebacks_for'] = _traceback.traceback_for()
|
|
1006
|
+
|
|
1004
1007
|
def _execute_module(self, module_name=None, module_args=None, tmp=None, task_vars=None, persist_files=False, delete_remote_tmp=None, wrap_async=False,
|
|
1005
1008
|
ignore_unknown_opts: bool = False):
|
|
1006
|
-
|
|
1009
|
+
"""
|
|
1007
1010
|
Transfer and run a module along with its arguments.
|
|
1008
|
-
|
|
1011
|
+
"""
|
|
1009
1012
|
if tmp is not None:
|
|
1010
1013
|
display.warning('_execute_module no longer honors the tmp parameter. Action plugins'
|
|
1011
1014
|
' should set self._connection._shell.tmpdir to share the tmpdir')
|
|
@@ -1047,7 +1050,8 @@ class ActionBase(ABC):
|
|
|
1047
1050
|
self._task.environment.append({"ANSIBLE_ASYNC_DIR": async_dir})
|
|
1048
1051
|
|
|
1049
1052
|
# FUTURE: refactor this along with module build process to better encapsulate "smart wrapper" functionality
|
|
1050
|
-
|
|
1053
|
+
module_bits, module_path = self._configure_module(module_name=module_name, module_args=module_args, task_vars=task_vars)
|
|
1054
|
+
(module_style, shebang, module_data) = (module_bits.module_style, module_bits.shebang, module_bits.b_module_data)
|
|
1051
1055
|
display.vvv("Using module file %s" % module_path)
|
|
1052
1056
|
if not shebang and module_style != 'binary':
|
|
1053
1057
|
raise AnsibleError("module (%s) is missing interpreter line" % module_name)
|
|
@@ -1083,7 +1087,8 @@ class ActionBase(ABC):
|
|
|
1083
1087
|
args_data += '%s=%s ' % (k, shlex.quote(text_type(v)))
|
|
1084
1088
|
self._transfer_data(args_file_path, args_data)
|
|
1085
1089
|
elif module_style in ('non_native_want_json', 'binary'):
|
|
1086
|
-
|
|
1090
|
+
profile_encoder = get_module_encoder(module_bits.serialization_profile, Direction.CONTROLLER_TO_MODULE)
|
|
1091
|
+
self._transfer_data(args_file_path, json.dumps(module_args, cls=profile_encoder))
|
|
1087
1092
|
display.debug("done transferring module to remote")
|
|
1088
1093
|
|
|
1089
1094
|
environment_string = self._compute_environment_string()
|
|
@@ -1106,8 +1111,8 @@ class ActionBase(ABC):
|
|
|
1106
1111
|
|
|
1107
1112
|
if wrap_async and not self._connection.always_pipeline_modules:
|
|
1108
1113
|
# configure, upload, and chmod the async_wrapper module
|
|
1109
|
-
(
|
|
1110
|
-
|
|
1114
|
+
(async_module_bits, async_module_path) = self._configure_module(module_name='ansible.legacy.async_wrapper', module_args=dict(), task_vars=task_vars)
|
|
1115
|
+
(shebang, async_module_data) = (async_module_bits.shebang, async_module_bits.b_module_data)
|
|
1111
1116
|
async_module_remote_filename = self._connection._shell.get_remote_filename(async_module_path)
|
|
1112
1117
|
remote_async_module_path = self._connection._shell.join_path(tmpdir, async_module_remote_filename)
|
|
1113
1118
|
self._transfer_data(remote_async_module_path, async_module_data)
|
|
@@ -1156,7 +1161,7 @@ class ActionBase(ABC):
|
|
|
1156
1161
|
res = self._low_level_execute_command(cmd, sudoable=sudoable, in_data=in_data)
|
|
1157
1162
|
|
|
1158
1163
|
# parse the main result
|
|
1159
|
-
data = self._parse_returned_data(res)
|
|
1164
|
+
data = self._parse_returned_data(res, module_bits.serialization_profile)
|
|
1160
1165
|
|
|
1161
1166
|
# NOTE: INTERNAL KEYS ONLY ACCESSIBLE HERE
|
|
1162
1167
|
# get internal info before cleaning
|
|
@@ -1197,74 +1202,71 @@ class ActionBase(ABC):
|
|
|
1197
1202
|
|
|
1198
1203
|
data['ansible_facts'][self._discovered_interpreter_key] = self._discovered_interpreter
|
|
1199
1204
|
|
|
1200
|
-
if self._discovery_warnings:
|
|
1201
|
-
if data.get('warnings') is None:
|
|
1202
|
-
data['warnings'] = []
|
|
1203
|
-
data['warnings'].extend(self._discovery_warnings)
|
|
1204
|
-
|
|
1205
|
-
if self._discovery_deprecation_warnings:
|
|
1206
|
-
if data.get('deprecations') is None:
|
|
1207
|
-
data['deprecations'] = []
|
|
1208
|
-
data['deprecations'].extend(self._discovery_deprecation_warnings)
|
|
1209
|
-
|
|
1210
|
-
# mark the entire module results untrusted as a template right here, since the current action could
|
|
1211
|
-
# possibly template one of these values.
|
|
1212
|
-
data = wrap_var(data)
|
|
1213
|
-
|
|
1214
1205
|
display.debug("done with _execute_module (%s, %s)" % (module_name, module_args))
|
|
1215
1206
|
return data
|
|
1216
1207
|
|
|
1217
|
-
def _parse_returned_data(self, res):
|
|
1208
|
+
def _parse_returned_data(self, res: dict[str, t.Any], profile: str) -> dict[str, t.Any]:
|
|
1218
1209
|
try:
|
|
1219
|
-
filtered_output, warnings = _filter_non_json_lines(res.get('stdout',
|
|
1210
|
+
filtered_output, warnings = _filter_non_json_lines(res.get('stdout', ''), objects_only=True)
|
|
1211
|
+
|
|
1220
1212
|
for w in warnings:
|
|
1221
1213
|
display.warning(w)
|
|
1222
1214
|
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
except ValueError as e:
|
|
1236
|
-
# not valid json, lets try to capture error
|
|
1237
|
-
data = dict(failed=True, _ansible_parsed=False)
|
|
1238
|
-
data['module_stdout'] = res.get('stdout', u'')
|
|
1239
|
-
if 'stderr' in res:
|
|
1240
|
-
data['module_stderr'] = res['stderr']
|
|
1241
|
-
if res['stderr'].startswith(u'Traceback'):
|
|
1242
|
-
data['exception'] = res['stderr']
|
|
1243
|
-
|
|
1244
|
-
# in some cases a traceback will arrive on stdout instead of stderr, such as when using ssh with -tt
|
|
1245
|
-
if 'exception' not in data and data['module_stdout'].startswith(u'Traceback'):
|
|
1246
|
-
data['exception'] = data['module_stdout']
|
|
1247
|
-
|
|
1248
|
-
# The default
|
|
1249
|
-
data['msg'] = f"MODULE FAILURE: {e}"
|
|
1250
|
-
|
|
1251
|
-
# try to figure out if we are missing interpreter
|
|
1215
|
+
decoder = get_module_decoder(profile, Direction.MODULE_TO_CONTROLLER)
|
|
1216
|
+
|
|
1217
|
+
data = json.loads(filtered_output, cls=decoder)
|
|
1218
|
+
|
|
1219
|
+
_captured.AnsibleModuleCapturedError.normalize_result_exception(data)
|
|
1220
|
+
|
|
1221
|
+
data.update(_ansible_parsed=True) # this must occur after normalize_result_exception, since it checks the type of data to ensure it's a dict
|
|
1222
|
+
except ValueError as ex:
|
|
1223
|
+
message = "Module result deserialization failed."
|
|
1224
|
+
help_text = ""
|
|
1225
|
+
include_cause_message = True
|
|
1226
|
+
|
|
1252
1227
|
if self._used_interpreter is not None:
|
|
1253
|
-
interpreter =
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1228
|
+
interpreter = self._used_interpreter.lstrip('!#')
|
|
1229
|
+
# "not found" case is currently not tested; it was once reproducible
|
|
1230
|
+
# see: https://github.com/ansible/ansible/pull/53534
|
|
1231
|
+
not_found_err_re = re.compile(rf'{re.escape(interpreter)}: (?:No such file or directory|not found|command not found)')
|
|
1232
|
+
|
|
1233
|
+
if not_found_err_re.search(res.get('stderr', '')) or not_found_err_re.search(res.get('stdout', '')):
|
|
1234
|
+
message = f"The module interpreter {interpreter!r} was not found."
|
|
1235
|
+
help_text = 'Consider overriding the configured interpreter path for this host. '
|
|
1236
|
+
include_cause_message = False # cause context *might* be useful in the traceback, but the JSON deserialization failure message is not
|
|
1237
|
+
|
|
1238
|
+
try:
|
|
1239
|
+
# Because the underlying action API is built on result dicts instead of exceptions (for all but the most catastrophic failures),
|
|
1240
|
+
# we're using a tweaked version of the module exception handler to get new ErrorDetail-backed errors from this part of the code.
|
|
1241
|
+
# Ideally this would raise immediately on failure, but this would likely break actions that assume `ActionBase._execute_module()`
|
|
1242
|
+
# does not raise on module failure.
|
|
1257
1243
|
|
|
1258
|
-
|
|
1259
|
-
|
|
1244
|
+
error = AnsibleError(
|
|
1245
|
+
message=message,
|
|
1246
|
+
help_text=help_text + "See stdout/stderr for the returned output.",
|
|
1247
|
+
)
|
|
1248
|
+
|
|
1249
|
+
error._include_cause_message = include_cause_message
|
|
1250
|
+
|
|
1251
|
+
raise error from ex
|
|
1252
|
+
except AnsibleError as ansible_ex:
|
|
1253
|
+
sentinel = object()
|
|
1254
|
+
|
|
1255
|
+
data = _error_utils.result_dict_from_exception(ansible_ex)
|
|
1256
|
+
data.update(
|
|
1257
|
+
_ansible_parsed=False,
|
|
1258
|
+
module_stdout=res.get('stdout', ''),
|
|
1259
|
+
module_stderr=res.get('stderr', sentinel),
|
|
1260
|
+
rc=res.get('rc', sentinel),
|
|
1261
|
+
)
|
|
1262
|
+
|
|
1263
|
+
data = {k: v for k, v in data.items() if v is not sentinel}
|
|
1260
1264
|
|
|
1261
|
-
if 'rc' in res:
|
|
1262
|
-
data['rc'] = res['rc']
|
|
1263
1265
|
return data
|
|
1264
1266
|
|
|
1265
1267
|
# FIXME: move to connection base
|
|
1266
1268
|
def _low_level_execute_command(self, cmd, sudoable=True, in_data=None, executable=None, encoding_errors='surrogate_then_replace', chdir=None):
|
|
1267
|
-
|
|
1269
|
+
"""
|
|
1268
1270
|
This is the function which executes the low level shell command, which
|
|
1269
1271
|
may be commands to create/remove directories for temporary files, or to
|
|
1270
1272
|
run the module code or python directly when pipelining.
|
|
@@ -1277,7 +1279,7 @@ class ActionBase(ABC):
|
|
|
1277
1279
|
verbatim, then this won't work. May have to use some sort of
|
|
1278
1280
|
replacement strategy (python3 could use surrogateescape)
|
|
1279
1281
|
:kwarg chdir: cd into this directory before executing the command.
|
|
1280
|
-
|
|
1282
|
+
"""
|
|
1281
1283
|
|
|
1282
1284
|
display.debug("_low_level_execute_command(): starting")
|
|
1283
1285
|
# if not cmd:
|
|
@@ -1373,7 +1375,7 @@ class ActionBase(ABC):
|
|
|
1373
1375
|
elif peek_result.get('size') and C.MAX_FILE_SIZE_FOR_DIFF > 0 and peek_result['size'] > C.MAX_FILE_SIZE_FOR_DIFF:
|
|
1374
1376
|
diff['dst_larger'] = C.MAX_FILE_SIZE_FOR_DIFF
|
|
1375
1377
|
else:
|
|
1376
|
-
display.debug(u"Slurping the file %s" %
|
|
1378
|
+
display.debug(u"Slurping the file %s" % destination)
|
|
1377
1379
|
dest_result = self._execute_module(
|
|
1378
1380
|
module_name='ansible.legacy.slurp', module_args=dict(path=destination),
|
|
1379
1381
|
task_vars=task_vars, persist_files=True)
|
|
@@ -1420,11 +1422,11 @@ class ActionBase(ABC):
|
|
|
1420
1422
|
return diff
|
|
1421
1423
|
|
|
1422
1424
|
def _find_needle(self, dirname, needle):
|
|
1423
|
-
|
|
1425
|
+
"""
|
|
1424
1426
|
find a needle in haystack of paths, optionally using 'dirname' as a subdir.
|
|
1425
1427
|
This will build the ordered list of paths to search and pass them to dwim
|
|
1426
1428
|
to get back the first existing file found.
|
|
1427
|
-
|
|
1429
|
+
"""
|
|
1428
1430
|
|
|
1429
1431
|
# dwim already deals with playbook basedirs
|
|
1430
1432
|
path_stack = self._task.get_search_path()
|