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
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
from __future__ import annotations as _annotations
|
|
2
|
+
|
|
3
|
+
import collections.abc as _c
|
|
4
|
+
import textwrap as _textwrap
|
|
5
|
+
|
|
6
|
+
from ansible.module_utils._internal import _event_utils, _messages
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def format_event(event: _messages.Event, include_traceback: bool) -> str:
|
|
10
|
+
"""Format an event into a verbose message and traceback."""
|
|
11
|
+
msg = format_event_verbose_message(event)
|
|
12
|
+
|
|
13
|
+
if include_traceback:
|
|
14
|
+
msg += '\n' + format_event_traceback(event)
|
|
15
|
+
|
|
16
|
+
msg = msg.strip()
|
|
17
|
+
|
|
18
|
+
if '\n' in msg:
|
|
19
|
+
msg += '\n\n'
|
|
20
|
+
else:
|
|
21
|
+
msg += '\n'
|
|
22
|
+
|
|
23
|
+
return msg
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def format_event_traceback(event: _messages.Event) -> str:
|
|
27
|
+
"""Format an event into a traceback."""
|
|
28
|
+
segments: list[str] = []
|
|
29
|
+
|
|
30
|
+
while event:
|
|
31
|
+
segment = event.formatted_traceback or '(traceback missing)\n'
|
|
32
|
+
|
|
33
|
+
if event.events:
|
|
34
|
+
child_tracebacks = [format_event_traceback(child) for child in event.events]
|
|
35
|
+
segment += _format_event_children("Sub-Traceback", child_tracebacks)
|
|
36
|
+
|
|
37
|
+
segments.append(segment)
|
|
38
|
+
|
|
39
|
+
if event.chain:
|
|
40
|
+
segments.append(f'\n{event.chain.traceback_reason}\n\n')
|
|
41
|
+
|
|
42
|
+
event = event.chain.event
|
|
43
|
+
else:
|
|
44
|
+
event = None
|
|
45
|
+
|
|
46
|
+
return ''.join(reversed(segments))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def format_event_verbose_message(event: _messages.Event) -> str:
|
|
50
|
+
"""
|
|
51
|
+
Format an event into a verbose message.
|
|
52
|
+
Help text, contextual information and sub-events will be included.
|
|
53
|
+
"""
|
|
54
|
+
segments: list[str] = []
|
|
55
|
+
original_event = event
|
|
56
|
+
|
|
57
|
+
while event:
|
|
58
|
+
messages = [event.msg]
|
|
59
|
+
chain: _messages.EventChain = event.chain
|
|
60
|
+
|
|
61
|
+
while chain and chain.follow:
|
|
62
|
+
if chain.event.events:
|
|
63
|
+
break # do not collapse a chained event with sub-events, since they would be lost
|
|
64
|
+
|
|
65
|
+
if chain.event.formatted_source_context or chain.event.help_text:
|
|
66
|
+
if chain.event.formatted_source_context != event.formatted_source_context or chain.event.help_text != event.help_text:
|
|
67
|
+
break # do not collapse a chained event with different details, since they would be lost
|
|
68
|
+
|
|
69
|
+
if chain.event.chain and chain.msg_reason != chain.event.chain.msg_reason:
|
|
70
|
+
break # do not collapse a chained event which has a chain with a different msg_reason
|
|
71
|
+
|
|
72
|
+
messages.append(chain.event.msg)
|
|
73
|
+
|
|
74
|
+
chain = chain.event.chain
|
|
75
|
+
|
|
76
|
+
msg = _event_utils.deduplicate_message_parts(messages)
|
|
77
|
+
segment = '\n'.join(_get_message_lines(msg, event.help_text, event.formatted_source_context)) + '\n'
|
|
78
|
+
|
|
79
|
+
if event.events:
|
|
80
|
+
child_msgs = [format_event_verbose_message(child) for child in event.events]
|
|
81
|
+
segment += _format_event_children("Sub-Event", child_msgs)
|
|
82
|
+
|
|
83
|
+
segments.append(segment)
|
|
84
|
+
|
|
85
|
+
if chain and chain.follow:
|
|
86
|
+
segments.append(f'\n{chain.msg_reason}\n\n')
|
|
87
|
+
|
|
88
|
+
event = chain.event
|
|
89
|
+
else:
|
|
90
|
+
event = None
|
|
91
|
+
|
|
92
|
+
if len(segments) > 1:
|
|
93
|
+
segments.insert(0, _event_utils.format_event_brief_message(original_event) + '\n\n')
|
|
94
|
+
|
|
95
|
+
return ''.join(segments)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _format_event_children(label: str, children: _c.Iterable[str]) -> str:
|
|
99
|
+
"""Format the given list of child messages into a single string."""
|
|
100
|
+
items = list(children)
|
|
101
|
+
count = len(items)
|
|
102
|
+
lines = ['\n']
|
|
103
|
+
|
|
104
|
+
for idx, item in enumerate(items):
|
|
105
|
+
lines.append(f'+--[ {label} {idx + 1} of {count} ]---\n')
|
|
106
|
+
lines.append(_textwrap.indent(f"\n{item}\n", "| ", lambda value: True))
|
|
107
|
+
|
|
108
|
+
lines.append(f'+--[ End {label} ]---\n')
|
|
109
|
+
|
|
110
|
+
return ''.join(lines)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _get_message_lines(message: str, help_text: str | None, formatted_source_context: str | None) -> list[str]:
|
|
114
|
+
"""Return a list of message lines constructed from the given message, help text and formatted source context."""
|
|
115
|
+
if help_text and not formatted_source_context and '\n' not in message and '\n' not in help_text:
|
|
116
|
+
return [f'{message} {help_text}'] # prefer a single-line message with help text when there is no source context
|
|
117
|
+
|
|
118
|
+
message_lines = [message]
|
|
119
|
+
|
|
120
|
+
if formatted_source_context:
|
|
121
|
+
message_lines.append(formatted_source_context)
|
|
122
|
+
|
|
123
|
+
if help_text:
|
|
124
|
+
message_lines.append('')
|
|
125
|
+
message_lines.append(help_text)
|
|
126
|
+
|
|
127
|
+
return message_lines
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"""Internal utilities for serialization and deserialization."""
|
|
2
|
+
|
|
3
|
+
# DTFIX-FUTURE: most of this isn't JSON specific, find a better home
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import enum
|
|
8
|
+
import json
|
|
9
|
+
import typing as t
|
|
10
|
+
|
|
11
|
+
from ansible.errors import AnsibleVariableTypeError
|
|
12
|
+
|
|
13
|
+
from ansible.module_utils._internal._datatag import (
|
|
14
|
+
_ANSIBLE_ALLOWED_MAPPING_VAR_TYPES,
|
|
15
|
+
_ANSIBLE_ALLOWED_NON_SCALAR_COLLECTION_VAR_TYPES,
|
|
16
|
+
_ANSIBLE_ALLOWED_VAR_TYPES,
|
|
17
|
+
_AnsibleTaggedStr,
|
|
18
|
+
AnsibleTagHelper,
|
|
19
|
+
)
|
|
20
|
+
from ansible.module_utils._internal._json._profiles import _tagless
|
|
21
|
+
from ansible.parsing.vault import EncryptedString
|
|
22
|
+
from ansible._internal._datatag._tags import Origin, TrustedAsTemplate
|
|
23
|
+
from ansible._internal._templating import _transform
|
|
24
|
+
from ansible.module_utils import _internal
|
|
25
|
+
from ansible.module_utils._internal import _datatag
|
|
26
|
+
|
|
27
|
+
_T = t.TypeVar('_T')
|
|
28
|
+
_sentinel = object()
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class HasCurrent(t.Protocol):
|
|
32
|
+
"""Utility protocol for mixin type safety."""
|
|
33
|
+
|
|
34
|
+
_current: t.Any
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class StateTrackingMixIn(HasCurrent):
|
|
38
|
+
"""Mixin for use with `AnsibleVariableVisitor` to track current visitation context."""
|
|
39
|
+
|
|
40
|
+
def __init__(self, *args, **kwargs) -> None:
|
|
41
|
+
super().__init__(*args, **kwargs)
|
|
42
|
+
|
|
43
|
+
self._stack: list[t.Any] = []
|
|
44
|
+
|
|
45
|
+
def __enter__(self) -> None:
|
|
46
|
+
self._stack.append(self._current)
|
|
47
|
+
|
|
48
|
+
def __exit__(self, *_args, **_kwargs) -> None:
|
|
49
|
+
self._stack.pop()
|
|
50
|
+
|
|
51
|
+
def _get_stack(self) -> list[t.Any]:
|
|
52
|
+
if not self._stack:
|
|
53
|
+
return []
|
|
54
|
+
|
|
55
|
+
return self._stack[1:] + [self._current]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class EncryptedStringBehavior(enum.Enum):
|
|
59
|
+
"""How `AnsibleVariableVisitor` will handle instances of `EncryptedString`."""
|
|
60
|
+
|
|
61
|
+
PRESERVE = enum.auto()
|
|
62
|
+
"""Preserves the unmodified `EncryptedString` instance."""
|
|
63
|
+
DECRYPT = enum.auto()
|
|
64
|
+
"""Replaces the value with its decrypted plaintext."""
|
|
65
|
+
REDACT = enum.auto()
|
|
66
|
+
"""Replaces the value with a placeholder string."""
|
|
67
|
+
FAIL = enum.auto()
|
|
68
|
+
"""Raises an `AnsibleVariableTypeError` error."""
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class AnsibleVariableVisitor:
|
|
72
|
+
"""Utility visitor base class to recursively apply various behaviors and checks to variable object graphs."""
|
|
73
|
+
|
|
74
|
+
def __init__(
|
|
75
|
+
self,
|
|
76
|
+
*,
|
|
77
|
+
trusted_as_template: bool = False,
|
|
78
|
+
origin: Origin | None = None,
|
|
79
|
+
convert_mapping_to_dict: bool = False,
|
|
80
|
+
convert_sequence_to_list: bool = False,
|
|
81
|
+
convert_custom_scalars: bool = False,
|
|
82
|
+
convert_to_native_values: bool = False,
|
|
83
|
+
apply_transforms: bool = False,
|
|
84
|
+
visit_keys: bool = False,
|
|
85
|
+
encrypted_string_behavior: EncryptedStringBehavior = EncryptedStringBehavior.DECRYPT,
|
|
86
|
+
):
|
|
87
|
+
super().__init__() # supports StateTrackingMixIn
|
|
88
|
+
|
|
89
|
+
self.trusted_as_template = trusted_as_template
|
|
90
|
+
self.origin = origin
|
|
91
|
+
self.convert_mapping_to_dict = convert_mapping_to_dict
|
|
92
|
+
self.convert_sequence_to_list = convert_sequence_to_list
|
|
93
|
+
self.convert_custom_scalars = convert_custom_scalars
|
|
94
|
+
self.convert_to_native_values = convert_to_native_values
|
|
95
|
+
self.apply_transforms = apply_transforms
|
|
96
|
+
self.visit_keys = visit_keys
|
|
97
|
+
self.encrypted_string_behavior = encrypted_string_behavior
|
|
98
|
+
|
|
99
|
+
if apply_transforms:
|
|
100
|
+
from ansible._internal._templating import _engine
|
|
101
|
+
|
|
102
|
+
self._template_engine = _engine.TemplateEngine()
|
|
103
|
+
else:
|
|
104
|
+
self._template_engine = None
|
|
105
|
+
|
|
106
|
+
self._current: t.Any = None # supports StateTrackingMixIn
|
|
107
|
+
|
|
108
|
+
def __enter__(self) -> t.Any:
|
|
109
|
+
"""No-op context manager dispatcher (delegates to mixin behavior if present)."""
|
|
110
|
+
if func := getattr(super(), '__enter__', None):
|
|
111
|
+
func()
|
|
112
|
+
|
|
113
|
+
def __exit__(self, *args, **kwargs) -> t.Any:
|
|
114
|
+
"""No-op context manager dispatcher (delegates to mixin behavior if present)."""
|
|
115
|
+
if func := getattr(super(), '__exit__', None):
|
|
116
|
+
func(*args, **kwargs)
|
|
117
|
+
|
|
118
|
+
def visit(self, value: _T) -> _T:
|
|
119
|
+
"""
|
|
120
|
+
Enforces Ansible's variable type system restrictions before a var is accepted in inventory. Also, conditionally implements template trust
|
|
121
|
+
compatibility, depending on the plugin's declared understanding (or lack thereof). This always recursively copies inputs to fully isolate
|
|
122
|
+
inventory data from what the plugin provided, and prevent any later mutation.
|
|
123
|
+
"""
|
|
124
|
+
return self._visit(None, value)
|
|
125
|
+
|
|
126
|
+
def _early_visit(self, value, value_type) -> t.Any:
|
|
127
|
+
"""Overridable hook point to allow custom string handling in derived visitors."""
|
|
128
|
+
if value_type in (str, _AnsibleTaggedStr):
|
|
129
|
+
# apply compatibility behavior
|
|
130
|
+
if self.trusted_as_template:
|
|
131
|
+
result = TrustedAsTemplate().tag(value)
|
|
132
|
+
else:
|
|
133
|
+
result = value
|
|
134
|
+
else:
|
|
135
|
+
result = _sentinel
|
|
136
|
+
|
|
137
|
+
return result
|
|
138
|
+
|
|
139
|
+
def _visit_key(self, key: t.Any) -> t.Any:
|
|
140
|
+
"""Internal implementation to recursively visit a key if visit_keys is enabled."""
|
|
141
|
+
if not self.visit_keys:
|
|
142
|
+
return key
|
|
143
|
+
|
|
144
|
+
return self._visit(None, key) # key=None prevents state tracking from seeing the key as value
|
|
145
|
+
|
|
146
|
+
def _visit(self, key: t.Any, value: _T) -> _T:
|
|
147
|
+
"""Internal implementation to recursively visit a data structure's contents."""
|
|
148
|
+
self._current = key # supports StateTrackingMixIn
|
|
149
|
+
|
|
150
|
+
value_type: type = type(value)
|
|
151
|
+
|
|
152
|
+
# handle EncryptedString conversion before more generic transformation and native conversions
|
|
153
|
+
if value_type is EncryptedString: # pylint: disable=unidiomatic-typecheck
|
|
154
|
+
match self.encrypted_string_behavior:
|
|
155
|
+
case EncryptedStringBehavior.DECRYPT:
|
|
156
|
+
value = str(value) # type: ignore[assignment]
|
|
157
|
+
value_type = str
|
|
158
|
+
case EncryptedStringBehavior.REDACT:
|
|
159
|
+
value = "<redacted>" # type: ignore[assignment]
|
|
160
|
+
value_type = str
|
|
161
|
+
case EncryptedStringBehavior.FAIL:
|
|
162
|
+
raise AnsibleVariableTypeError.from_value(obj=value)
|
|
163
|
+
elif self.apply_transforms and value_type in _transform._type_transform_mapping:
|
|
164
|
+
value = self._template_engine.transform(value)
|
|
165
|
+
value_type = type(value)
|
|
166
|
+
|
|
167
|
+
if self.convert_to_native_values and isinstance(value, _datatag.AnsibleTaggedObject):
|
|
168
|
+
value = value._native_copy()
|
|
169
|
+
value_type = type(value)
|
|
170
|
+
|
|
171
|
+
result: _T
|
|
172
|
+
|
|
173
|
+
# DTFIX-FUTURE: Visitor generally ignores dict/mapping keys by default except for debugging and schema-aware checking.
|
|
174
|
+
# It could be checking keys destined for variable storage to apply more strict rules about key shape and type.
|
|
175
|
+
|
|
176
|
+
if (result := self._early_visit(value, value_type)) is not _sentinel:
|
|
177
|
+
pass
|
|
178
|
+
# DTFIX7: de-duplicate and optimize; extract inline generator expressions and fallback function or mapping for native type calculation?
|
|
179
|
+
elif value_type in _ANSIBLE_ALLOWED_MAPPING_VAR_TYPES: # check mappings first, because they're also collections
|
|
180
|
+
with self: # supports StateTrackingMixIn
|
|
181
|
+
result = AnsibleTagHelper.tag_copy(value, ((self._visit_key(k), self._visit(k, v)) for k, v in value.items()), value_type=value_type)
|
|
182
|
+
elif value_type in _ANSIBLE_ALLOWED_NON_SCALAR_COLLECTION_VAR_TYPES:
|
|
183
|
+
with self: # supports StateTrackingMixIn
|
|
184
|
+
result = AnsibleTagHelper.tag_copy(value, (self._visit(k, v) for k, v in enumerate(t.cast(t.Iterable, value))), value_type=value_type)
|
|
185
|
+
elif self.convert_mapping_to_dict and _internal.is_intermediate_mapping(value):
|
|
186
|
+
with self: # supports StateTrackingMixIn
|
|
187
|
+
result = {self._visit_key(k): self._visit(k, v) for k, v in value.items()} # type: ignore[assignment]
|
|
188
|
+
elif self.convert_sequence_to_list and _internal.is_intermediate_iterable(value):
|
|
189
|
+
with self: # supports StateTrackingMixIn
|
|
190
|
+
result = [self._visit(k, v) for k, v in enumerate(t.cast(t.Iterable, value))] # type: ignore[assignment]
|
|
191
|
+
elif self.convert_custom_scalars and isinstance(value, str):
|
|
192
|
+
result = str(value) # type: ignore[assignment]
|
|
193
|
+
elif self.convert_custom_scalars and isinstance(value, float):
|
|
194
|
+
result = float(value) # type: ignore[assignment]
|
|
195
|
+
elif self.convert_custom_scalars and isinstance(value, int) and not isinstance(value, bool):
|
|
196
|
+
result = int(value) # type: ignore[assignment]
|
|
197
|
+
elif value_type in _ANSIBLE_ALLOWED_VAR_TYPES:
|
|
198
|
+
# supported scalar type that requires no special handling, just return as-is
|
|
199
|
+
result = value
|
|
200
|
+
elif self.encrypted_string_behavior is EncryptedStringBehavior.PRESERVE and isinstance(value, EncryptedString):
|
|
201
|
+
result = value # type: ignore[assignment]
|
|
202
|
+
else:
|
|
203
|
+
raise AnsibleVariableTypeError.from_value(obj=value)
|
|
204
|
+
|
|
205
|
+
if self.origin and not Origin.is_tagged_on(result):
|
|
206
|
+
# apply shared instance default origin tag
|
|
207
|
+
result = self.origin.tag(result)
|
|
208
|
+
|
|
209
|
+
return result
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def json_dumps_formatted(value: object) -> str:
|
|
213
|
+
"""Return a JSON dump of `value` with formatting and keys sorted."""
|
|
214
|
+
return json.dumps(value, cls=_tagless.Encoder, sort_keys=True, indent=4)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from __future__ import annotations as _annotations
|
|
2
|
+
|
|
3
|
+
import typing as _t
|
|
4
|
+
|
|
5
|
+
from ansible.module_utils._internal._json import _profiles
|
|
6
|
+
from ansible._internal._json._profiles import _legacy
|
|
7
|
+
from ansible.parsing import vault as _vault
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class LegacyControllerJSONEncoder(_legacy.Encoder):
|
|
11
|
+
"""Compatibility wrapper over `legacy` profile JSON encoder to support trust stripping and vault value plaintext conversion."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, preprocess_unsafe: bool = False, vault_to_text: bool = False, _decode_bytes: bool = False, **kwargs) -> None:
|
|
14
|
+
self._preprocess_unsafe = preprocess_unsafe
|
|
15
|
+
self._vault_to_text = vault_to_text
|
|
16
|
+
self._decode_bytes = _decode_bytes
|
|
17
|
+
|
|
18
|
+
super().__init__(**kwargs)
|
|
19
|
+
|
|
20
|
+
def default(self, o: _t.Any) -> _t.Any:
|
|
21
|
+
"""Hooked default that can conditionally bypass base encoder behavior based on this instance's config."""
|
|
22
|
+
if type(o) is _profiles._WrappedValue: # pylint: disable=unidiomatic-typecheck
|
|
23
|
+
o = o.wrapped
|
|
24
|
+
|
|
25
|
+
if not self._preprocess_unsafe and type(o) is _legacy._Untrusted: # pylint: disable=unidiomatic-typecheck
|
|
26
|
+
return o.value # if not emitting unsafe markers, bypass custom unsafe serialization and just return the raw value
|
|
27
|
+
|
|
28
|
+
if self._vault_to_text and type(o) is _vault.EncryptedString: # pylint: disable=unidiomatic-typecheck
|
|
29
|
+
return str(o) # decrypt and return the plaintext (or fail trying)
|
|
30
|
+
|
|
31
|
+
if self._decode_bytes and isinstance(o, bytes):
|
|
32
|
+
return o.decode(errors='surrogateescape') # backward compatibility with `ansible.module_utils.basic.jsonify`
|
|
33
|
+
|
|
34
|
+
return super().default(o)
|
|
File without changes
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import datetime as _datetime
|
|
4
|
+
|
|
5
|
+
from ansible.module_utils._internal import _datatag
|
|
6
|
+
from ansible.module_utils._internal._json import _profiles
|
|
7
|
+
from ansible.parsing import vault as _vault
|
|
8
|
+
from ansible._internal._datatag import _tags
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class _Profile(_profiles._JSONSerializationProfile):
|
|
12
|
+
"""Profile for external cache persistence of inventory/fact data that preserves most tags."""
|
|
13
|
+
|
|
14
|
+
serialize_map = {}
|
|
15
|
+
schema_id = 1
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def post_init(cls, **kwargs):
|
|
19
|
+
cls.allowed_ansible_serializable_types = (
|
|
20
|
+
_profiles._common_module_types
|
|
21
|
+
| _profiles._common_module_response_types
|
|
22
|
+
| {
|
|
23
|
+
_datatag._AnsibleTaggedDate,
|
|
24
|
+
_datatag._AnsibleTaggedTime,
|
|
25
|
+
_datatag._AnsibleTaggedDateTime,
|
|
26
|
+
_datatag._AnsibleTaggedStr,
|
|
27
|
+
_datatag._AnsibleTaggedInt,
|
|
28
|
+
_datatag._AnsibleTaggedFloat,
|
|
29
|
+
_datatag._AnsibleTaggedList,
|
|
30
|
+
_datatag._AnsibleTaggedSet,
|
|
31
|
+
_datatag._AnsibleTaggedTuple,
|
|
32
|
+
_datatag._AnsibleTaggedDict,
|
|
33
|
+
_tags.SourceWasEncrypted,
|
|
34
|
+
_tags.Origin,
|
|
35
|
+
_tags.TrustedAsTemplate,
|
|
36
|
+
_vault.EncryptedString,
|
|
37
|
+
_vault.VaultedValue,
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
cls.serialize_map = {
|
|
42
|
+
set: cls.serialize_as_list,
|
|
43
|
+
tuple: cls.serialize_as_list,
|
|
44
|
+
_datetime.date: _datatag.AnsibleSerializableDate,
|
|
45
|
+
_datetime.time: _datatag.AnsibleSerializableTime,
|
|
46
|
+
_datetime.datetime: _datatag.AnsibleSerializableDateTime,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
cls.handle_key = cls._handle_key_str_fallback # legacy stdlib-compatible key behavior
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class Encoder(_profiles.AnsibleProfileJSONEncoder):
|
|
53
|
+
_profile = _Profile
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class Decoder(_profiles.AnsibleProfileJSONDecoder):
|
|
57
|
+
_profile = _Profile
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Backwards compatibility profile for serialization for persisted ansible-inventory output.
|
|
3
|
+
Behavior is equivalent to pre 2.18 `AnsibleJSONEncoder` with vault_to_text=True.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from ... import _json
|
|
9
|
+
from . import _legacy
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class _InventoryVariableVisitor(_legacy._LegacyVariableVisitor, _json.StateTrackingMixIn):
|
|
13
|
+
"""State-tracking visitor implementation that only applies trust to `_meta.hostvars` and `vars` inventory values."""
|
|
14
|
+
|
|
15
|
+
# DTFIX5: does the variable visitor need to support conversion of sequence/mapping for inventory?
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def _allow_trust(self) -> bool:
|
|
19
|
+
stack = self._get_stack()
|
|
20
|
+
|
|
21
|
+
if len(stack) >= 4 and stack[:2] == ['_meta', 'hostvars']:
|
|
22
|
+
return True
|
|
23
|
+
|
|
24
|
+
if len(stack) >= 3 and stack[1] == 'vars':
|
|
25
|
+
return True
|
|
26
|
+
|
|
27
|
+
return False
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class _Profile(_legacy._Profile):
|
|
31
|
+
visitor_type = _InventoryVariableVisitor
|
|
32
|
+
encode_strings_as_utf8 = True
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class Encoder(_legacy.Encoder):
|
|
36
|
+
_profile = _Profile
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class Decoder(_legacy.Decoder):
|
|
40
|
+
_profile = _Profile
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Backwards compatibility profile for serialization other than inventory (which should use inventory_legacy for backward-compatible trust behavior).
|
|
3
|
+
Behavior is equivalent to pre 2.19 `AnsibleJSONEncoder` with vault_to_text=True.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations as _annotations
|
|
7
|
+
|
|
8
|
+
import datetime as _datetime
|
|
9
|
+
import typing as _t
|
|
10
|
+
|
|
11
|
+
from ansible._internal import _json
|
|
12
|
+
from ansible._internal._datatag import _tags
|
|
13
|
+
from ansible.module_utils._internal import _datatag
|
|
14
|
+
from ansible.module_utils._internal._json import _profiles
|
|
15
|
+
from ansible.parsing import vault as _vault
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class _Untrusted:
|
|
19
|
+
"""
|
|
20
|
+
Temporarily wraps strings which are not trusted for templating.
|
|
21
|
+
Used before serialization of strings not tagged TrustedAsTemplate when trust inversion is enabled and trust is allowed in the string's context.
|
|
22
|
+
Used during deserialization of `__ansible_unsafe` strings to indicate they should not be tagged TrustedAsTemplate.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
__slots__ = ('value',)
|
|
26
|
+
|
|
27
|
+
def __init__(self, value: str) -> None:
|
|
28
|
+
self.value = value
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class _LegacyVariableVisitor(_json.AnsibleVariableVisitor):
|
|
32
|
+
"""Variable visitor that supports optional trust inversion for legacy serialization."""
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
*,
|
|
37
|
+
trusted_as_template: bool = False,
|
|
38
|
+
invert_trust: bool = False,
|
|
39
|
+
origin: _tags.Origin | None = None,
|
|
40
|
+
convert_mapping_to_dict: bool = False,
|
|
41
|
+
convert_sequence_to_list: bool = False,
|
|
42
|
+
convert_custom_scalars: bool = False,
|
|
43
|
+
):
|
|
44
|
+
super().__init__(
|
|
45
|
+
trusted_as_template=trusted_as_template,
|
|
46
|
+
origin=origin,
|
|
47
|
+
convert_mapping_to_dict=convert_mapping_to_dict,
|
|
48
|
+
convert_sequence_to_list=convert_sequence_to_list,
|
|
49
|
+
convert_custom_scalars=convert_custom_scalars,
|
|
50
|
+
encrypted_string_behavior=_json.EncryptedStringBehavior.PRESERVE,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
self.invert_trust = invert_trust
|
|
54
|
+
|
|
55
|
+
if trusted_as_template and invert_trust:
|
|
56
|
+
raise ValueError('trusted_as_template is mutually exclusive with invert_trust')
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def _allow_trust(self) -> bool:
|
|
60
|
+
"""
|
|
61
|
+
This profile supports trust application in all contexts.
|
|
62
|
+
Derived implementations can override this behavior for application-dependent/schema-aware trust.
|
|
63
|
+
"""
|
|
64
|
+
return True
|
|
65
|
+
|
|
66
|
+
def _early_visit(self, value, value_type) -> _t.Any:
|
|
67
|
+
"""Similar to base implementation, but supports an intermediate wrapper for trust inversion."""
|
|
68
|
+
if value_type in (str, _datatag._AnsibleTaggedStr):
|
|
69
|
+
# apply compatibility behavior
|
|
70
|
+
if self.trusted_as_template and self._allow_trust:
|
|
71
|
+
result = _tags.TrustedAsTemplate().tag(value)
|
|
72
|
+
elif self.invert_trust and not _tags.TrustedAsTemplate.is_tagged_on(value) and self._allow_trust:
|
|
73
|
+
result = _Untrusted(value)
|
|
74
|
+
else:
|
|
75
|
+
result = value
|
|
76
|
+
elif value_type is _Untrusted:
|
|
77
|
+
result = value.value
|
|
78
|
+
else:
|
|
79
|
+
result = _json._sentinel
|
|
80
|
+
|
|
81
|
+
return result
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class _Profile(_profiles._JSONSerializationProfile["Encoder", "Decoder"]):
|
|
85
|
+
visitor_type = _LegacyVariableVisitor
|
|
86
|
+
|
|
87
|
+
@classmethod
|
|
88
|
+
def serialize_untrusted(cls, value: _Untrusted) -> dict[str, str] | str:
|
|
89
|
+
return dict(
|
|
90
|
+
__ansible_unsafe=_datatag.AnsibleTagHelper.untag(value.value),
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
@classmethod
|
|
94
|
+
def serialize_tagged_str(cls, value: _datatag.AnsibleTaggedObject) -> _t.Any:
|
|
95
|
+
if ciphertext := _vault.VaultHelper.get_ciphertext(value, with_tags=False):
|
|
96
|
+
return dict(
|
|
97
|
+
__ansible_vault=ciphertext,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
return _datatag.AnsibleTagHelper.untag(value)
|
|
101
|
+
|
|
102
|
+
@classmethod
|
|
103
|
+
def deserialize_unsafe(cls, value: dict[str, _t.Any]) -> _Untrusted:
|
|
104
|
+
ansible_unsafe = value['__ansible_unsafe']
|
|
105
|
+
|
|
106
|
+
if type(ansible_unsafe) is not str: # pylint: disable=unidiomatic-typecheck
|
|
107
|
+
raise TypeError(f"__ansible_unsafe is {type(ansible_unsafe)} not {str}")
|
|
108
|
+
|
|
109
|
+
return _Untrusted(ansible_unsafe)
|
|
110
|
+
|
|
111
|
+
@classmethod
|
|
112
|
+
def deserialize_vault(cls, value: dict[str, _t.Any]) -> _vault.EncryptedString:
|
|
113
|
+
ansible_vault = value['__ansible_vault']
|
|
114
|
+
|
|
115
|
+
if type(ansible_vault) is not str: # pylint: disable=unidiomatic-typecheck
|
|
116
|
+
raise TypeError(f"__ansible_vault is {type(ansible_vault)} not {str}")
|
|
117
|
+
|
|
118
|
+
encrypted_string = _vault.EncryptedString(ciphertext=ansible_vault)
|
|
119
|
+
|
|
120
|
+
return encrypted_string
|
|
121
|
+
|
|
122
|
+
@classmethod
|
|
123
|
+
def serialize_encrypted_string(cls, value: _vault.EncryptedString) -> dict[str, str]:
|
|
124
|
+
return dict(
|
|
125
|
+
__ansible_vault=_vault.VaultHelper.get_ciphertext(value, with_tags=False),
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
@classmethod
|
|
129
|
+
def post_init(cls) -> None:
|
|
130
|
+
cls.serialize_map = {
|
|
131
|
+
set: cls.serialize_as_list,
|
|
132
|
+
tuple: cls.serialize_as_list,
|
|
133
|
+
_datetime.date: cls.serialize_as_isoformat, # existing devel behavior
|
|
134
|
+
_datetime.time: cls.serialize_as_isoformat, # always failed pre-2.18, so okay to include for consistency
|
|
135
|
+
_datetime.datetime: cls.serialize_as_isoformat, # existing devel behavior
|
|
136
|
+
_datatag._AnsibleTaggedDate: cls.discard_tags,
|
|
137
|
+
_datatag._AnsibleTaggedTime: cls.discard_tags,
|
|
138
|
+
_datatag._AnsibleTaggedDateTime: cls.discard_tags,
|
|
139
|
+
_vault.EncryptedString: cls.serialize_encrypted_string,
|
|
140
|
+
_datatag._AnsibleTaggedStr: cls.serialize_tagged_str, # for VaultedValue tagged str
|
|
141
|
+
_datatag._AnsibleTaggedInt: cls.discard_tags,
|
|
142
|
+
_datatag._AnsibleTaggedFloat: cls.discard_tags,
|
|
143
|
+
_datatag._AnsibleTaggedList: cls.discard_tags,
|
|
144
|
+
_datatag._AnsibleTaggedSet: cls.discard_tags,
|
|
145
|
+
_datatag._AnsibleTaggedTuple: cls.discard_tags,
|
|
146
|
+
_datatag._AnsibleTaggedDict: cls.discard_tags,
|
|
147
|
+
_Untrusted: cls.serialize_untrusted, # equivalent to AnsibleJSONEncoder(preprocess_unsafe=True) in devel
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
cls.deserialize_map = {
|
|
151
|
+
'__ansible_unsafe': cls.deserialize_unsafe,
|
|
152
|
+
'__ansible_vault': cls.deserialize_vault,
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
cls.handle_key = cls._handle_key_str_fallback # type: ignore[method-assign] # legacy stdlib-compatible key behavior
|
|
156
|
+
|
|
157
|
+
@classmethod
|
|
158
|
+
def pre_serialize(cls, encoder: Encoder, o: _t.Any) -> _t.Any:
|
|
159
|
+
# DTFIX7: these conversion args probably aren't needed
|
|
160
|
+
avv = cls.visitor_type(invert_trust=True, convert_mapping_to_dict=True, convert_sequence_to_list=True, convert_custom_scalars=True)
|
|
161
|
+
|
|
162
|
+
return avv.visit(o)
|
|
163
|
+
|
|
164
|
+
@classmethod
|
|
165
|
+
def post_deserialize(cls, decoder: Decoder, o: _t.Any) -> _t.Any:
|
|
166
|
+
avv = cls.visitor_type(trusted_as_template=decoder._trusted_as_template, origin=decoder._origin)
|
|
167
|
+
|
|
168
|
+
return avv.visit(o)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class Encoder(_profiles.AnsibleProfileJSONEncoder):
|
|
172
|
+
_profile = _Profile
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class Decoder(_profiles.AnsibleProfileJSONDecoder):
|
|
176
|
+
_profile = _Profile
|
|
177
|
+
|
|
178
|
+
def __init__(self, **kwargs) -> None:
|
|
179
|
+
super().__init__(**kwargs)
|
|
180
|
+
|
|
181
|
+
# NB: these can only be sampled properly when loading strings, eg, `json.loads`; the global `json.load` function does not expose the file-like to us
|
|
182
|
+
self._origin: _tags.Origin | None = None
|
|
183
|
+
self._trusted_as_template: bool = False
|
|
184
|
+
|
|
185
|
+
def raw_decode(self, s: str, idx: int = 0) -> tuple[_t.Any, int]:
|
|
186
|
+
self._origin = _tags.Origin.get_tag(s)
|
|
187
|
+
self._trusted_as_template = _tags.TrustedAsTemplate.is_tagged_on(s)
|
|
188
|
+
|
|
189
|
+
return super().raw_decode(s, idx)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import contextlib
|
|
4
|
+
import fcntl
|
|
5
|
+
import typing as t
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@contextlib.contextmanager
|
|
9
|
+
def named_mutex(path: str) -> t.Iterator[None]:
|
|
10
|
+
"""
|
|
11
|
+
Lightweight context manager wrapper over `fcntl.flock` to provide IPC locking via a shared filename.
|
|
12
|
+
Entering the context manager blocks until the lock is acquired.
|
|
13
|
+
The lock file will be created automatically, but creation of the parent directory and deletion of the lockfile are the caller's responsibility.
|
|
14
|
+
"""
|
|
15
|
+
with open(path, 'a') as file:
|
|
16
|
+
fcntl.flock(file, fcntl.LOCK_EX)
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
yield
|
|
20
|
+
finally:
|
|
21
|
+
fcntl.flock(file, fcntl.LOCK_UN)
|
|
File without changes
|