ansible-core 2.18.5rc1__py3-none-any.whl → 2.19.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ansible/_internal/__init__.py +53 -0
- ansible/_internal/_ansiballz.py +265 -0
- ansible/_internal/_datatag/__init__.py +0 -0
- ansible/_internal/_datatag/_tags.py +130 -0
- ansible/_internal/_datatag/_utils.py +19 -0
- ansible/_internal/_datatag/_wrappers.py +33 -0
- ansible/_internal/_errors/__init__.py +0 -0
- ansible/_internal/_errors/_captured.py +128 -0
- ansible/_internal/_errors/_handler.py +91 -0
- ansible/_internal/_errors/_utils.py +310 -0
- ansible/_internal/_json/__init__.py +160 -0
- ansible/_internal/_json/_legacy_encoder.py +34 -0
- ansible/_internal/_json/_profiles/__init__.py +0 -0
- ansible/_internal/_json/_profiles/_cache_persistence.py +55 -0
- ansible/_internal/_json/_profiles/_inventory_legacy.py +40 -0
- ansible/_internal/_json/_profiles/_legacy.py +198 -0
- ansible/_internal/_locking.py +21 -0
- ansible/_internal/_plugins/__init__.py +0 -0
- ansible/_internal/_plugins/_cache.py +57 -0
- ansible/_internal/_task.py +78 -0
- ansible/_internal/_templating/__init__.py +10 -0
- ansible/_internal/_templating/_access.py +86 -0
- ansible/_internal/_templating/_chain_templar.py +63 -0
- ansible/_internal/_templating/_datatag.py +95 -0
- ansible/_internal/_templating/_engine.py +588 -0
- ansible/_internal/_templating/_errors.py +28 -0
- ansible/_internal/_templating/_jinja_bits.py +1066 -0
- ansible/_internal/_templating/_jinja_common.py +332 -0
- ansible/_internal/_templating/_jinja_patches.py +44 -0
- ansible/_internal/_templating/_jinja_plugins.py +351 -0
- ansible/_internal/_templating/_lazy_containers.py +633 -0
- ansible/_internal/_templating/_marker_behaviors.py +103 -0
- ansible/_internal/_templating/_transform.py +63 -0
- ansible/_internal/_templating/_utils.py +107 -0
- ansible/_internal/_wrapt.py +1052 -0
- ansible/_internal/_yaml/__init__.py +0 -0
- ansible/_internal/_yaml/_constructor.py +240 -0
- ansible/_internal/_yaml/_dumper.py +62 -0
- ansible/_internal/_yaml/_errors.py +166 -0
- ansible/_internal/_yaml/_loader.py +66 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/README.md +11 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/debug.py +36 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/apply_trust.py +19 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py +18 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/finalize.py +16 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/origin.py +18 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.py +24 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.yml +33 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/tag_names.py +16 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +17 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +49 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.py +21 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.yml +2 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.py +15 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.yml +19 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.py +18 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.yml +19 -0
- ansible/cli/__init__.py +153 -89
- ansible/cli/_ssh_askpass.py +47 -0
- ansible/cli/adhoc.py +14 -7
- ansible/cli/arguments/option_helpers.py +154 -7
- ansible/cli/config.py +43 -68
- ansible/cli/console.py +10 -8
- ansible/cli/doc.py +48 -46
- ansible/cli/galaxy.py +27 -20
- ansible/cli/inventory.py +28 -26
- ansible/cli/playbook.py +4 -12
- ansible/cli/pull.py +51 -11
- ansible/cli/scripts/ansible_connection_cli_stub.py +7 -7
- ansible/cli/vault.py +12 -11
- ansible/compat/__init__.py +2 -2
- ansible/config/base.yml +165 -108
- ansible/config/manager.py +52 -49
- ansible/constants.py +3 -4
- ansible/errors/__init__.py +277 -235
- ansible/executor/interpreter_discovery.py +28 -149
- ansible/executor/module_common.py +426 -493
- ansible/executor/play_iterator.py +22 -27
- ansible/executor/playbook_executor.py +11 -11
- ansible/executor/powershell/async_watchdog.ps1 +97 -102
- ansible/executor/powershell/async_wrapper.ps1 +202 -151
- ansible/executor/powershell/become_wrapper.ps1 +89 -144
- ansible/executor/powershell/bootstrap_wrapper.ps1 +24 -9
- ansible/executor/powershell/coverage_wrapper.ps1 +82 -135
- ansible/executor/powershell/exec_wrapper.ps1 +462 -196
- ansible/executor/powershell/module_manifest.py +417 -265
- ansible/executor/powershell/module_wrapper.ps1 +169 -186
- ansible/executor/powershell/psrp_fetch_file.ps1 +41 -0
- ansible/executor/powershell/psrp_put_file.ps1 +122 -0
- ansible/executor/powershell/winrm_fetch_file.ps1 +46 -0
- ansible/executor/powershell/winrm_put_file.ps1 +36 -0
- ansible/executor/process/worker.py +136 -76
- ansible/executor/stats.py +5 -5
- ansible/executor/task_executor.py +237 -236
- ansible/executor/task_queue_manager.py +62 -38
- ansible/executor/task_result.py +21 -12
- ansible/galaxy/__init__.py +2 -2
- ansible/galaxy/api.py +22 -18
- ansible/galaxy/collection/__init__.py +1 -1
- ansible/galaxy/collection/concrete_artifact_manager.py +8 -11
- ansible/galaxy/dependency_resolution/dataclasses.py +14 -4
- ansible/galaxy/dependency_resolution/providers.py +1 -1
- ansible/galaxy/dependency_resolution/reporters.py +81 -0
- ansible/galaxy/role.py +4 -8
- ansible/galaxy/token.py +28 -21
- ansible/inventory/data.py +47 -57
- ansible/inventory/group.py +44 -72
- ansible/inventory/helpers.py +9 -0
- ansible/inventory/host.py +32 -54
- ansible/inventory/manager.py +77 -34
- ansible/keyword_desc.yml +1 -1
- ansible/module_utils/_internal/__init__.py +55 -0
- ansible/module_utils/_internal/_ambient_context.py +58 -0
- ansible/module_utils/_internal/_ansiballz.py +133 -0
- ansible/module_utils/_internal/_concurrent/_daemon_threading.py +1 -0
- ansible/module_utils/_internal/_dataclass_annotation_patch.py +64 -0
- ansible/module_utils/_internal/_dataclass_validation.py +217 -0
- ansible/module_utils/_internal/_datatag/__init__.py +928 -0
- ansible/module_utils/_internal/_datatag/_tags.py +38 -0
- ansible/module_utils/_internal/_debugging.py +31 -0
- ansible/module_utils/_internal/_errors.py +30 -0
- ansible/module_utils/_internal/_json/__init__.py +63 -0
- ansible/module_utils/_internal/_json/_legacy_encoder.py +26 -0
- ansible/module_utils/_internal/_json/_profiles/__init__.py +410 -0
- ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py +73 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +31 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +35 -0
- ansible/module_utils/_internal/_json/_profiles/_module_modern_c2m.py +35 -0
- ansible/module_utils/_internal/_json/_profiles/_module_modern_m2c.py +33 -0
- ansible/module_utils/_internal/_json/_profiles/_tagless.py +50 -0
- ansible/module_utils/_internal/_patches/__init__.py +66 -0
- ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +55 -0
- ansible/module_utils/_internal/_patches/_socket_patch.py +34 -0
- ansible/module_utils/_internal/_patches/_sys_intern_patch.py +34 -0
- ansible/module_utils/_internal/_plugin_exec_context.py +49 -0
- ansible/module_utils/_internal/_testing.py +0 -0
- ansible/module_utils/_internal/_traceback.py +89 -0
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/api.py +1 -2
- ansible/module_utils/basic.py +154 -120
- ansible/module_utils/common/_utils.py +24 -28
- ansible/module_utils/common/collections.py +1 -2
- ansible/module_utils/common/dict_transformations.py +2 -2
- ansible/module_utils/common/file.py +2 -2
- ansible/module_utils/common/json.py +90 -84
- ansible/module_utils/common/locale.py +2 -2
- ansible/module_utils/common/messages.py +108 -0
- ansible/module_utils/common/parameters.py +27 -24
- ansible/module_utils/common/process.py +2 -2
- ansible/module_utils/common/respawn.py +41 -19
- ansible/module_utils/common/sentinel.py +66 -0
- ansible/module_utils/common/sys_info.py +8 -8
- ansible/module_utils/common/text/converters.py +16 -37
- ansible/module_utils/common/validation.py +35 -24
- ansible/module_utils/common/warnings.py +86 -25
- ansible/module_utils/common/yaml.py +29 -3
- ansible/module_utils/compat/datetime.py +33 -21
- ansible/module_utils/compat/paramiko.py +21 -10
- ansible/module_utils/compat/typing.py +6 -5
- ansible/module_utils/connection.py +2 -2
- ansible/module_utils/csharp/Ansible.Basic.cs +14 -11
- ansible/module_utils/csharp/Ansible.Become.cs +1 -0
- ansible/module_utils/csharp/Ansible._Async.cs +517 -0
- ansible/module_utils/datatag.py +46 -0
- ansible/module_utils/distro/__init__.py +2 -2
- ansible/module_utils/facts/ansible_collector.py +4 -5
- ansible/module_utils/facts/collector.py +13 -14
- ansible/module_utils/facts/compat.py +4 -4
- ansible/module_utils/facts/default_collectors.py +1 -1
- ansible/module_utils/facts/hardware/aix.py +34 -0
- ansible/module_utils/facts/hardware/base.py +1 -1
- ansible/module_utils/facts/hardware/darwin.py +1 -3
- ansible/module_utils/facts/hardware/freebsd.py +2 -2
- ansible/module_utils/facts/hardware/linux.py +4 -4
- ansible/module_utils/facts/namespace.py +1 -1
- ansible/module_utils/facts/network/base.py +1 -1
- ansible/module_utils/facts/network/fc_wwn.py +1 -2
- ansible/module_utils/facts/network/iscsi.py +1 -2
- ansible/module_utils/facts/network/nvme.py +1 -2
- ansible/module_utils/facts/other/facter.py +1 -2
- ansible/module_utils/facts/other/ohai.py +2 -3
- ansible/module_utils/facts/system/apparmor.py +1 -2
- ansible/module_utils/facts/system/caps.py +1 -1
- ansible/module_utils/facts/system/chroot.py +1 -2
- ansible/module_utils/facts/system/cmdline.py +1 -2
- ansible/module_utils/facts/system/date_time.py +5 -3
- ansible/module_utils/facts/system/distribution.py +9 -8
- ansible/module_utils/facts/system/dns.py +1 -1
- ansible/module_utils/facts/system/env.py +1 -2
- ansible/module_utils/facts/system/fips.py +7 -20
- ansible/module_utils/facts/system/loadavg.py +1 -2
- ansible/module_utils/facts/system/local.py +1 -2
- ansible/module_utils/facts/system/lsb.py +1 -2
- ansible/module_utils/facts/system/pkg_mgr.py +1 -2
- ansible/module_utils/facts/system/platform.py +1 -2
- ansible/module_utils/facts/system/python.py +1 -2
- ansible/module_utils/facts/system/selinux.py +1 -1
- ansible/module_utils/facts/system/service_mgr.py +1 -2
- ansible/module_utils/facts/system/ssh_pub_keys.py +1 -1
- ansible/module_utils/facts/system/systemd.py +1 -1
- ansible/module_utils/facts/system/user.py +1 -2
- ansible/module_utils/facts/utils.py +3 -3
- ansible/module_utils/facts/virtual/base.py +1 -1
- ansible/module_utils/facts/virtual/sunos.py +3 -15
- ansible/module_utils/facts/virtual/sysctl.py +3 -16
- ansible/module_utils/json_utils.py +2 -2
- ansible/module_utils/parsing/convert_bool.py +1 -1
- ansible/module_utils/service.py +18 -21
- ansible/module_utils/splitter.py +7 -7
- ansible/module_utils/testing.py +31 -0
- ansible/module_utils/urls.py +60 -31
- ansible/modules/add_host.py +4 -4
- ansible/modules/apt.py +60 -46
- ansible/modules/apt_key.py +19 -12
- ansible/modules/apt_repository.py +19 -16
- ansible/modules/assemble.py +6 -6
- ansible/modules/assert.py +4 -4
- ansible/modules/async_status.py +10 -12
- ansible/modules/async_wrapper.py +8 -3
- ansible/modules/blockinfile.py +6 -7
- ansible/modules/command.py +10 -17
- ansible/modules/copy.py +57 -144
- ansible/modules/cron.py +20 -15
- ansible/modules/deb822_repository.py +8 -9
- ansible/modules/debconf.py +5 -5
- ansible/modules/debug.py +4 -4
- ansible/modules/dnf.py +8 -8
- ansible/modules/dnf5.py +39 -13
- ansible/modules/dpkg_selections.py +4 -4
- ansible/modules/expect.py +8 -10
- ansible/modules/fail.py +4 -4
- ansible/modules/fetch.py +4 -4
- ansible/modules/file.py +174 -133
- ansible/modules/find.py +19 -17
- ansible/modules/gather_facts.py +3 -3
- ansible/modules/get_url.py +59 -53
- ansible/modules/getent.py +7 -9
- ansible/modules/git.py +28 -25
- ansible/modules/group.py +6 -6
- ansible/modules/group_by.py +4 -4
- ansible/modules/hostname.py +13 -29
- ansible/modules/import_playbook.py +6 -6
- ansible/modules/import_role.py +6 -6
- ansible/modules/import_tasks.py +6 -6
- ansible/modules/include_role.py +6 -6
- ansible/modules/include_tasks.py +6 -6
- ansible/modules/include_vars.py +6 -6
- ansible/modules/iptables.py +86 -73
- ansible/modules/known_hosts.py +10 -10
- ansible/modules/lineinfile.py +5 -5
- ansible/modules/meta.py +4 -4
- ansible/modules/mount_facts.py +2 -2
- ansible/modules/package.py +4 -4
- ansible/modules/package_facts.py +22 -10
- ansible/modules/pause.py +6 -6
- ansible/modules/ping.py +6 -6
- ansible/modules/pip.py +10 -11
- ansible/modules/raw.py +4 -4
- ansible/modules/reboot.py +6 -6
- ansible/modules/replace.py +9 -13
- ansible/modules/rpm_key.py +7 -8
- ansible/modules/script.py +4 -4
- ansible/modules/service.py +7 -8
- ansible/modules/service_facts.py +87 -10
- ansible/modules/set_fact.py +5 -5
- ansible/modules/set_stats.py +4 -4
- ansible/modules/setup.py +2 -2
- ansible/modules/shell.py +6 -6
- ansible/modules/slurp.py +6 -6
- ansible/modules/stat.py +9 -23
- ansible/modules/subversion.py +15 -15
- ansible/modules/systemd.py +6 -6
- ansible/modules/systemd_service.py +6 -6
- ansible/modules/sysvinit.py +6 -6
- ansible/modules/tempfile.py +5 -6
- ansible/modules/template.py +6 -6
- ansible/modules/unarchive.py +32 -11
- ansible/modules/uri.py +33 -26
- ansible/modules/user.py +53 -34
- ansible/modules/validate_argument_spec.py +10 -7
- ansible/modules/wait_for.py +32 -27
- ansible/modules/wait_for_connection.py +6 -6
- ansible/modules/yum_repository.py +6 -6
- ansible/parsing/ajson.py +14 -32
- ansible/parsing/dataloader.py +99 -54
- ansible/parsing/mod_args.py +28 -44
- ansible/parsing/plugin_docs.py +21 -86
- ansible/parsing/quoting.py +1 -1
- ansible/parsing/splitter.py +27 -12
- ansible/parsing/utils/addresses.py +24 -24
- ansible/parsing/utils/yaml.py +32 -61
- ansible/parsing/vault/__init__.py +319 -87
- ansible/parsing/yaml/__init__.py +0 -18
- ansible/parsing/yaml/dumper.py +6 -120
- ansible/parsing/yaml/loader.py +6 -39
- ansible/parsing/yaml/objects.py +36 -339
- ansible/playbook/__init__.py +1 -1
- ansible/playbook/attribute.py +8 -3
- ansible/playbook/base.py +182 -132
- ansible/playbook/block.py +26 -24
- ansible/playbook/collectionsearch.py +1 -15
- ansible/playbook/conditional.py +3 -77
- ansible/playbook/handler.py +8 -2
- ansible/playbook/helpers.py +41 -53
- ansible/playbook/included_file.py +6 -15
- ansible/playbook/loop_control.py +2 -2
- ansible/playbook/play.py +85 -44
- ansible/playbook/play_context.py +12 -17
- ansible/playbook/playbook_include.py +14 -15
- ansible/playbook/role/__init__.py +24 -26
- ansible/playbook/role/definition.py +15 -17
- ansible/playbook/role/include.py +2 -4
- ansible/playbook/role/metadata.py +10 -11
- ansible/playbook/role_include.py +3 -3
- ansible/playbook/taggable.py +13 -8
- ansible/playbook/task.py +188 -118
- ansible/playbook/task_include.py +5 -5
- ansible/plugins/__init__.py +68 -21
- ansible/plugins/action/__init__.py +209 -176
- ansible/plugins/action/add_host.py +1 -1
- ansible/plugins/action/assemble.py +1 -1
- ansible/plugins/action/assert.py +54 -66
- ansible/plugins/action/copy.py +7 -11
- ansible/plugins/action/debug.py +37 -31
- ansible/plugins/action/dnf.py +3 -4
- ansible/plugins/action/fail.py +1 -1
- ansible/plugins/action/fetch.py +4 -5
- ansible/plugins/action/gather_facts.py +7 -6
- ansible/plugins/action/group_by.py +1 -1
- ansible/plugins/action/include_vars.py +10 -11
- ansible/plugins/action/package.py +3 -6
- ansible/plugins/action/pause.py +2 -2
- ansible/plugins/action/script.py +15 -8
- ansible/plugins/action/service.py +6 -11
- ansible/plugins/action/set_fact.py +3 -12
- ansible/plugins/action/set_stats.py +3 -8
- ansible/plugins/action/template.py +35 -59
- ansible/plugins/action/unarchive.py +1 -1
- ansible/plugins/action/validate_argument_spec.py +5 -5
- ansible/plugins/action/wait_for_connection.py +1 -1
- ansible/plugins/become/__init__.py +31 -8
- ansible/plugins/become/runas.py +71 -0
- ansible/plugins/become/su.py +13 -8
- ansible/plugins/become/sudo.py +19 -0
- ansible/plugins/cache/__init__.py +35 -44
- ansible/plugins/cache/base.py +8 -0
- ansible/plugins/cache/jsonfile.py +10 -16
- ansible/plugins/cache/memory.py +6 -12
- ansible/plugins/callback/__init__.py +141 -123
- ansible/plugins/callback/default.py +30 -23
- ansible/plugins/callback/junit.py +28 -24
- ansible/plugins/callback/minimal.py +17 -14
- ansible/plugins/callback/oneline.py +13 -7
- ansible/plugins/callback/tree.py +10 -6
- ansible/plugins/connection/__init__.py +47 -34
- ansible/plugins/connection/local.py +150 -54
- ansible/plugins/connection/paramiko_ssh.py +21 -18
- ansible/plugins/connection/psrp.py +76 -165
- ansible/plugins/connection/ssh.py +301 -78
- ansible/plugins/connection/winrm.py +58 -140
- ansible/plugins/doc_fragments/action_common_attributes.py +14 -14
- ansible/plugins/doc_fragments/action_core.py +6 -6
- ansible/plugins/doc_fragments/backup.py +2 -2
- ansible/plugins/doc_fragments/checksum_common.py +27 -0
- ansible/plugins/doc_fragments/constructed.py +6 -2
- ansible/plugins/doc_fragments/decrypt.py +2 -2
- ansible/plugins/doc_fragments/default_callback.py +2 -2
- ansible/plugins/doc_fragments/files.py +2 -2
- ansible/plugins/doc_fragments/inventory_cache.py +2 -2
- ansible/plugins/doc_fragments/result_format_callback.py +2 -2
- ansible/plugins/doc_fragments/return_common.py +2 -2
- ansible/plugins/doc_fragments/template_common.py +4 -4
- ansible/plugins/doc_fragments/url.py +17 -1
- ansible/plugins/doc_fragments/url_windows.py +2 -2
- ansible/plugins/doc_fragments/validate.py +2 -2
- ansible/plugins/doc_fragments/vars_plugin_staging.py +2 -2
- ansible/plugins/filter/__init__.py +6 -2
- ansible/plugins/filter/b64decode.yml +22 -0
- ansible/plugins/filter/b64encode.yml +22 -0
- ansible/plugins/filter/bool.yml +11 -4
- ansible/plugins/filter/core.py +218 -108
- ansible/plugins/filter/encryption.py +32 -32
- ansible/plugins/filter/flatten.yml +3 -2
- ansible/plugins/filter/human_to_bytes.yml +1 -1
- ansible/plugins/filter/mathstuff.py +30 -37
- ansible/plugins/filter/password_hash.yml +8 -0
- ansible/plugins/filter/regex_search.yml +1 -4
- ansible/plugins/filter/split.yml +1 -1
- ansible/plugins/filter/to_nice_yaml.yml +0 -4
- ansible/plugins/filter/to_yaml.yml +0 -4
- ansible/plugins/filter/unvault.yml +1 -1
- ansible/plugins/filter/urls.py +1 -1
- ansible/plugins/filter/urlsplit.py +8 -9
- ansible/plugins/filter/vault.yml +14 -9
- ansible/plugins/filter/win_basename.yml +6 -1
- ansible/plugins/filter/win_dirname.yml +5 -0
- ansible/plugins/inventory/__init__.py +97 -77
- ansible/plugins/inventory/advanced_host_list.py +7 -5
- ansible/plugins/inventory/auto.py +11 -4
- ansible/plugins/inventory/constructed.py +21 -24
- ansible/plugins/inventory/generator.py +16 -11
- ansible/plugins/inventory/host_list.py +7 -5
- ansible/plugins/inventory/ini.py +78 -44
- ansible/plugins/inventory/script.py +189 -119
- ansible/plugins/inventory/toml.py +16 -126
- ansible/plugins/inventory/yaml.py +10 -8
- ansible/plugins/list.py +3 -3
- ansible/plugins/loader.py +197 -82
- ansible/plugins/lookup/__init__.py +21 -4
- ansible/plugins/lookup/config.py +21 -35
- ansible/plugins/lookup/csvfile.py +3 -2
- ansible/plugins/lookup/dict.py +1 -6
- ansible/plugins/lookup/env.py +12 -9
- ansible/plugins/lookup/file.py +5 -8
- ansible/plugins/lookup/first_found.py +86 -55
- ansible/plugins/lookup/indexed_items.py +1 -10
- ansible/plugins/lookup/ini.py +14 -13
- ansible/plugins/lookup/items.py +1 -1
- ansible/plugins/lookup/lines.py +8 -1
- ansible/plugins/lookup/list.py +1 -1
- ansible/plugins/lookup/nested.py +2 -18
- ansible/plugins/lookup/password.py +5 -5
- ansible/plugins/lookup/pipe.py +5 -7
- ansible/plugins/lookup/sequence.py +18 -8
- ansible/plugins/lookup/subelements.py +1 -4
- ansible/plugins/lookup/template.py +42 -36
- ansible/plugins/lookup/together.py +0 -12
- ansible/plugins/lookup/unvault.py +1 -5
- ansible/plugins/lookup/url.py +2 -8
- ansible/plugins/lookup/vars.py +16 -24
- ansible/plugins/shell/__init__.py +2 -2
- ansible/plugins/shell/cmd.py +2 -2
- ansible/plugins/shell/powershell.py +39 -22
- ansible/plugins/shell/sh.py +3 -2
- ansible/plugins/strategy/__init__.py +94 -113
- ansible/plugins/strategy/debug.py +2 -2
- ansible/plugins/strategy/free.py +13 -28
- ansible/plugins/strategy/host_pinned.py +2 -2
- ansible/plugins/strategy/linear.py +31 -33
- ansible/plugins/terminal/__init__.py +4 -4
- ansible/plugins/test/__init__.py +7 -2
- ansible/plugins/test/core.py +54 -20
- ansible/plugins/test/files.py +1 -1
- ansible/plugins/test/mathstuff.py +3 -3
- ansible/plugins/test/uri.py +3 -3
- ansible/plugins/vars/host_group_vars.py +7 -14
- ansible/release.py +2 -2
- ansible/template/__init__.py +368 -944
- ansible/utils/__init__.py +0 -18
- ansible/utils/_ssh_agent.py +657 -0
- ansible/utils/collection_loader/__init__.py +52 -5
- ansible/utils/collection_loader/_collection_config.py +5 -6
- ansible/utils/collection_loader/_collection_finder.py +79 -93
- ansible/utils/collection_loader/_collection_meta.py +13 -8
- ansible/utils/display.py +428 -58
- ansible/utils/encrypt.py +27 -19
- ansible/utils/fqcn.py +2 -2
- ansible/utils/hashing.py +2 -2
- ansible/utils/helpers.py +2 -2
- ansible/utils/listify.py +8 -8
- ansible/utils/lock.py +2 -2
- ansible/utils/path.py +4 -4
- ansible/utils/plugin_docs.py +14 -13
- ansible/utils/sentinel.py +4 -62
- ansible/utils/singleton.py +2 -0
- ansible/utils/ssh_functions.py +1 -1
- ansible/utils/unsafe_proxy.py +23 -332
- ansible/utils/vars.py +28 -8
- ansible/utils/version.py +2 -2
- ansible/vars/clean.py +4 -4
- ansible/vars/hostvars.py +60 -90
- ansible/vars/manager.py +205 -264
- ansible/vars/reserved.py +8 -9
- ansible_core-2.19.0b1.dist-info/BSD-3-Clause.txt +28 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/METADATA +5 -4
- ansible_core-2.19.0b1.dist-info/RECORD +1070 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/WHEEL +1 -1
- ansible_test/_data/completion/docker.txt +7 -7
- ansible_test/_data/completion/remote.txt +6 -6
- ansible_test/_data/completion/windows.txt +1 -0
- ansible_test/_data/requirements/ansible.txt +2 -2
- ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
- ansible_test/_data/requirements/sanity.changelog.txt +1 -1
- ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
- ansible_test/_data/requirements/sanity.pylint.txt +4 -4
- ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
- ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
- ansible_test/_data/requirements/units.txt +1 -0
- ansible_test/_internal/__init__.py +1 -0
- ansible_test/_internal/ansible_util.py +2 -0
- ansible_test/_internal/become.py +1 -0
- ansible_test/_internal/bootstrap.py +1 -0
- ansible_test/_internal/cache.py +1 -0
- ansible_test/_internal/cgroup.py +1 -0
- ansible_test/_internal/ci/__init__.py +1 -0
- ansible_test/_internal/ci/azp.py +1 -0
- ansible_test/_internal/ci/local.py +1 -0
- ansible_test/_internal/classification/__init__.py +1 -0
- ansible_test/_internal/classification/common.py +1 -0
- ansible_test/_internal/classification/csharp.py +1 -0
- ansible_test/_internal/classification/powershell.py +1 -0
- ansible_test/_internal/classification/python.py +1 -0
- ansible_test/_internal/cli/__init__.py +1 -0
- ansible_test/_internal/cli/actions.py +1 -0
- ansible_test/_internal/cli/argparsing/__init__.py +1 -0
- ansible_test/_internal/cli/argparsing/actions.py +1 -0
- ansible_test/_internal/cli/argparsing/argcompletion.py +1 -0
- ansible_test/_internal/cli/argparsing/parsers.py +1 -0
- ansible_test/_internal/cli/commands/__init__.py +11 -0
- ansible_test/_internal/cli/commands/coverage/__init__.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/__init__.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/__init__.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/combine.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/expand.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/filter.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/generate.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/missing.py +1 -0
- ansible_test/_internal/cli/commands/coverage/combine.py +1 -0
- ansible_test/_internal/cli/commands/coverage/erase.py +1 -0
- ansible_test/_internal/cli/commands/coverage/html.py +1 -0
- ansible_test/_internal/cli/commands/coverage/report.py +1 -0
- ansible_test/_internal/cli/commands/coverage/xml.py +1 -0
- ansible_test/_internal/cli/commands/env.py +1 -0
- ansible_test/_internal/cli/commands/integration/__init__.py +1 -0
- ansible_test/_internal/cli/commands/integration/network.py +1 -0
- ansible_test/_internal/cli/commands/integration/posix.py +1 -0
- ansible_test/_internal/cli/commands/integration/windows.py +1 -0
- ansible_test/_internal/cli/commands/sanity.py +9 -0
- ansible_test/_internal/cli/commands/shell.py +1 -0
- ansible_test/_internal/cli/commands/units.py +1 -0
- ansible_test/_internal/cli/compat.py +1 -0
- ansible_test/_internal/cli/completers.py +1 -0
- ansible_test/_internal/cli/converters.py +1 -0
- ansible_test/_internal/cli/environments.py +1 -0
- ansible_test/_internal/cli/epilog.py +1 -0
- ansible_test/_internal/cli/parsers/__init__.py +1 -0
- ansible_test/_internal/cli/parsers/base_argument_parsers.py +1 -0
- ansible_test/_internal/cli/parsers/helpers.py +1 -0
- ansible_test/_internal/cli/parsers/host_config_parsers.py +1 -0
- ansible_test/_internal/cli/parsers/key_value_parsers.py +1 -0
- ansible_test/_internal/cli/parsers/value_parsers.py +1 -0
- ansible_test/_internal/commands/__init__.py +1 -0
- ansible_test/_internal/commands/coverage/__init__.py +2 -1
- ansible_test/_internal/commands/coverage/analyze/__init__.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/__init__.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/combine.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/expand.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/filter.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/generate.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/missing.py +1 -0
- ansible_test/_internal/commands/coverage/combine.py +2 -1
- ansible_test/_internal/commands/coverage/erase.py +1 -0
- ansible_test/_internal/commands/coverage/html.py +1 -0
- ansible_test/_internal/commands/coverage/report.py +1 -0
- ansible_test/_internal/commands/coverage/xml.py +1 -0
- ansible_test/_internal/commands/env/__init__.py +2 -0
- ansible_test/_internal/commands/integration/__init__.py +4 -0
- ansible_test/_internal/commands/integration/cloud/__init__.py +1 -0
- ansible_test/_internal/commands/integration/cloud/acme.py +2 -1
- ansible_test/_internal/commands/integration/cloud/aws.py +1 -0
- ansible_test/_internal/commands/integration/cloud/azure.py +1 -0
- ansible_test/_internal/commands/integration/cloud/cs.py +1 -0
- ansible_test/_internal/commands/integration/cloud/digitalocean.py +1 -0
- ansible_test/_internal/commands/integration/cloud/galaxy.py +3 -2
- ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -0
- ansible_test/_internal/commands/integration/cloud/httptester.py +2 -1
- ansible_test/_internal/commands/integration/cloud/nios.py +2 -1
- ansible_test/_internal/commands/integration/cloud/opennebula.py +1 -0
- ansible_test/_internal/commands/integration/cloud/openshift.py +1 -0
- ansible_test/_internal/commands/integration/cloud/scaleway.py +1 -0
- ansible_test/_internal/commands/integration/cloud/vcenter.py +1 -0
- ansible_test/_internal/commands/integration/cloud/vultr.py +1 -0
- ansible_test/_internal/commands/integration/coverage.py +1 -0
- ansible_test/_internal/commands/integration/filters.py +1 -0
- ansible_test/_internal/commands/integration/network.py +1 -0
- ansible_test/_internal/commands/integration/posix.py +1 -0
- ansible_test/_internal/commands/integration/windows.py +1 -0
- ansible_test/_internal/commands/sanity/__init__.py +16 -1
- ansible_test/_internal/commands/sanity/ansible_doc.py +1 -0
- ansible_test/_internal/commands/sanity/bin_symlinks.py +1 -0
- ansible_test/_internal/commands/sanity/compile.py +1 -0
- ansible_test/_internal/commands/sanity/ignores.py +1 -0
- ansible_test/_internal/commands/sanity/import.py +1 -0
- ansible_test/_internal/commands/sanity/integration_aliases.py +1 -0
- ansible_test/_internal/commands/sanity/pep8.py +1 -0
- ansible_test/_internal/commands/sanity/pslint.py +1 -0
- ansible_test/_internal/commands/sanity/pylint.py +24 -26
- ansible_test/_internal/commands/sanity/shellcheck.py +1 -0
- ansible_test/_internal/commands/sanity/validate_modules.py +1 -0
- ansible_test/_internal/commands/sanity/yamllint.py +1 -0
- ansible_test/_internal/commands/shell/__init__.py +1 -0
- ansible_test/_internal/commands/units/__init__.py +1 -0
- ansible_test/_internal/compat/__init__.py +1 -0
- ansible_test/_internal/compat/packaging.py +1 -0
- ansible_test/_internal/compat/yaml.py +1 -0
- ansible_test/_internal/completion.py +1 -0
- ansible_test/_internal/config.py +2 -0
- ansible_test/_internal/connections.py +1 -0
- ansible_test/_internal/constants.py +1 -0
- ansible_test/_internal/containers.py +1 -0
- ansible_test/_internal/content_config.py +1 -0
- ansible_test/_internal/core_ci.py +1 -0
- ansible_test/_internal/coverage_util.py +11 -10
- ansible_test/_internal/data.py +1 -0
- ansible_test/_internal/delegation.py +1 -0
- ansible_test/_internal/dev/__init__.py +1 -0
- ansible_test/_internal/dev/container_probe.py +1 -0
- ansible_test/_internal/diff.py +3 -2
- ansible_test/_internal/docker_util.py +2 -1
- ansible_test/_internal/encoding.py +1 -0
- ansible_test/_internal/executor.py +1 -0
- ansible_test/_internal/git.py +1 -0
- ansible_test/_internal/host_configs.py +1 -0
- ansible_test/_internal/host_profiles.py +1 -0
- ansible_test/_internal/http.py +1 -0
- ansible_test/_internal/init.py +1 -0
- ansible_test/_internal/inventory.py +35 -3
- ansible_test/_internal/io.py +1 -0
- ansible_test/_internal/metadata.py +1 -0
- ansible_test/_internal/payload.py +1 -0
- ansible_test/_internal/provider/__init__.py +1 -0
- ansible_test/_internal/provider/layout/__init__.py +1 -0
- ansible_test/_internal/provider/layout/ansible.py +1 -0
- ansible_test/_internal/provider/layout/collection.py +1 -0
- ansible_test/_internal/provider/layout/unsupported.py +1 -0
- ansible_test/_internal/provider/source/__init__.py +1 -0
- ansible_test/_internal/provider/source/git.py +1 -0
- ansible_test/_internal/provider/source/installed.py +1 -0
- ansible_test/_internal/provider/source/unsupported.py +1 -0
- ansible_test/_internal/provider/source/unversioned.py +1 -0
- ansible_test/_internal/provisioning.py +1 -0
- ansible_test/_internal/pypi_proxy.py +6 -5
- ansible_test/_internal/python_requirements.py +1 -0
- ansible_test/_internal/ssh.py +1 -0
- ansible_test/_internal/target.py +1 -0
- ansible_test/_internal/test.py +3 -2
- ansible_test/_internal/thread.py +1 -0
- ansible_test/_internal/timeout.py +1 -0
- ansible_test/_internal/util.py +1 -0
- ansible_test/_internal/util_common.py +5 -2
- ansible_test/_internal/venv.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/changelog/sphinx.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/changelog.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/empty-init.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/line-endings.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-assert.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-get-exception.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-illegal-filenames.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-smart-quotes.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/replace-urlopen.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +28 -1
- ansible_test/_util/controller/sanity/code-smell/shebang.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/symlinks.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/use-argspec-type-path.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/use-compat-six.py +1 -0
- ansible_test/_util/controller/sanity/integration-aliases/yaml_to_json.py +2 -1
- ansible_test/_util/controller/sanity/pep8/current-ignore.txt +4 -0
- ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +7 -5
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +7 -5
- ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +7 -5
- ansible_test/_util/controller/sanity/pylint/config/collection.cfg +3 -5
- ansible_test/_util/controller/sanity/pylint/config/default.cfg +7 -7
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -13
- ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +1 -0
- ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +1 -8
- ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +1 -8
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +55 -28
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +12 -5
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +13 -2
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -0
- ansible_test/_util/controller/sanity/yamllint/yamllinter.py +35 -17
- ansible_test/_util/controller/tools/collection_detail.py +1 -0
- ansible_test/_util/controller/tools/yaml_to_json.py +2 -1
- ansible_test/_util/target/pytest/plugins/ansible_forked.py +6 -1
- ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py +2 -1
- ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +1 -0
- ansible_test/_util/target/sanity/compile/compile.py +1 -0
- ansible_test/_util/target/sanity/import/importer.py +15 -16
- ansible_test/_util/target/setup/bootstrap.sh +9 -20
- ansible_test/_util/target/setup/probe_cgroups.py +1 -0
- ansible_test/_util/target/setup/quiet_pip.py +1 -0
- ansible_test/_util/target/setup/requirements.py +35 -27
- ansible_test/_util/target/tools/virtualenvcheck.py +2 -1
- ansible_test/_util/target/tools/yamlcheck.py +2 -1
- ansible/compat/selectors.py +0 -32
- ansible/errors/yaml_strings.py +0 -138
- ansible/executor/action_write_locks.py +0 -44
- ansible/executor/discovery/python_target.py +0 -47
- ansible/executor/powershell/module_powershell_wrapper.ps1 +0 -86
- ansible/executor/powershell/module_script_wrapper.ps1 +0 -22
- ansible/module_utils/compat/importlib.py +0 -26
- ansible/module_utils/compat/selectors.py +0 -32
- ansible/module_utils/pycompat24.py +0 -73
- ansible/parsing/utils/jsonify.py +0 -36
- ansible/parsing/yaml/constructor.py +0 -178
- ansible/template/native_helpers.py +0 -251
- ansible/template/template.py +0 -43
- ansible/template/vars.py +0 -77
- ansible/utils/native_jinja.py +0 -11
- ansible/vars/fact_cache.py +0 -71
- ansible_core-2.18.5rc1.dist-info/RECORD +0 -992
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/Apache-License.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/COPYING +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/MIT-license.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/PSF-license.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/simplified_bsd.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/top_level.txt +0 -0
File without changes
|
@@ -0,0 +1,240 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import abc
|
4
|
+
import copy
|
5
|
+
import typing as t
|
6
|
+
|
7
|
+
from yaml import Node
|
8
|
+
from yaml.constructor import SafeConstructor
|
9
|
+
from yaml.resolver import BaseResolver
|
10
|
+
|
11
|
+
from ansible import constants as C
|
12
|
+
from ansible.module_utils.common.text.converters import to_text
|
13
|
+
from ansible.module_utils._internal._datatag import AnsibleTagHelper
|
14
|
+
from ansible._internal._datatag._tags import Origin, TrustedAsTemplate
|
15
|
+
from ansible.parsing.vault import EncryptedString
|
16
|
+
from ansible.utils.display import Display
|
17
|
+
|
18
|
+
from ._errors import AnsibleConstructorError
|
19
|
+
|
20
|
+
display = Display()
|
21
|
+
|
22
|
+
_TRUSTED_AS_TEMPLATE: t.Final[TrustedAsTemplate] = TrustedAsTemplate()
|
23
|
+
|
24
|
+
|
25
|
+
class _BaseConstructor(SafeConstructor, metaclass=abc.ABCMeta):
|
26
|
+
"""Base class for Ansible YAML constructors."""
|
27
|
+
|
28
|
+
@classmethod
|
29
|
+
@abc.abstractmethod
|
30
|
+
def _register_constructors(cls) -> None:
|
31
|
+
"""Method used to register constructors to derived types during class initialization."""
|
32
|
+
|
33
|
+
def __init_subclass__(cls, **kwargs) -> None:
|
34
|
+
"""Initialization for derived types."""
|
35
|
+
cls._register_constructors()
|
36
|
+
|
37
|
+
|
38
|
+
class AnsibleInstrumentedConstructor(_BaseConstructor):
|
39
|
+
"""Ansible constructor which supports Ansible custom behavior such as `Origin` tagging, but no Ansible-specific YAML tags."""
|
40
|
+
|
41
|
+
name: t.Any # provided by the YAML parser, which retrieves it from the stream
|
42
|
+
|
43
|
+
def __init__(self, origin: Origin, trusted_as_template: bool) -> None:
|
44
|
+
if not origin.line_num:
|
45
|
+
origin = origin.replace(line_num=1)
|
46
|
+
|
47
|
+
self._origin = origin
|
48
|
+
self._trusted_as_template = trusted_as_template
|
49
|
+
self._duplicate_key_mode = C.config.get_config_value('DUPLICATE_YAML_DICT_KEY')
|
50
|
+
|
51
|
+
super().__init__()
|
52
|
+
|
53
|
+
@property
|
54
|
+
def trusted_as_template(self) -> bool:
|
55
|
+
return self._trusted_as_template
|
56
|
+
|
57
|
+
def construct_yaml_map(self, node):
|
58
|
+
data = self._node_position_info(node).tag({}) # always an ordered dictionary on py3.7+
|
59
|
+
yield data
|
60
|
+
value = self.construct_mapping(node)
|
61
|
+
data.update(value)
|
62
|
+
|
63
|
+
def construct_mapping(self, node, deep=False):
|
64
|
+
# Delegate to built-in implementation to construct the mapping.
|
65
|
+
# This is done before checking for duplicates to leverage existing error checking on the input node.
|
66
|
+
mapping = super().construct_mapping(node, deep)
|
67
|
+
keys = set()
|
68
|
+
|
69
|
+
# Now that the node is known to be a valid mapping, handle any duplicate keys.
|
70
|
+
for key_node, _value_node in node.value:
|
71
|
+
if (key := self.construct_object(key_node, deep=deep)) in keys:
|
72
|
+
msg = f'Found duplicate mapping key {key!r}.'
|
73
|
+
|
74
|
+
if self._duplicate_key_mode == 'error':
|
75
|
+
raise AnsibleConstructorError(problem=msg, problem_mark=key_node.start_mark)
|
76
|
+
|
77
|
+
if self._duplicate_key_mode == 'warn':
|
78
|
+
display.warning(msg=msg, obj=key, help_text='Using last defined value only.')
|
79
|
+
|
80
|
+
keys.add(key)
|
81
|
+
|
82
|
+
return mapping
|
83
|
+
|
84
|
+
def construct_yaml_int(self, node):
|
85
|
+
value = super().construct_yaml_int(node)
|
86
|
+
return self._node_position_info(node).tag(value)
|
87
|
+
|
88
|
+
def construct_yaml_float(self, node):
|
89
|
+
value = super().construct_yaml_float(node)
|
90
|
+
return self._node_position_info(node).tag(value)
|
91
|
+
|
92
|
+
def construct_yaml_timestamp(self, node):
|
93
|
+
value = super().construct_yaml_timestamp(node)
|
94
|
+
return self._node_position_info(node).tag(value)
|
95
|
+
|
96
|
+
def construct_yaml_omap(self, node):
|
97
|
+
origin = self._node_position_info(node)
|
98
|
+
display.deprecated(
|
99
|
+
msg='Use of the YAML `!!omap` tag is deprecated.',
|
100
|
+
version='2.23',
|
101
|
+
obj=origin,
|
102
|
+
help_text='Use a standard mapping instead, as key order is always preserved.',
|
103
|
+
)
|
104
|
+
items = list(super().construct_yaml_omap(node))[0]
|
105
|
+
items = [origin.tag(item) for item in items]
|
106
|
+
yield origin.tag(items)
|
107
|
+
|
108
|
+
def construct_yaml_pairs(self, node):
|
109
|
+
origin = self._node_position_info(node)
|
110
|
+
display.deprecated(
|
111
|
+
msg='Use of the YAML `!!pairs` tag is deprecated.',
|
112
|
+
version='2.23',
|
113
|
+
obj=origin,
|
114
|
+
help_text='Use a standard mapping instead.',
|
115
|
+
)
|
116
|
+
items = list(super().construct_yaml_pairs(node))[0]
|
117
|
+
items = [origin.tag(item) for item in items]
|
118
|
+
yield origin.tag(items)
|
119
|
+
|
120
|
+
def construct_yaml_str(self, node):
|
121
|
+
# Override the default string handling function
|
122
|
+
# to always return unicode objects
|
123
|
+
# DTFIX-FUTURE: is this to_text conversion still necessary under Py3?
|
124
|
+
value = to_text(self.construct_scalar(node))
|
125
|
+
|
126
|
+
tags = [self._node_position_info(node)]
|
127
|
+
|
128
|
+
if self.trusted_as_template:
|
129
|
+
# NB: since we're not context aware, this will happily add trust to dictionary keys; this is actually necessary for
|
130
|
+
# certain backward compat scenarios, though might be accomplished in other ways if we wanted to avoid trusting keys in
|
131
|
+
# the general scenario
|
132
|
+
tags.append(_TRUSTED_AS_TEMPLATE)
|
133
|
+
|
134
|
+
return AnsibleTagHelper.tag(value, tags)
|
135
|
+
|
136
|
+
def construct_yaml_binary(self, node):
|
137
|
+
value = super().construct_yaml_binary(node)
|
138
|
+
|
139
|
+
return AnsibleTagHelper.tag(value, self._node_position_info(node))
|
140
|
+
|
141
|
+
def construct_yaml_set(self, node):
|
142
|
+
data = AnsibleTagHelper.tag(set(), self._node_position_info(node))
|
143
|
+
yield data
|
144
|
+
value = self.construct_mapping(node)
|
145
|
+
data.update(value)
|
146
|
+
|
147
|
+
def construct_yaml_seq(self, node):
|
148
|
+
data = self._node_position_info(node).tag([])
|
149
|
+
yield data
|
150
|
+
data.extend(self.construct_sequence(node))
|
151
|
+
|
152
|
+
def _resolve_and_construct_object(self, node):
|
153
|
+
# use a copied node to avoid mutating existing node and tripping the recursion check in construct_object
|
154
|
+
copied_node = copy.copy(node)
|
155
|
+
# repeat implicit resolution process to determine the proper tag for the value in the unsafe node
|
156
|
+
copied_node.tag = t.cast(BaseResolver, self).resolve(type(node), node.value, (True, False))
|
157
|
+
|
158
|
+
# re-entrant call using the correct tag
|
159
|
+
# non-deferred construction of hierarchical nodes so the result is a fully realized object, and so our stateful unsafe propagation behavior works
|
160
|
+
return self.construct_object(copied_node, deep=True)
|
161
|
+
|
162
|
+
def _node_position_info(self, node) -> Origin:
|
163
|
+
# the line number where the previous token has ended (plus empty lines)
|
164
|
+
# Add one so that the first line is line 1 rather than line 0
|
165
|
+
return self._origin.replace(line_num=node.start_mark.line + self._origin.line_num, col_num=node.start_mark.column + 1)
|
166
|
+
|
167
|
+
@classmethod
|
168
|
+
def _register_constructors(cls) -> None:
|
169
|
+
constructors: dict[str, t.Callable] = {
|
170
|
+
'tag:yaml.org,2002:binary': cls.construct_yaml_binary,
|
171
|
+
'tag:yaml.org,2002:float': cls.construct_yaml_float,
|
172
|
+
'tag:yaml.org,2002:int': cls.construct_yaml_int,
|
173
|
+
'tag:yaml.org,2002:map': cls.construct_yaml_map,
|
174
|
+
'tag:yaml.org,2002:omap': cls.construct_yaml_omap,
|
175
|
+
'tag:yaml.org,2002:pairs': cls.construct_yaml_pairs,
|
176
|
+
'tag:yaml.org,2002:python/dict': cls.construct_yaml_map,
|
177
|
+
'tag:yaml.org,2002:python/unicode': cls.construct_yaml_str,
|
178
|
+
'tag:yaml.org,2002:seq': cls.construct_yaml_seq,
|
179
|
+
'tag:yaml.org,2002:set': cls.construct_yaml_set,
|
180
|
+
'tag:yaml.org,2002:str': cls.construct_yaml_str,
|
181
|
+
'tag:yaml.org,2002:timestamp': cls.construct_yaml_timestamp,
|
182
|
+
}
|
183
|
+
|
184
|
+
for tag, constructor in constructors.items():
|
185
|
+
cls.add_constructor(tag, constructor)
|
186
|
+
|
187
|
+
|
188
|
+
class AnsibleConstructor(AnsibleInstrumentedConstructor):
|
189
|
+
"""Ansible constructor which supports Ansible custom behavior such as `Origin` tagging, as well as Ansible-specific YAML tags."""
|
190
|
+
|
191
|
+
def __init__(self, origin: Origin, trusted_as_template: bool) -> None:
|
192
|
+
self._unsafe_depth = 0 # volatile state var used during recursive construction of a value tagged unsafe
|
193
|
+
|
194
|
+
super().__init__(origin=origin, trusted_as_template=trusted_as_template)
|
195
|
+
|
196
|
+
@property
|
197
|
+
def trusted_as_template(self) -> bool:
|
198
|
+
return self._trusted_as_template and not self._unsafe_depth
|
199
|
+
|
200
|
+
def construct_yaml_unsafe(self, node):
|
201
|
+
self._unsafe_depth += 1
|
202
|
+
|
203
|
+
try:
|
204
|
+
return self._resolve_and_construct_object(node)
|
205
|
+
finally:
|
206
|
+
self._unsafe_depth -= 1
|
207
|
+
|
208
|
+
def construct_yaml_vault(self, node: Node) -> EncryptedString:
|
209
|
+
ciphertext = self._resolve_and_construct_object(node)
|
210
|
+
|
211
|
+
if not isinstance(ciphertext, str):
|
212
|
+
raise AnsibleConstructorError(problem=f"the {node.tag!r} tag requires a string value", problem_mark=node.start_mark)
|
213
|
+
|
214
|
+
encrypted_string = AnsibleTagHelper.tag_copy(ciphertext, EncryptedString(ciphertext=AnsibleTagHelper.untag(ciphertext)))
|
215
|
+
|
216
|
+
return encrypted_string
|
217
|
+
|
218
|
+
def construct_yaml_vault_encrypted(self, node: Node) -> EncryptedString:
|
219
|
+
origin = self._node_position_info(node)
|
220
|
+
display.deprecated(
|
221
|
+
msg='Use of the YAML `!vault-encrypted` tag is deprecated.',
|
222
|
+
version='2.23',
|
223
|
+
obj=origin,
|
224
|
+
help_text='Use the `!vault` tag instead.',
|
225
|
+
)
|
226
|
+
|
227
|
+
return self.construct_yaml_vault(node)
|
228
|
+
|
229
|
+
@classmethod
|
230
|
+
def _register_constructors(cls) -> None:
|
231
|
+
super()._register_constructors()
|
232
|
+
|
233
|
+
constructors: dict[str, t.Callable] = {
|
234
|
+
'!unsafe': cls.construct_yaml_unsafe,
|
235
|
+
'!vault': cls.construct_yaml_vault,
|
236
|
+
'!vault-encrypted': cls.construct_yaml_vault_encrypted,
|
237
|
+
}
|
238
|
+
|
239
|
+
for tag, constructor in constructors.items():
|
240
|
+
cls.add_constructor(tag, constructor)
|
@@ -0,0 +1,62 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import abc
|
4
|
+
import collections.abc as c
|
5
|
+
import typing as t
|
6
|
+
|
7
|
+
from yaml.representer import SafeRepresenter
|
8
|
+
|
9
|
+
from ansible.module_utils._internal._datatag import AnsibleTaggedObject, Tripwire, AnsibleTagHelper
|
10
|
+
from ansible.parsing.vault import VaultHelper
|
11
|
+
from ansible.module_utils.common.yaml import HAS_LIBYAML
|
12
|
+
|
13
|
+
if HAS_LIBYAML:
|
14
|
+
from yaml.cyaml import CSafeDumper as SafeDumper
|
15
|
+
else:
|
16
|
+
from yaml import SafeDumper # type: ignore[assignment]
|
17
|
+
|
18
|
+
|
19
|
+
class _BaseDumper(SafeDumper, metaclass=abc.ABCMeta):
|
20
|
+
"""Base class for Ansible YAML dumpers."""
|
21
|
+
|
22
|
+
@classmethod
|
23
|
+
@abc.abstractmethod
|
24
|
+
def _register_representers(cls) -> None:
|
25
|
+
"""Method used to register representers to derived types during class initialization."""
|
26
|
+
|
27
|
+
def __init_subclass__(cls, **kwargs) -> None:
|
28
|
+
"""Initialization for derived types."""
|
29
|
+
cls._register_representers()
|
30
|
+
|
31
|
+
|
32
|
+
class AnsibleDumper(_BaseDumper):
|
33
|
+
"""A simple stub class that allows us to add representers for our custom types."""
|
34
|
+
|
35
|
+
# DTFIX-RELEASE: need a better way to handle serialization controls during YAML dumping
|
36
|
+
def __init__(self, *args, dump_vault_tags: bool | None = None, **kwargs):
|
37
|
+
super().__init__(*args, **kwargs)
|
38
|
+
|
39
|
+
self._dump_vault_tags = dump_vault_tags
|
40
|
+
|
41
|
+
@classmethod
|
42
|
+
def _register_representers(cls) -> None:
|
43
|
+
cls.add_multi_representer(AnsibleTaggedObject, cls.represent_ansible_tagged_object)
|
44
|
+
cls.add_multi_representer(Tripwire, cls.represent_tripwire)
|
45
|
+
cls.add_multi_representer(c.Mapping, SafeRepresenter.represent_dict)
|
46
|
+
cls.add_multi_representer(c.Sequence, SafeRepresenter.represent_list)
|
47
|
+
|
48
|
+
def represent_ansible_tagged_object(self, data):
|
49
|
+
if self._dump_vault_tags is not False and (ciphertext := VaultHelper.get_ciphertext(data, with_tags=False)):
|
50
|
+
# deprecated: description='enable the deprecation warning below' core_version='2.23'
|
51
|
+
# if self._dump_vault_tags is None:
|
52
|
+
# Display().deprecated(
|
53
|
+
# msg="Implicit YAML dumping of vaulted value ciphertext is deprecated. Set `dump_vault_tags` to explicitly specify the desired behavior",
|
54
|
+
# version="2.27",
|
55
|
+
# )
|
56
|
+
|
57
|
+
return self.represent_scalar('!vault', ciphertext, style='|')
|
58
|
+
|
59
|
+
return self.represent_data(AnsibleTagHelper.as_native_type(data)) # automatically decrypts encrypted strings
|
60
|
+
|
61
|
+
def represent_tripwire(self, data: Tripwire) -> t.NoReturn:
|
62
|
+
data.trip()
|
@@ -0,0 +1,166 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import re
|
4
|
+
|
5
|
+
import typing as t
|
6
|
+
|
7
|
+
from yaml import MarkedYAMLError
|
8
|
+
from yaml.constructor import ConstructorError
|
9
|
+
|
10
|
+
from ansible._internal._errors import _utils
|
11
|
+
from ansible.errors import AnsibleParserError
|
12
|
+
from ansible._internal._datatag._tags import Origin
|
13
|
+
|
14
|
+
|
15
|
+
class AnsibleConstructorError(ConstructorError):
|
16
|
+
"""Ansible-specific ConstructorError used to bypass exception analysis during wrapping in AnsibleYAMLParserError."""
|
17
|
+
|
18
|
+
|
19
|
+
class AnsibleYAMLParserError(AnsibleParserError):
|
20
|
+
"""YAML-specific parsing failure wrapping an exception raised by the YAML parser."""
|
21
|
+
|
22
|
+
_default_message = 'YAML parsing failed.'
|
23
|
+
|
24
|
+
_include_cause_message = False # hide the underlying cause message, it's included by `handle_exception` as needed
|
25
|
+
|
26
|
+
_formatted_source_context_value: str | None = None
|
27
|
+
|
28
|
+
@property
|
29
|
+
def _formatted_source_context(self) -> str | None:
|
30
|
+
return self._formatted_source_context_value
|
31
|
+
|
32
|
+
@classmethod
|
33
|
+
def handle_exception(cls, exception: Exception, origin: Origin) -> t.NoReturn:
|
34
|
+
if isinstance(exception, MarkedYAMLError):
|
35
|
+
origin = origin.replace(line_num=exception.problem_mark.line + 1, col_num=exception.problem_mark.column + 1)
|
36
|
+
|
37
|
+
source_context = _utils.SourceContext.from_origin(origin)
|
38
|
+
|
39
|
+
target_line = source_context.target_line or '' # for these cases, we don't need to distinguish between None and empty string
|
40
|
+
|
41
|
+
message: str | None = None
|
42
|
+
help_text = None
|
43
|
+
|
44
|
+
# FIXME: Do all this by walking the parsed YAML doc stream. Using regexes is a dead-end; YAML's just too flexible to not have a
|
45
|
+
# raft of false-positives and corner cases. If we directly consume either the YAML parse stream or override the YAML composer, we can
|
46
|
+
# better catch these things without worrying about duplicating YAML's scalar parsing logic around quoting/escaping. At first, we can
|
47
|
+
# replace the regex logic below with tiny special-purpose parse consumers to catch specific issues, but ideally, we could do a lot of this
|
48
|
+
# inline with the actual doc parse, since our rules are a lot more strict than YAML's (eg, no support for non-scalar keys), and a lot of the
|
49
|
+
# problem cases where that comes into play are around expression quoting and Jinja {{ syntax looking like weird YAML values we don't support.
|
50
|
+
# Some common examples, where -> is "what YAML actually sees":
|
51
|
+
# foo: {{ bar }} -> {"foo": {{"bar": None}: None}} - a mapping with a mapping as its key (legal YAML, but not legal Python/Ansible)
|
52
|
+
#
|
53
|
+
# - copy: src=foo.txt # kv syntax (kv could be on following line(s), too- implicit multi-line block scalar)
|
54
|
+
# dest: bar.txt # orphaned mapping, since the value of `copy` is the scalar "src=foo.txt"
|
55
|
+
#
|
56
|
+
# - msg == "Error: 'dude' was not found" # unquoted scalar has a : in it -> {'msg == "Error"': 'dude'} [ was not found" ] is garbage orphan scalar
|
57
|
+
|
58
|
+
# noinspection PyUnboundLocalVariable
|
59
|
+
if not isinstance(exception, MarkedYAMLError):
|
60
|
+
pass # unexpected exception, don't use special analysis of exception
|
61
|
+
|
62
|
+
elif isinstance(exception, AnsibleConstructorError):
|
63
|
+
pass # raised internally by ansible code, don't use special analysis of exception
|
64
|
+
|
65
|
+
# Check for tabs.
|
66
|
+
# There may be cases where there is a valid tab in a line that has other errors.
|
67
|
+
# That's OK, users should "fix" their tab usage anyway -- at which point later error handling logic will hopefully find the real issue.
|
68
|
+
elif (tab_idx := target_line.find('\t')) >= 0:
|
69
|
+
source_context = _utils.SourceContext.from_origin(origin.replace(col_num=tab_idx + 1))
|
70
|
+
message = "Tabs are usually invalid in YAML."
|
71
|
+
|
72
|
+
# Check for unquoted templates.
|
73
|
+
elif match := re.search(r'^\s*(?:-\s+)*(?:[\w\s]+:\s+)?(?P<value>\{\{.*}})', target_line):
|
74
|
+
source_context = _utils.SourceContext.from_origin(origin.replace(col_num=match.start('value') + 1))
|
75
|
+
message = 'This may be an issue with missing quotes around a template block.'
|
76
|
+
# FIXME: Use the captured value to show the actual fix required.
|
77
|
+
help_text = """
|
78
|
+
For example:
|
79
|
+
|
80
|
+
raw: {{ some_var }}
|
81
|
+
|
82
|
+
Should be:
|
83
|
+
|
84
|
+
raw: "{{ some_var }}"
|
85
|
+
"""
|
86
|
+
|
87
|
+
# Check for common unquoted colon mistakes.
|
88
|
+
elif (
|
89
|
+
# ignore lines starting with only whitespace and a colon
|
90
|
+
not target_line.lstrip().startswith(':')
|
91
|
+
# find the value after list/dict preamble
|
92
|
+
and (value_match := re.search(r'^\s*(?:-\s+)*(?:[\w\s\[\]{}]+:\s+)?(?P<value>.*)$', target_line))
|
93
|
+
# ignore properly quoted values
|
94
|
+
and (target_fragment := _replace_quoted_value(value_match.group('value')))
|
95
|
+
# look for an unquoted colon in the value
|
96
|
+
and (colon_match := re.search(r':($| )', target_fragment))
|
97
|
+
):
|
98
|
+
source_context = _utils.SourceContext.from_origin(origin.replace(col_num=value_match.start('value') + colon_match.start() + 1))
|
99
|
+
message = 'Colons in unquoted values must be followed by a non-space character.'
|
100
|
+
# FIXME: Use the captured value to show the actual fix required.
|
101
|
+
help_text = """
|
102
|
+
For example:
|
103
|
+
|
104
|
+
raw: echo 'name: ansible'
|
105
|
+
|
106
|
+
Should be:
|
107
|
+
|
108
|
+
raw: "echo 'name: ansible'"
|
109
|
+
"""
|
110
|
+
|
111
|
+
# Check for common quoting mistakes.
|
112
|
+
elif match := re.search(r'^\s*(?:-\s+)*(?:[\w\s]+:\s+)?(?P<value>[\"\'].*?\s*)$', target_line):
|
113
|
+
suspected_value = match.group('value')
|
114
|
+
first, last = suspected_value[0], suspected_value[-1]
|
115
|
+
|
116
|
+
if first != last: # "foo" in bar
|
117
|
+
source_context = _utils.SourceContext.from_origin(origin.replace(col_num=match.start('value') + 1))
|
118
|
+
message = 'Values starting with a quote must end with the same quote.'
|
119
|
+
# FIXME: Use the captured value to show the actual fix required, and use that same logic to improve the origin further.
|
120
|
+
help_text = """
|
121
|
+
For example:
|
122
|
+
|
123
|
+
raw: "foo" in bar
|
124
|
+
|
125
|
+
Should be:
|
126
|
+
|
127
|
+
raw: '"foo" in bar'
|
128
|
+
"""
|
129
|
+
elif first == last and target_line.count(first) > 2: # "foo" and "bar"
|
130
|
+
source_context = _utils.SourceContext.from_origin(origin.replace(col_num=match.start('value') + 1))
|
131
|
+
message = 'Values starting with a quote must end with the same quote, and not contain that quote.'
|
132
|
+
# FIXME: Use the captured value to show the actual fix required, and use that same logic to improve the origin further.
|
133
|
+
help_text = """
|
134
|
+
For example:
|
135
|
+
|
136
|
+
raw: "foo" in "bar"
|
137
|
+
|
138
|
+
Should be:
|
139
|
+
|
140
|
+
raw: '"foo" in "bar"'
|
141
|
+
"""
|
142
|
+
|
143
|
+
if not message:
|
144
|
+
if isinstance(exception, MarkedYAMLError):
|
145
|
+
# marked YAML error, pull out the useful messages while omitting the noise
|
146
|
+
message = ' '.join(filter(None, (exception.context, exception.problem, exception.note)))
|
147
|
+
message = message.strip()
|
148
|
+
message = f'{message[0].upper()}{message[1:]}'
|
149
|
+
|
150
|
+
if not message.endswith('.'):
|
151
|
+
message += '.'
|
152
|
+
else:
|
153
|
+
# unexpected error, use the exception message (normally hidden by overriding include_cause_message)
|
154
|
+
message = str(exception)
|
155
|
+
|
156
|
+
message = re.sub(r'\s+', ' ', message).strip()
|
157
|
+
|
158
|
+
error = cls(message, obj=source_context.origin)
|
159
|
+
error._formatted_source_context_value = str(source_context)
|
160
|
+
error._help_text = help_text
|
161
|
+
|
162
|
+
raise error from exception
|
163
|
+
|
164
|
+
|
165
|
+
def _replace_quoted_value(value: str, replacement='.') -> str:
|
166
|
+
return re.sub(r"""^\s*('[^']*'|"[^"]*")\s*$""", lambda match: replacement * len(match.group(0)), value)
|
@@ -0,0 +1,66 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import io as _io
|
4
|
+
|
5
|
+
from yaml.resolver import Resolver
|
6
|
+
|
7
|
+
from ansible.module_utils._internal._datatag import AnsibleTagHelper
|
8
|
+
from ansible.module_utils.common.yaml import HAS_LIBYAML
|
9
|
+
from ansible._internal._datatag import _tags
|
10
|
+
|
11
|
+
from ._constructor import AnsibleConstructor, AnsibleInstrumentedConstructor
|
12
|
+
|
13
|
+
if HAS_LIBYAML:
|
14
|
+
from yaml.cyaml import CParser
|
15
|
+
|
16
|
+
class _YamlParser(CParser):
|
17
|
+
def __init__(self, stream: str | bytes | _io.IOBase) -> None:
|
18
|
+
if isinstance(stream, (str, bytes)):
|
19
|
+
stream = AnsibleTagHelper.untag(stream) # PyYAML + libyaml barfs on str/bytes subclasses
|
20
|
+
|
21
|
+
CParser.__init__(self, stream)
|
22
|
+
|
23
|
+
self.name = getattr(stream, 'name', None) # provide feature parity with the Python implementation (yaml.reader.Reader provides name)
|
24
|
+
|
25
|
+
else:
|
26
|
+
from yaml.composer import Composer
|
27
|
+
from yaml.reader import Reader
|
28
|
+
from yaml.scanner import Scanner
|
29
|
+
from yaml.parser import Parser
|
30
|
+
|
31
|
+
class _YamlParser(Reader, Scanner, Parser, Composer): # type: ignore[no-redef]
|
32
|
+
def __init__(self, stream: str | bytes | _io.IOBase) -> None:
|
33
|
+
Reader.__init__(self, stream)
|
34
|
+
Scanner.__init__(self)
|
35
|
+
Parser.__init__(self)
|
36
|
+
Composer.__init__(self)
|
37
|
+
|
38
|
+
|
39
|
+
class AnsibleInstrumentedLoader(_YamlParser, AnsibleInstrumentedConstructor, Resolver):
|
40
|
+
"""Ansible YAML loader which supports Ansible custom behavior such as `Origin` tagging, but no Ansible-specific YAML tags."""
|
41
|
+
|
42
|
+
def __init__(self, stream: str | bytes | _io.IOBase) -> None:
|
43
|
+
_YamlParser.__init__(self, stream)
|
44
|
+
|
45
|
+
AnsibleInstrumentedConstructor.__init__(
|
46
|
+
self,
|
47
|
+
origin=_tags.Origin.get_or_create_tag(stream, self.name),
|
48
|
+
trusted_as_template=_tags.TrustedAsTemplate.is_tagged_on(stream),
|
49
|
+
)
|
50
|
+
|
51
|
+
Resolver.__init__(self)
|
52
|
+
|
53
|
+
|
54
|
+
class AnsibleLoader(_YamlParser, AnsibleConstructor, Resolver):
|
55
|
+
"""Ansible loader which supports Ansible custom behavior such as `Origin` tagging, as well as Ansible-specific YAML tags."""
|
56
|
+
|
57
|
+
def __init__(self, stream: str | bytes | _io.IOBase) -> None:
|
58
|
+
_YamlParser.__init__(self, stream)
|
59
|
+
|
60
|
+
AnsibleConstructor.__init__(
|
61
|
+
self,
|
62
|
+
origin=_tags.Origin.get_or_create_tag(stream, self.name),
|
63
|
+
trusted_as_template=_tags.TrustedAsTemplate.is_tagged_on(stream),
|
64
|
+
)
|
65
|
+
|
66
|
+
Resolver.__init__(self)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
"Protomatter - an unstable substance which every ethical scientist in the galaxy has denounced as dangerously unpredictable."
|
2
|
+
|
3
|
+
"But it was the only way to solve certain problems..."
|
4
|
+
|
5
|
+
This Ansible Collection is embedded within ansible-core.
|
6
|
+
It contains plugins useful for ansible-core's own integration tests.
|
7
|
+
They have been made available, completely unsupported,
|
8
|
+
in case they prove useful for debugging and troubleshooting purposes.
|
9
|
+
|
10
|
+
> CAUTION: This collection is not supported, and may be changed or removed in any version without prior notice.
|
11
|
+
Use of these plugins outside ansible-core is highly discouraged.
|
@@ -0,0 +1,36 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import typing as t
|
4
|
+
|
5
|
+
from ansible.module_utils.common.validation import _check_type_str_no_conversion, _check_type_list_strict
|
6
|
+
from ansible.plugins.action import ActionBase
|
7
|
+
from ansible._internal._templating._engine import TemplateEngine
|
8
|
+
from ansible._internal._templating._marker_behaviors import ReplacingMarkerBehavior
|
9
|
+
|
10
|
+
|
11
|
+
class ActionModule(ActionBase):
|
12
|
+
TRANSFERS_FILES = False
|
13
|
+
_requires_connection = False
|
14
|
+
|
15
|
+
@classmethod
|
16
|
+
def finalize_task_arg(cls, name: str, value: t.Any, templar: TemplateEngine, context: t.Any) -> t.Any:
|
17
|
+
if name == 'expression':
|
18
|
+
return value
|
19
|
+
|
20
|
+
return super().finalize_task_arg(name, value, templar, context)
|
21
|
+
|
22
|
+
def run(self, tmp=None, task_vars=None):
|
23
|
+
# accepts a list of literal expressions (no templating), evaluates with no failure on undefined, returns all results
|
24
|
+
_vr, args = self.validate_argument_spec(
|
25
|
+
argument_spec=dict(
|
26
|
+
expression=dict(type=_check_type_list_strict, elements=_check_type_str_no_conversion, required=True),
|
27
|
+
),
|
28
|
+
)
|
29
|
+
|
30
|
+
with ReplacingMarkerBehavior.warning_context() as replacing_behavior:
|
31
|
+
templar = self._templar._engine.extend(marker_behavior=replacing_behavior)
|
32
|
+
|
33
|
+
return dict(
|
34
|
+
_ansible_verbose_always=True,
|
35
|
+
expression_result=[templar.evaluate_expression(expression) for expression in args['expression']],
|
36
|
+
)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import typing as t
|
4
|
+
|
5
|
+
from ansible._internal._datatag._tags import TrustedAsTemplate
|
6
|
+
|
7
|
+
|
8
|
+
def apply_trust(value: object) -> object:
|
9
|
+
"""
|
10
|
+
Filter that returns a tagged copy of the input string with TrustedAsTemplate.
|
11
|
+
Containers and other non-string values are returned unmodified.
|
12
|
+
"""
|
13
|
+
return TrustedAsTemplate().tag(value) if isinstance(value, str) else value
|
14
|
+
|
15
|
+
|
16
|
+
class FilterModule:
|
17
|
+
@staticmethod
|
18
|
+
def filters() -> dict[str, t.Callable]:
|
19
|
+
return dict(apply_trust=apply_trust)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import dataclasses
|
4
|
+
import typing as t
|
5
|
+
|
6
|
+
|
7
|
+
def dump_object(value: t.Any) -> object:
|
8
|
+
"""Internal filter to convert objects not supported by JSON to types which are."""
|
9
|
+
if dataclasses.is_dataclass(value):
|
10
|
+
return dataclasses.asdict(value) # type: ignore[arg-type]
|
11
|
+
|
12
|
+
return value
|
13
|
+
|
14
|
+
|
15
|
+
class FilterModule(object):
|
16
|
+
@staticmethod
|
17
|
+
def filters() -> dict[str, t.Callable]:
|
18
|
+
return dict(dump_object=dump_object)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import typing as t
|
4
|
+
|
5
|
+
from ansible._internal._templating._engine import _finalize_template_result, FinalizeMode
|
6
|
+
|
7
|
+
|
8
|
+
def finalize(value: t.Any) -> t.Any:
|
9
|
+
"""Perform an explicit top-level template finalize operation on the supplied value."""
|
10
|
+
return _finalize_template_result(value, mode=FinalizeMode.TOP_LEVEL)
|
11
|
+
|
12
|
+
|
13
|
+
class FilterModule:
|
14
|
+
@staticmethod
|
15
|
+
def filters() -> dict[str, t.Callable]:
|
16
|
+
return dict(finalize=finalize)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import typing as t
|
4
|
+
|
5
|
+
from ansible._internal._datatag._tags import Origin
|
6
|
+
|
7
|
+
|
8
|
+
def origin(value: object) -> str | None:
|
9
|
+
"""Return the origin of the value, if any, otherwise `None`."""
|
10
|
+
origin_tag = Origin.get_tag(value)
|
11
|
+
|
12
|
+
return str(origin_tag) if origin_tag else None
|
13
|
+
|
14
|
+
|
15
|
+
class FilterModule:
|
16
|
+
@staticmethod
|
17
|
+
def filters() -> dict[str, t.Callable]:
|
18
|
+
return dict(origin=origin)
|