ansible-core 2.15.4rc1__py3-none-any.whl → 2.16.0b2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ansible-core might be problematic. Click here for more details.
- ansible/cli/__init__.py +3 -3
- ansible/cli/adhoc.py +1 -1
- ansible/cli/arguments/option_helpers.py +15 -5
- ansible/cli/config.py +2 -2
- ansible/cli/console.py +21 -17
- ansible/cli/doc.py +8 -9
- ansible/cli/galaxy.py +60 -27
- ansible/cli/inventory.py +1 -1
- ansible/cli/playbook.py +1 -1
- ansible/cli/pull.py +2 -2
- ansible/cli/scripts/ansible_connection_cli_stub.py +1 -1
- ansible/cli/vault.py +11 -6
- ansible/collections/__init__.py +0 -29
- ansible/collections/list.py +23 -44
- ansible/config/ansible_builtin_runtime.yml +8 -4
- ansible/config/base.yml +34 -22
- ansible/config/manager.py +1 -1
- ansible/constants.py +3 -5
- ansible/errors/__init__.py +1 -1
- ansible/executor/interpreter_discovery.py +1 -1
- ansible/executor/module_common.py +39 -32
- ansible/executor/play_iterator.py +0 -15
- ansible/executor/playbook_executor.py +3 -3
- ansible/executor/powershell/module_manifest.py +1 -1
- ansible/executor/powershell/module_wrapper.ps1 +4 -1
- ansible/executor/process/worker.py +22 -7
- ansible/executor/task_executor.py +39 -40
- ansible/executor/task_queue_manager.py +8 -11
- ansible/galaxy/__init__.py +1 -1
- ansible/galaxy/api.py +8 -11
- ansible/galaxy/collection/__init__.py +17 -4
- ansible/galaxy/collection/concrete_artifact_manager.py +7 -2
- ansible/galaxy/collection/galaxy_api_proxy.py +1 -1
- ansible/galaxy/data/container/README.md +3 -5
- ansible/galaxy/dependency_resolution/__init__.py +1 -6
- ansible/galaxy/dependency_resolution/dataclasses.py +22 -1
- ansible/galaxy/dependency_resolution/providers.py +61 -69
- ansible/galaxy/role.py +31 -13
- ansible/galaxy/token.py +2 -2
- ansible/inventory/group.py +1 -1
- ansible/inventory/manager.py +1 -1
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/basic.py +11 -41
- ansible/module_utils/common/file.py +0 -100
- ansible/module_utils/common/json.py +1 -1
- ansible/module_utils/common/locale.py +1 -1
- ansible/module_utils/common/text/converters.py +2 -2
- ansible/module_utils/common/validation.py +1 -1
- ansible/module_utils/compat/_selectors2.py +4 -4
- ansible/module_utils/compat/datetime.py +40 -0
- ansible/module_utils/compat/selinux.py +1 -1
- ansible/module_utils/compat/typing.py +1 -1
- ansible/module_utils/connection.py +1 -1
- ansible/module_utils/facts/hardware/linux.py +2 -2
- ansible/module_utils/facts/hardware/openbsd.py +1 -1
- ansible/module_utils/facts/network/linux.py +3 -3
- ansible/module_utils/facts/other/facter.py +8 -15
- ansible/module_utils/facts/sysctl.py +1 -1
- ansible/module_utils/facts/system/date_time.py +2 -2
- ansible/module_utils/facts/system/distribution.py +1 -1
- ansible/module_utils/facts/system/local.py +6 -2
- ansible/module_utils/facts/system/pkg_mgr.py +6 -1
- ansible/module_utils/facts/system/service_mgr.py +4 -2
- ansible/module_utils/parsing/convert_bool.py +1 -1
- ansible/module_utils/service.py +9 -6
- ansible/module_utils/urls.py +40 -22
- ansible/modules/add_host.py +2 -2
- ansible/modules/apt.py +48 -31
- ansible/modules/apt_key.py +4 -4
- ansible/modules/apt_repository.py +5 -5
- ansible/modules/assemble.py +7 -7
- ansible/modules/assert.py +1 -1
- ansible/modules/async_status.py +11 -7
- ansible/modules/async_wrapper.py +1 -1
- ansible/modules/blockinfile.py +60 -17
- ansible/modules/command.py +37 -15
- ansible/modules/copy.py +35 -30
- ansible/modules/cron.py +14 -14
- ansible/modules/deb822_repository.py +4 -3
- ansible/modules/debconf.py +35 -14
- ansible/modules/debug.py +1 -1
- ansible/modules/dnf.py +29 -27
- ansible/modules/dnf5.py +22 -22
- ansible/modules/dpkg_selections.py +9 -2
- ansible/modules/expect.py +4 -4
- ansible/modules/fetch.py +7 -7
- ansible/modules/file.py +30 -30
- ansible/modules/find.py +82 -22
- ansible/modules/gather_facts.py +6 -2
- ansible/modules/get_url.py +29 -29
- ansible/modules/getent.py +4 -4
- ansible/modules/git.py +27 -27
- ansible/modules/group.py +5 -12
- ansible/modules/hostname.py +21 -2
- ansible/modules/include_role.py +5 -5
- ansible/modules/include_tasks.py +2 -2
- ansible/modules/include_vars.py +5 -5
- ansible/modules/iptables.py +70 -65
- ansible/modules/known_hosts.py +7 -7
- ansible/modules/lineinfile.py +33 -33
- ansible/modules/meta.py +13 -13
- ansible/modules/package.py +8 -8
- ansible/modules/package_facts.py +3 -3
- ansible/modules/pause.py +2 -2
- ansible/modules/ping.py +5 -5
- ansible/modules/pip.py +80 -46
- ansible/modules/reboot.py +8 -4
- ansible/modules/replace.py +20 -15
- ansible/modules/rpm_key.py +2 -2
- ansible/modules/script.py +16 -10
- ansible/modules/service.py +26 -98
- ansible/modules/service_facts.py +36 -12
- ansible/modules/set_fact.py +2 -2
- ansible/modules/set_stats.py +2 -2
- ansible/modules/setup.py +18 -18
- ansible/modules/shell.py +3 -3
- ansible/modules/stat.py +9 -30
- ansible/modules/subversion.py +9 -9
- ansible/modules/systemd.py +20 -19
- ansible/modules/systemd_service.py +20 -19
- ansible/modules/sysvinit.py +26 -21
- ansible/modules/tempfile.py +5 -4
- ansible/modules/template.py +60 -6
- ansible/modules/unarchive.py +21 -18
- ansible/modules/uri.py +39 -39
- ansible/modules/user.py +81 -53
- ansible/modules/wait_for.py +22 -21
- ansible/modules/wait_for_connection.py +4 -4
- ansible/modules/yum.py +38 -38
- ansible/modules/yum_repository.py +58 -80
- ansible/parsing/dataloader.py +27 -27
- ansible/parsing/mod_args.py +1 -1
- ansible/parsing/plugin_docs.py +3 -3
- ansible/parsing/splitter.py +14 -16
- ansible/parsing/utils/yaml.py +1 -1
- ansible/parsing/vault/__init__.py +8 -6
- ansible/parsing/yaml/constructor.py +1 -1
- ansible/parsing/yaml/objects.py +1 -1
- ansible/playbook/__init__.py +1 -1
- ansible/playbook/base.py +2 -2
- ansible/playbook/block.py +0 -1
- ansible/playbook/conditional.py +40 -114
- ansible/playbook/helpers.py +5 -28
- ansible/playbook/included_file.py +8 -7
- ansible/playbook/play.py +1 -1
- ansible/playbook/play_context.py +2 -2
- ansible/playbook/playbook_include.py +2 -2
- ansible/playbook/role/__init__.py +1 -1
- ansible/playbook/role/include.py +1 -1
- ansible/playbook/role/metadata.py +1 -1
- ansible/playbook/role_include.py +1 -1
- ansible/playbook/task.py +2 -2
- ansible/playbook/task_include.py +1 -24
- ansible/plugins/__init__.py +13 -5
- ansible/plugins/action/__init__.py +17 -43
- ansible/plugins/action/add_host.py +2 -3
- ansible/plugins/action/assemble.py +1 -1
- ansible/plugins/action/assert.py +2 -1
- ansible/plugins/action/copy.py +2 -2
- ansible/plugins/action/debug.py +2 -1
- ansible/plugins/action/fail.py +1 -0
- ansible/plugins/action/fetch.py +3 -1
- ansible/plugins/action/gather_facts.py +37 -13
- ansible/plugins/action/group_by.py +1 -0
- ansible/plugins/action/include_vars.py +3 -2
- ansible/plugins/action/normal.py +3 -3
- ansible/plugins/action/pause.py +1 -1
- ansible/plugins/action/reboot.py +21 -16
- ansible/plugins/action/script.py +23 -8
- ansible/plugins/action/set_fact.py +1 -0
- ansible/plugins/action/set_stats.py +1 -0
- ansible/plugins/action/shell.py +6 -0
- ansible/plugins/action/template.py +1 -1
- ansible/plugins/action/unarchive.py +1 -1
- ansible/plugins/action/uri.py +1 -1
- ansible/plugins/action/validate_argument_spec.py +1 -0
- ansible/plugins/action/wait_for_connection.py +4 -4
- ansible/plugins/become/__init__.py +1 -1
- ansible/plugins/become/su.py +1 -1
- ansible/plugins/cache/__init__.py +1 -1
- ansible/plugins/callback/junit.py +1 -1
- ansible/plugins/callback/oneline.py +1 -1
- ansible/plugins/callback/tree.py +1 -1
- ansible/plugins/cliconf/__init__.py +2 -2
- ansible/plugins/connection/__init__.py +65 -37
- ansible/plugins/connection/local.py +9 -8
- ansible/plugins/connection/paramiko_ssh.py +34 -28
- ansible/plugins/connection/psrp.py +56 -43
- ansible/plugins/connection/ssh.py +67 -43
- ansible/plugins/connection/winrm.py +77 -30
- ansible/plugins/doc_fragments/constructed.py +4 -4
- ansible/plugins/doc_fragments/files.py +12 -12
- ansible/plugins/doc_fragments/inventory_cache.py +0 -6
- ansible/plugins/doc_fragments/result_format_callback.py +5 -5
- ansible/plugins/doc_fragments/shell_common.py +2 -2
- ansible/plugins/doc_fragments/shell_windows.py +1 -1
- ansible/plugins/doc_fragments/template_common.py +6 -6
- ansible/plugins/doc_fragments/url.py +10 -10
- ansible/plugins/doc_fragments/url_windows.py +15 -15
- ansible/plugins/doc_fragments/vars_plugin_staging.py +4 -4
- ansible/plugins/filter/b64decode.yml +1 -1
- ansible/plugins/filter/b64encode.yml +2 -2
- ansible/plugins/filter/bool.yml +5 -5
- ansible/plugins/filter/combine.yml +1 -1
- ansible/plugins/filter/commonpath.yml +2 -1
- ansible/plugins/filter/core.py +6 -8
- ansible/plugins/filter/dict2items.yml +11 -1
- ansible/plugins/filter/difference.yml +1 -0
- ansible/plugins/filter/encryption.py +1 -1
- ansible/plugins/filter/extract.yml +1 -1
- ansible/plugins/filter/flatten.yml +1 -1
- ansible/plugins/filter/from_yaml.yml +1 -1
- ansible/plugins/filter/from_yaml_all.yml +2 -2
- ansible/plugins/filter/hash.yml +1 -1
- ansible/plugins/filter/human_readable.yml +1 -1
- ansible/plugins/filter/human_to_bytes.yml +2 -2
- ansible/plugins/filter/intersect.yml +1 -0
- ansible/plugins/filter/mandatory.yml +7 -0
- ansible/plugins/filter/mathstuff.py +15 -17
- ansible/plugins/filter/normpath.yml +1 -1
- ansible/plugins/filter/path_join.yml +8 -1
- ansible/plugins/filter/realpath.yml +3 -2
- ansible/plugins/filter/regex_findall.yml +8 -2
- ansible/plugins/filter/regex_replace.yml +9 -3
- ansible/plugins/filter/regex_search.yml +8 -2
- ansible/plugins/filter/relpath.yml +2 -2
- ansible/plugins/filter/root.yml +1 -1
- ansible/plugins/filter/splitext.yml +1 -1
- ansible/plugins/filter/subelements.yml +2 -2
- ansible/plugins/filter/symmetric_difference.yml +1 -0
- ansible/plugins/filter/ternary.yml +5 -5
- ansible/plugins/filter/to_json.yml +7 -7
- ansible/plugins/filter/to_nice_json.yml +5 -5
- ansible/plugins/filter/to_yaml.yml +2 -2
- ansible/plugins/filter/type_debug.yml +1 -1
- ansible/plugins/filter/union.yml +1 -0
- ansible/plugins/filter/unvault.yml +2 -2
- ansible/plugins/filter/urldecode.yml +13 -32
- ansible/plugins/filter/urlsplit.py +1 -1
- ansible/plugins/filter/vault.yml +1 -1
- ansible/plugins/filter/zip.yml +1 -1
- ansible/plugins/filter/zip_longest.yml +1 -1
- ansible/plugins/inventory/__init__.py +1 -1
- ansible/plugins/inventory/advanced_host_list.py +1 -1
- ansible/plugins/inventory/constructed.py +2 -2
- ansible/plugins/inventory/host_list.py +1 -1
- ansible/plugins/inventory/ini.py +6 -3
- ansible/plugins/inventory/script.py +8 -2
- ansible/plugins/inventory/toml.py +1 -1
- ansible/plugins/inventory/yaml.py +1 -1
- ansible/plugins/list.py +21 -17
- ansible/plugins/loader.py +66 -88
- ansible/plugins/lookup/__init__.py +1 -1
- ansible/plugins/lookup/config.py +16 -6
- ansible/plugins/lookup/csvfile.py +7 -4
- ansible/plugins/lookup/env.py +1 -1
- ansible/plugins/lookup/file.py +5 -2
- ansible/plugins/lookup/fileglob.py +5 -2
- ansible/plugins/lookup/first_found.py +20 -14
- ansible/plugins/lookup/ini.py +6 -3
- ansible/plugins/lookup/lines.py +2 -1
- ansible/plugins/lookup/password.py +7 -7
- ansible/plugins/lookup/pipe.py +1 -0
- ansible/plugins/lookup/random_choice.py +2 -2
- ansible/plugins/lookup/sequence.py +1 -1
- ansible/plugins/lookup/subelements.py +2 -2
- ansible/plugins/lookup/template.py +4 -1
- ansible/plugins/lookup/unvault.py +4 -1
- ansible/plugins/lookup/url.py +6 -6
- ansible/plugins/lookup/varnames.py +1 -1
- ansible/plugins/netconf/__init__.py +3 -3
- ansible/plugins/shell/__init__.py +1 -1
- ansible/plugins/shell/cmd.py +7 -7
- ansible/plugins/shell/powershell.py +1 -1
- ansible/plugins/strategy/__init__.py +8 -10
- ansible/plugins/strategy/free.py +1 -1
- ansible/plugins/strategy/linear.py +3 -3
- ansible/plugins/terminal/__init__.py +2 -2
- ansible/plugins/test/abs.yml +1 -1
- ansible/plugins/test/all.yml +1 -1
- ansible/plugins/test/any.yml +1 -1
- ansible/plugins/test/change.yml +2 -2
- ansible/plugins/test/changed.yml +2 -2
- ansible/plugins/test/contains.yml +1 -1
- ansible/plugins/test/core.py +1 -1
- ansible/plugins/test/directory.yml +1 -1
- ansible/plugins/test/exists.yml +3 -2
- ansible/plugins/test/failed.yml +2 -2
- ansible/plugins/test/failure.yml +2 -2
- ansible/plugins/test/falsy.yml +2 -2
- ansible/plugins/test/file.yml +1 -1
- ansible/plugins/test/finished.yml +2 -2
- ansible/plugins/test/is_abs.yml +1 -1
- ansible/plugins/test/is_dir.yml +1 -1
- ansible/plugins/test/is_file.yml +1 -1
- ansible/plugins/test/is_link.yml +1 -1
- ansible/plugins/test/is_mount.yml +1 -1
- ansible/plugins/test/is_same_file.yml +1 -1
- ansible/plugins/test/isnan.yml +1 -1
- ansible/plugins/test/issubset.yml +1 -2
- ansible/plugins/test/issuperset.yml +1 -2
- ansible/plugins/test/link.yml +1 -1
- ansible/plugins/test/link_exists.yml +1 -1
- ansible/plugins/test/match.yml +2 -2
- ansible/plugins/test/mount.yml +1 -1
- ansible/plugins/test/nan.yml +1 -1
- ansible/plugins/test/reachable.yml +2 -2
- ansible/plugins/test/regex.yml +1 -1
- ansible/plugins/test/same_file.yml +1 -1
- ansible/plugins/test/search.yml +2 -2
- ansible/plugins/test/skip.yml +3 -3
- ansible/plugins/test/skipped.yml +3 -3
- ansible/plugins/test/started.yml +2 -2
- ansible/plugins/test/subset.yml +1 -2
- ansible/plugins/test/succeeded.yml +2 -2
- ansible/plugins/test/success.yml +2 -2
- ansible/plugins/test/successful.yml +2 -2
- ansible/plugins/test/superset.yml +1 -2
- ansible/plugins/test/truthy.yml +3 -3
- ansible/plugins/test/unreachable.yml +2 -2
- ansible/plugins/test/uri.yml +1 -1
- ansible/plugins/test/url.yml +1 -1
- ansible/plugins/test/urn.yml +1 -1
- ansible/plugins/test/vault_encrypted.yml +1 -1
- ansible/plugins/test/version.yml +7 -7
- ansible/plugins/test/version_compare.yml +7 -7
- ansible/plugins/vars/host_group_vars.py +1 -1
- ansible/release.py +2 -2
- ansible/template/__init__.py +24 -26
- ansible/template/native_helpers.py +1 -1
- ansible/template/vars.py +1 -1
- ansible/utils/_junit_xml.py +1 -1
- ansible/utils/cmd_functions.py +1 -1
- ansible/utils/collection_loader/_collection_finder.py +12 -1
- ansible/utils/display.py +113 -62
- ansible/utils/encrypt.py +11 -14
- ansible/utils/hashing.py +1 -1
- ansible/utils/jsonrpc.py +1 -1
- ansible/utils/path.py +1 -1
- ansible/utils/plugin_docs.py +1 -1
- ansible/utils/py3compat.py +1 -1
- ansible/utils/shlex.py +2 -10
- ansible/utils/ssh_functions.py +5 -4
- ansible/utils/unicode.py +1 -1
- ansible/utils/unsafe_proxy.py +1 -1
- ansible/utils/vars.py +4 -29
- ansible/vars/hostvars.py +1 -2
- ansible/vars/manager.py +13 -9
- ansible/vars/plugins.py +2 -2
- {ansible_core-2.15.4rc1.dist-info → ansible_core-2.16.0b2.dist-info}/COPYING +4 -5
- {ansible_core-2.15.4rc1.dist-info → ansible_core-2.16.0b2.dist-info}/METADATA +2 -4
- {ansible_core-2.15.4rc1.dist-info → ansible_core-2.16.0b2.dist-info}/RECORD +424 -425
- ansible_test/_data/completion/docker.txt +9 -9
- ansible_test/_data/completion/remote.txt +4 -7
- ansible_test/_data/completion/windows.txt +0 -2
- ansible_test/_data/requirements/ansible-test.txt +2 -1
- ansible_test/_data/requirements/ansible.txt +0 -3
- ansible_test/_data/requirements/constraints.txt +0 -2
- ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -5
- ansible_test/_data/requirements/sanity.changelog.in +1 -2
- ansible_test/_data/requirements/sanity.changelog.txt +4 -6
- ansible_test/_data/requirements/sanity.import.plugin.txt +2 -4
- ansible_test/_data/requirements/sanity.import.txt +1 -3
- ansible_test/_data/requirements/sanity.integration-aliases.txt +1 -3
- ansible_test/_data/requirements/sanity.mypy.txt +12 -12
- ansible_test/_data/requirements/sanity.pep8.txt +1 -1
- ansible_test/_data/requirements/sanity.pylint.txt +6 -12
- ansible_test/_data/requirements/sanity.runtime-metadata.txt +1 -3
- ansible_test/_data/requirements/sanity.validate-modules.in +1 -1
- ansible_test/_data/requirements/sanity.validate-modules.txt +3 -5
- ansible_test/_data/requirements/sanity.yamllint.txt +3 -5
- ansible_test/_data/requirements/units.txt +0 -1
- ansible_test/_internal/ci/azp.py +4 -4
- ansible_test/_internal/cli/environments.py +0 -13
- ansible_test/_internal/commands/coverage/analyze/targets/__init__.py +4 -4
- ansible_test/_internal/commands/coverage/combine.py +1 -1
- ansible_test/_internal/commands/integration/cloud/acme.py +6 -8
- ansible_test/_internal/commands/integration/cloud/cs.py +4 -9
- ansible_test/_internal/commands/integration/cloud/galaxy.py +103 -96
- ansible_test/_internal/commands/integration/cloud/httptester.py +0 -3
- ansible_test/_internal/commands/integration/cloud/nios.py +7 -9
- ansible_test/_internal/commands/integration/cloud/openshift.py +2 -7
- ansible_test/_internal/commands/integration/cloud/vcenter.py +11 -95
- ansible_test/_internal/commands/sanity/__init__.py +10 -0
- ansible_test/_internal/commands/sanity/import.py +8 -2
- ansible_test/_internal/commands/sanity/pylint.py +27 -1
- ansible_test/_internal/commands/units/__init__.py +2 -1
- ansible_test/_internal/config.py +0 -7
- ansible_test/_internal/containers.py +11 -56
- ansible_test/_internal/core_ci.py +0 -7
- ansible_test/_internal/coverage_util.py +8 -3
- ansible_test/_internal/delegation.py +0 -1
- ansible_test/_internal/diff.py +1 -1
- ansible_test/_internal/docker_util.py +9 -2
- ansible_test/_internal/host_profiles.py +6 -6
- ansible_test/_internal/http.py +1 -1
- ansible_test/_internal/junit_xml.py +1 -1
- ansible_test/_internal/pypi_proxy.py +1 -1
- ansible_test/_internal/python_requirements.py +3 -8
- ansible_test/_internal/util.py +1 -6
- ansible_test/_util/controller/sanity/code-smell/no-get-exception.json +4 -0
- ansible_test/_util/controller/sanity/code-smell/replace-urlopen.json +4 -0
- ansible_test/_util/controller/sanity/code-smell/use-compat-six.json +4 -0
- ansible_test/_util/controller/sanity/mypy/ansible-core.ini +3 -0
- ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +2 -0
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +0 -1
- ansible_test/_util/controller/sanity/pylint/config/collection.cfg +1 -0
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +172 -10
- ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +13 -2
- ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +7 -1
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +6 -6
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +1 -1
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -1
- ansible_test/_util/controller/sanity/yamllint/yamllinter.py +3 -3
- ansible_test/_util/controller/tools/collection_detail.py +2 -2
- ansible_test/_util/target/common/constants.py +2 -2
- ansible_test/_util/target/pytest/plugins/ansible_forked.py +103 -0
- ansible_test/_util/target/sanity/import/importer.py +0 -8
- ansible_test/_util/target/setup/bootstrap.sh +36 -16
- ansible_test/_util/target/setup/quiet_pip.py +0 -4
- ansible/modules/_include.py +0 -80
- ansible_test/_internal/commands/integration/cloud/foreman.py +0 -102
- ansible_test/_util/target/setup/ConfigureRemotingForAnsible.ps1 +0 -435
- {ansible_core-2.15.4rc1.data → ansible_core-2.16.0b2.data}/scripts/ansible-test +0 -0
- {ansible_core-2.15.4rc1.dist-info → ansible_core-2.16.0b2.dist-info}/WHEEL +0 -0
- {ansible_core-2.15.4rc1.dist-info → ansible_core-2.16.0b2.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.15.4rc1.dist-info → ansible_core-2.16.0b2.dist-info}/top_level.txt +0 -0
|
@@ -28,6 +28,8 @@ DOCUMENTATION = '''
|
|
|
28
28
|
notes:
|
|
29
29
|
- Enabled in configuration by default.
|
|
30
30
|
- The plugin does not cache results because external inventory scripts are responsible for their own caching.
|
|
31
|
+
- To write your own inventory script see (R(Developing dynamic inventory,developing_inventory) from the documentation site.
|
|
32
|
+
- To find the scripts that used to be part of the code release, go to U(https://github.com/ansible-community/contrib-scripts/).
|
|
31
33
|
'''
|
|
32
34
|
|
|
33
35
|
import os
|
|
@@ -37,7 +39,7 @@ from collections.abc import Mapping
|
|
|
37
39
|
|
|
38
40
|
from ansible.errors import AnsibleError, AnsibleParserError
|
|
39
41
|
from ansible.module_utils.basic import json_dict_bytes_to_unicode
|
|
40
|
-
from ansible.module_utils.
|
|
42
|
+
from ansible.module_utils.common.text.converters import to_native, to_text
|
|
41
43
|
from ansible.plugins.inventory import BaseInventoryPlugin
|
|
42
44
|
from ansible.utils.display import Display
|
|
43
45
|
|
|
@@ -187,7 +189,11 @@ class InventoryModule(BaseInventoryPlugin):
|
|
|
187
189
|
sp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
188
190
|
except OSError as e:
|
|
189
191
|
raise AnsibleError("problem running %s (%s)" % (' '.join(cmd), e))
|
|
190
|
-
(out,
|
|
192
|
+
(out, stderr) = sp.communicate()
|
|
193
|
+
|
|
194
|
+
if sp.returncode != 0:
|
|
195
|
+
raise AnsibleError("Inventory script (%s) had an execution error: %s" % (path, to_native(stderr)))
|
|
196
|
+
|
|
191
197
|
if out.strip() == '':
|
|
192
198
|
return {}
|
|
193
199
|
try:
|
|
@@ -94,7 +94,7 @@ from collections.abc import MutableMapping, MutableSequence
|
|
|
94
94
|
from functools import partial
|
|
95
95
|
|
|
96
96
|
from ansible.errors import AnsibleFileNotFound, AnsibleParserError, AnsibleRuntimeError
|
|
97
|
-
from ansible.module_utils.
|
|
97
|
+
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
|
|
98
98
|
from ansible.module_utils.six import string_types, text_type
|
|
99
99
|
from ansible.parsing.yaml.objects import AnsibleSequence, AnsibleUnicode
|
|
100
100
|
from ansible.plugins.inventory import BaseFileInventoryPlugin
|
|
@@ -72,7 +72,7 @@ from collections.abc import MutableMapping
|
|
|
72
72
|
|
|
73
73
|
from ansible.errors import AnsibleError, AnsibleParserError
|
|
74
74
|
from ansible.module_utils.six import string_types
|
|
75
|
-
from ansible.module_utils.
|
|
75
|
+
from ansible.module_utils.common.text.converters import to_native, to_text
|
|
76
76
|
from ansible.plugins.inventory import BaseFileInventoryPlugin
|
|
77
77
|
|
|
78
78
|
NoneType = type(None)
|
ansible/plugins/list.py
CHANGED
|
@@ -11,7 +11,7 @@ from ansible import context
|
|
|
11
11
|
from ansible import constants as C
|
|
12
12
|
from ansible.collections.list import list_collections
|
|
13
13
|
from ansible.errors import AnsibleError
|
|
14
|
-
from ansible.module_utils.
|
|
14
|
+
from ansible.module_utils.common.text.converters import to_native, to_bytes
|
|
15
15
|
from ansible.plugins import loader
|
|
16
16
|
from ansible.utils.display import Display
|
|
17
17
|
from ansible.utils.collection_loader._collection_finder import _get_collection_path
|
|
@@ -171,28 +171,32 @@ def list_collection_plugins(ptype, collections, search_paths=None):
|
|
|
171
171
|
return plugins
|
|
172
172
|
|
|
173
173
|
|
|
174
|
-
def list_plugins(ptype,
|
|
174
|
+
def list_plugins(ptype, collections=None, search_paths=None):
|
|
175
|
+
if isinstance(collections, str):
|
|
176
|
+
collections = [collections]
|
|
175
177
|
|
|
176
178
|
# {plugin_name: (filepath, class), ...}
|
|
177
179
|
plugins = {}
|
|
178
|
-
|
|
179
|
-
if
|
|
180
|
+
plugin_collections = {}
|
|
181
|
+
if collections is None:
|
|
180
182
|
# list all collections, add synthetic ones
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
elif collection == 'ansible.legacy':
|
|
185
|
-
# add builtin, since legacy also resolves to these
|
|
186
|
-
collections[collection] = b''
|
|
187
|
-
collections['ansible.builtin'] = b''
|
|
183
|
+
plugin_collections['ansible.builtin'] = b''
|
|
184
|
+
plugin_collections['ansible.legacy'] = b''
|
|
185
|
+
plugin_collections.update(list_collections(search_paths=search_paths, dedupe=True))
|
|
188
186
|
else:
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
187
|
+
for collection in collections:
|
|
188
|
+
if collection == 'ansible.legacy':
|
|
189
|
+
# add builtin, since legacy also resolves to these
|
|
190
|
+
plugin_collections[collection] = b''
|
|
191
|
+
plugin_collections['ansible.builtin'] = b''
|
|
192
|
+
else:
|
|
193
|
+
try:
|
|
194
|
+
plugin_collections[collection] = to_bytes(_get_collection_path(collection))
|
|
195
|
+
except ValueError as e:
|
|
196
|
+
raise AnsibleError("Cannot use supplied collection {0}: {1}".format(collection, to_native(e)), orig_exc=e)
|
|
193
197
|
|
|
194
|
-
if
|
|
195
|
-
plugins.update(list_collection_plugins(ptype,
|
|
198
|
+
if plugin_collections:
|
|
199
|
+
plugins.update(list_collection_plugins(ptype, plugin_collections))
|
|
196
200
|
|
|
197
201
|
return plugins
|
|
198
202
|
|
ansible/plugins/loader.py
CHANGED
|
@@ -18,10 +18,14 @@ from collections import defaultdict, namedtuple
|
|
|
18
18
|
from traceback import format_exc
|
|
19
19
|
|
|
20
20
|
import ansible.module_utils.compat.typing as t
|
|
21
|
+
|
|
22
|
+
from .filter import AnsibleJinja2Filter
|
|
23
|
+
from .test import AnsibleJinja2Test
|
|
24
|
+
|
|
21
25
|
from ansible import __version__ as ansible_version
|
|
22
26
|
from ansible import constants as C
|
|
23
27
|
from ansible.errors import AnsibleError, AnsiblePluginCircularRedirect, AnsiblePluginRemovedError, AnsibleCollectionUnsupportedVersionError
|
|
24
|
-
from ansible.module_utils.
|
|
28
|
+
from ansible.module_utils.common.text.converters import to_bytes, to_text, to_native
|
|
25
29
|
from ansible.module_utils.compat.importlib import import_module
|
|
26
30
|
from ansible.module_utils.six import string_types
|
|
27
31
|
from ansible.parsing.utils.yaml import from_yaml
|
|
@@ -1067,28 +1071,17 @@ class Jinja2Loader(PluginLoader):
|
|
|
1067
1071
|
We need to do a few things differently in the base class because of file == plugin
|
|
1068
1072
|
assumptions and dedupe logic.
|
|
1069
1073
|
"""
|
|
1070
|
-
def __init__(self, class_name, package, config, subdir, aliases=None, required_base_class=None):
|
|
1071
|
-
|
|
1074
|
+
def __init__(self, class_name, package, config, subdir, plugin_wrapper_type, aliases=None, required_base_class=None):
|
|
1072
1075
|
super(Jinja2Loader, self).__init__(class_name, package, config, subdir, aliases=aliases, required_base_class=required_base_class)
|
|
1073
|
-
self.
|
|
1076
|
+
self._plugin_wrapper_type = plugin_wrapper_type
|
|
1077
|
+
self._cached_non_collection_wrappers = {}
|
|
1074
1078
|
|
|
1075
1079
|
def _clear_caches(self):
|
|
1076
1080
|
super(Jinja2Loader, self)._clear_caches()
|
|
1077
|
-
self.
|
|
1081
|
+
self._cached_non_collection_wrappers = {}
|
|
1078
1082
|
|
|
1079
1083
|
def find_plugin(self, name, mod_type='', ignore_deprecated=False, check_aliases=False, collection_list=None):
|
|
1080
|
-
|
|
1081
|
-
# TODO: handle collection plugin find, see 'get_with_context'
|
|
1082
|
-
# this can really 'find plugin file'
|
|
1083
|
-
plugin = super(Jinja2Loader, self).find_plugin(name, mod_type=mod_type, ignore_deprecated=ignore_deprecated, check_aliases=check_aliases,
|
|
1084
|
-
collection_list=collection_list)
|
|
1085
|
-
|
|
1086
|
-
# if not found, try loading all non collection plugins and see if this in there
|
|
1087
|
-
if not plugin:
|
|
1088
|
-
all_plugins = self.all()
|
|
1089
|
-
plugin = all_plugins.get(name, None)
|
|
1090
|
-
|
|
1091
|
-
return plugin
|
|
1084
|
+
raise NotImplementedError('find_plugin is not supported on Jinja2Loader')
|
|
1092
1085
|
|
|
1093
1086
|
@property
|
|
1094
1087
|
def method_map_name(self):
|
|
@@ -1122,8 +1115,7 @@ class Jinja2Loader(PluginLoader):
|
|
|
1122
1115
|
for func_name, func in plugin_map:
|
|
1123
1116
|
fq_name = '.'.join((collection, func_name))
|
|
1124
1117
|
full = '.'.join((full_name, func_name))
|
|
1125
|
-
|
|
1126
|
-
plugin = pclass(func)
|
|
1118
|
+
plugin = self._plugin_wrapper_type(func)
|
|
1127
1119
|
if plugin in plugins:
|
|
1128
1120
|
continue
|
|
1129
1121
|
self._update_object(plugin, full, plugin_path, resolved=fq_name)
|
|
@@ -1131,27 +1123,28 @@ class Jinja2Loader(PluginLoader):
|
|
|
1131
1123
|
|
|
1132
1124
|
return plugins
|
|
1133
1125
|
|
|
1126
|
+
# FUTURE: now that the resulting plugins are closer, refactor base class method with some extra
|
|
1127
|
+
# hooks so we can avoid all the duplicated plugin metadata logic, and also cache the collection results properly here
|
|
1134
1128
|
def get_with_context(self, name, *args, **kwargs):
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
collection_list = kwargs.pop('collection_list', None)
|
|
1129
|
+
# pop N/A kwargs to avoid passthrough to parent methods
|
|
1130
|
+
kwargs.pop('class_only', False)
|
|
1131
|
+
kwargs.pop('collection_list', None)
|
|
1139
1132
|
|
|
1140
1133
|
context = PluginLoadContext()
|
|
1141
1134
|
|
|
1142
1135
|
# avoid collection path for legacy
|
|
1143
1136
|
name = name.removeprefix('ansible.legacy.')
|
|
1144
1137
|
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1138
|
+
self._ensure_non_collection_wrappers(*args, **kwargs)
|
|
1139
|
+
|
|
1140
|
+
# check for stuff loaded via legacy/builtin paths first
|
|
1141
|
+
if known_plugin := self._cached_non_collection_wrappers.get(name):
|
|
1142
|
+
context.resolved = True
|
|
1143
|
+
context.plugin_resolved_name = name
|
|
1144
|
+
context.plugin_resolved_path = known_plugin._original_path
|
|
1145
|
+
context.plugin_resolved_collection = 'ansible.builtin' if known_plugin.ansible_name.startswith('ansible.builtin.') else ''
|
|
1146
|
+
context._resolved_fqcn = known_plugin.ansible_name
|
|
1147
|
+
return get_with_context_result(known_plugin, context)
|
|
1155
1148
|
|
|
1156
1149
|
plugin = None
|
|
1157
1150
|
key, leaf_key = get_fqcr_and_name(name)
|
|
@@ -1237,14 +1230,10 @@ class Jinja2Loader(PluginLoader):
|
|
|
1237
1230
|
# use 'parent' loader class to find files, but cannot return this as it can contain
|
|
1238
1231
|
# multiple plugins per file
|
|
1239
1232
|
plugin_impl = super(Jinja2Loader, self).get_with_context(module_name, *args, **kwargs)
|
|
1240
|
-
except Exception as e:
|
|
1241
|
-
raise KeyError(to_native(e))
|
|
1242
|
-
|
|
1243
|
-
try:
|
|
1244
1233
|
method_map = getattr(plugin_impl.object, self.method_map_name)
|
|
1245
1234
|
plugin_map = method_map().items()
|
|
1246
1235
|
except Exception as e:
|
|
1247
|
-
display.warning("Skipping
|
|
1236
|
+
display.warning(f"Skipping {self.type} plugins in {module_name}'; an error occurred while loading: {e}")
|
|
1248
1237
|
continue
|
|
1249
1238
|
|
|
1250
1239
|
for func_name, func in plugin_map:
|
|
@@ -1253,11 +1242,11 @@ class Jinja2Loader(PluginLoader):
|
|
|
1253
1242
|
# TODO: load anyways into CACHE so we only match each at end of loop
|
|
1254
1243
|
# the files themseves should already be cached by base class caching of modules(python)
|
|
1255
1244
|
if key in (func_name, fq_name):
|
|
1256
|
-
|
|
1257
|
-
plugin = pclass(func)
|
|
1245
|
+
plugin = self._plugin_wrapper_type(func)
|
|
1258
1246
|
if plugin:
|
|
1259
1247
|
context = plugin_impl.plugin_load_context
|
|
1260
1248
|
self._update_object(plugin, src_name, plugin_impl.object._original_path, resolved=fq_name)
|
|
1249
|
+
# FIXME: once we start caching these results, we'll be missing functions that would have loaded later
|
|
1261
1250
|
break # go to next file as it can override if dupe (dont break both loops)
|
|
1262
1251
|
|
|
1263
1252
|
except AnsiblePluginRemovedError as apre:
|
|
@@ -1272,8 +1261,7 @@ class Jinja2Loader(PluginLoader):
|
|
|
1272
1261
|
return get_with_context_result(plugin, context)
|
|
1273
1262
|
|
|
1274
1263
|
def all(self, *args, **kwargs):
|
|
1275
|
-
|
|
1276
|
-
# inputs, we ignore 'dedupe' we always do, used in base class to find files for this one
|
|
1264
|
+
kwargs.pop('_dedupe', None)
|
|
1277
1265
|
path_only = kwargs.pop('path_only', False)
|
|
1278
1266
|
class_only = kwargs.pop('class_only', False) # basically ignored for test/filters since they are functions
|
|
1279
1267
|
|
|
@@ -1281,9 +1269,19 @@ class Jinja2Loader(PluginLoader):
|
|
|
1281
1269
|
if path_only and class_only:
|
|
1282
1270
|
raise AnsibleError('Do not set both path_only and class_only when calling PluginLoader.all()')
|
|
1283
1271
|
|
|
1284
|
-
|
|
1272
|
+
self._ensure_non_collection_wrappers(*args, **kwargs)
|
|
1273
|
+
if path_only:
|
|
1274
|
+
yield from (w._original_path for w in self._cached_non_collection_wrappers.values())
|
|
1275
|
+
else:
|
|
1276
|
+
yield from (w for w in self._cached_non_collection_wrappers.values())
|
|
1277
|
+
|
|
1278
|
+
def _ensure_non_collection_wrappers(self, *args, **kwargs):
|
|
1279
|
+
if self._cached_non_collection_wrappers:
|
|
1280
|
+
return
|
|
1281
|
+
|
|
1285
1282
|
# get plugins from files in configured paths (multiple in each)
|
|
1286
|
-
for p_map in self.
|
|
1283
|
+
for p_map in super(Jinja2Loader, self).all(*args, **kwargs):
|
|
1284
|
+
is_builtin = p_map.ansible_name.startswith('ansible.builtin.')
|
|
1287
1285
|
|
|
1288
1286
|
# p_map is really object from file with class that holds multiple plugins
|
|
1289
1287
|
plugins_list = getattr(p_map, self.method_map_name)
|
|
@@ -1294,57 +1292,35 @@ class Jinja2Loader(PluginLoader):
|
|
|
1294
1292
|
continue
|
|
1295
1293
|
|
|
1296
1294
|
for plugin_name in plugins.keys():
|
|
1297
|
-
if
|
|
1298
|
-
display.debug(
|
|
1295
|
+
if '.' in plugin_name:
|
|
1296
|
+
display.debug(f'{plugin_name} skipped in {p_map._original_path}; Jinja plugin short names may not contain "."')
|
|
1299
1297
|
continue
|
|
1300
1298
|
|
|
1301
|
-
if plugin_name in
|
|
1302
|
-
display.debug("%s skipped
|
|
1299
|
+
if plugin_name in _PLUGIN_FILTERS[self.package]:
|
|
1300
|
+
display.debug("%s skipped due to a defined plugin filter" % plugin_name)
|
|
1303
1301
|
continue
|
|
1304
1302
|
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
fqcn = plugin_name
|
|
1313
|
-
collection = '.'.join(p_map.ansible_name.split('.')[:2]) if p_map.ansible_name.count('.') >= 2 else ''
|
|
1314
|
-
if not plugin_name.startswith(collection):
|
|
1315
|
-
fqcn = f"{collection}.{plugin_name}"
|
|
1316
|
-
|
|
1317
|
-
self._update_object(result, plugin_name, p_map._original_path, resolved=fqcn)
|
|
1318
|
-
yield result
|
|
1319
|
-
|
|
1320
|
-
def _load_jinja2_class(self):
|
|
1321
|
-
""" override the normal method of plugin classname as these are used in the generic funciton
|
|
1322
|
-
to access the 'multimap' of filter/tests to function, this is a 'singular' plugin for
|
|
1323
|
-
each entry.
|
|
1324
|
-
"""
|
|
1325
|
-
class_name = 'AnsibleJinja2%s' % get_plugin_class(self.class_name).capitalize()
|
|
1326
|
-
module = __import__(self.package, fromlist=[class_name])
|
|
1327
|
-
|
|
1328
|
-
return getattr(module, class_name)
|
|
1303
|
+
# the plugin class returned by the loader may host multiple Jinja plugins, but we wrap each plugin in
|
|
1304
|
+
# its own surrogate wrapper instance here to ease the bookkeeping...
|
|
1305
|
+
wrapper = self._plugin_wrapper_type(plugins[plugin_name])
|
|
1306
|
+
fqcn = plugin_name
|
|
1307
|
+
collection = '.'.join(p_map.ansible_name.split('.')[:2]) if p_map.ansible_name.count('.') >= 2 else ''
|
|
1308
|
+
if not plugin_name.startswith(collection):
|
|
1309
|
+
fqcn = f"{collection}.{plugin_name}"
|
|
1329
1310
|
|
|
1330
|
-
|
|
1331
|
-
"""
|
|
1332
|
-
* Unlike other plugin types, file != plugin, a file can contain multiple plugins (of same type).
|
|
1333
|
-
This is why we do not deduplicate ansible file names at this point, we mostly care about
|
|
1334
|
-
the names of the actual jinja2 plugins which are inside of our files.
|
|
1335
|
-
* This method will NOT fetch collection plugin files, only those that would be expected under 'ansible.builtin/legacy'.
|
|
1336
|
-
"""
|
|
1337
|
-
# populate cache if needed
|
|
1338
|
-
if not self._loaded_j2_file_maps:
|
|
1311
|
+
self._update_object(wrapper, plugin_name, p_map._original_path, resolved=fqcn)
|
|
1339
1312
|
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1313
|
+
target_names = {plugin_name, fqcn}
|
|
1314
|
+
if is_builtin:
|
|
1315
|
+
target_names.add(f'ansible.builtin.{plugin_name}')
|
|
1343
1316
|
|
|
1344
|
-
|
|
1345
|
-
|
|
1317
|
+
for target_name in target_names:
|
|
1318
|
+
if existing_plugin := self._cached_non_collection_wrappers.get(target_name):
|
|
1319
|
+
display.debug(f'Jinja plugin {target_name} from {p_map._original_path} skipped; '
|
|
1320
|
+
f'shadowed by plugin from {existing_plugin._original_path})')
|
|
1321
|
+
continue
|
|
1346
1322
|
|
|
1347
|
-
|
|
1323
|
+
self._cached_non_collection_wrappers[target_name] = wrapper
|
|
1348
1324
|
|
|
1349
1325
|
|
|
1350
1326
|
def get_fqcr_and_name(resource, collection='ansible.builtin'):
|
|
@@ -1572,13 +1548,15 @@ filter_loader = Jinja2Loader(
|
|
|
1572
1548
|
'ansible.plugins.filter',
|
|
1573
1549
|
C.DEFAULT_FILTER_PLUGIN_PATH,
|
|
1574
1550
|
'filter_plugins',
|
|
1551
|
+
AnsibleJinja2Filter
|
|
1575
1552
|
)
|
|
1576
1553
|
|
|
1577
1554
|
test_loader = Jinja2Loader(
|
|
1578
1555
|
'TestModule',
|
|
1579
1556
|
'ansible.plugins.test',
|
|
1580
1557
|
C.DEFAULT_TEST_PLUGIN_PATH,
|
|
1581
|
-
'test_plugins'
|
|
1558
|
+
'test_plugins',
|
|
1559
|
+
AnsibleJinja2Test
|
|
1582
1560
|
)
|
|
1583
1561
|
|
|
1584
1562
|
strategy_loader = PluginLoader(
|
|
@@ -100,7 +100,7 @@ class LookupBase(AnsiblePlugin):
|
|
|
100
100
|
must be converted into python's unicode type as the strings will be run
|
|
101
101
|
through jinja2 which has this requirement. You can use::
|
|
102
102
|
|
|
103
|
-
from ansible.module_utils.
|
|
103
|
+
from ansible.module_utils.common.text.converters import to_text
|
|
104
104
|
result_string = to_text(result_string)
|
|
105
105
|
"""
|
|
106
106
|
pass
|
ansible/plugins/lookup/config.py
CHANGED
|
@@ -33,6 +33,10 @@ DOCUMENTATION = """
|
|
|
33
33
|
description: name of the plugin for which you want to retrieve configuration settings.
|
|
34
34
|
type: string
|
|
35
35
|
version_added: '2.12'
|
|
36
|
+
show_origin:
|
|
37
|
+
description: toggle the display of what configuration subsystem the value came from
|
|
38
|
+
type: bool
|
|
39
|
+
version_added: '2.16'
|
|
36
40
|
"""
|
|
37
41
|
|
|
38
42
|
EXAMPLES = """
|
|
@@ -67,7 +71,8 @@ EXAMPLES = """
|
|
|
67
71
|
RETURN = """
|
|
68
72
|
_raw:
|
|
69
73
|
description:
|
|
70
|
-
- value(s) of the key(s) in the config
|
|
74
|
+
- A list of value(s) of the key(s) in the config if show_origin is false (default)
|
|
75
|
+
- Optionally, a list of 2 element lists (value, origin) if show_origin is true
|
|
71
76
|
type: raw
|
|
72
77
|
"""
|
|
73
78
|
|
|
@@ -75,7 +80,7 @@ import ansible.plugins.loader as plugin_loader
|
|
|
75
80
|
|
|
76
81
|
from ansible import constants as C
|
|
77
82
|
from ansible.errors import AnsibleError, AnsibleLookupError, AnsibleOptionsError
|
|
78
|
-
from ansible.module_utils.
|
|
83
|
+
from ansible.module_utils.common.text.converters import to_native
|
|
79
84
|
from ansible.module_utils.six import string_types
|
|
80
85
|
from ansible.plugins.lookup import LookupBase
|
|
81
86
|
from ansible.utils.sentinel import Sentinel
|
|
@@ -92,7 +97,7 @@ def _get_plugin_config(pname, ptype, config, variables):
|
|
|
92
97
|
p = loader.get(pname, class_only=True)
|
|
93
98
|
if p is None:
|
|
94
99
|
raise AnsibleLookupError('Unable to load %s plugin "%s"' % (ptype, pname))
|
|
95
|
-
result = C.config.
|
|
100
|
+
result, origin = C.config.get_config_value_and_origin(config, plugin_type=ptype, plugin_name=p._load_name, variables=variables)
|
|
96
101
|
except AnsibleLookupError:
|
|
97
102
|
raise
|
|
98
103
|
except AnsibleError as e:
|
|
@@ -101,7 +106,7 @@ def _get_plugin_config(pname, ptype, config, variables):
|
|
|
101
106
|
raise MissingSetting(msg, orig_exc=e)
|
|
102
107
|
raise e
|
|
103
108
|
|
|
104
|
-
return result
|
|
109
|
+
return result, origin
|
|
105
110
|
|
|
106
111
|
|
|
107
112
|
def _get_global_config(config):
|
|
@@ -124,6 +129,7 @@ class LookupModule(LookupBase):
|
|
|
124
129
|
missing = self.get_option('on_missing')
|
|
125
130
|
ptype = self.get_option('plugin_type')
|
|
126
131
|
pname = self.get_option('plugin_name')
|
|
132
|
+
show_origin = self.get_option('show_origin')
|
|
127
133
|
|
|
128
134
|
if (ptype or pname) and not (ptype and pname):
|
|
129
135
|
raise AnsibleOptionsError('Both plugin_type and plugin_name are required, cannot use one without the other')
|
|
@@ -138,9 +144,10 @@ class LookupModule(LookupBase):
|
|
|
138
144
|
raise AnsibleOptionsError('Invalid setting identifier, "%s" is not a string, its a %s' % (term, type(term)))
|
|
139
145
|
|
|
140
146
|
result = Sentinel
|
|
147
|
+
origin = None
|
|
141
148
|
try:
|
|
142
149
|
if pname:
|
|
143
|
-
result = _get_plugin_config(pname, ptype, term, variables)
|
|
150
|
+
result, origin = _get_plugin_config(pname, ptype, term, variables)
|
|
144
151
|
else:
|
|
145
152
|
result = _get_global_config(term)
|
|
146
153
|
except MissingSetting as e:
|
|
@@ -152,5 +159,8 @@ class LookupModule(LookupBase):
|
|
|
152
159
|
pass # this is not needed, but added to have all 3 options stated
|
|
153
160
|
|
|
154
161
|
if result is not Sentinel:
|
|
155
|
-
|
|
162
|
+
if show_origin:
|
|
163
|
+
ret.append((result, origin))
|
|
164
|
+
else:
|
|
165
|
+
ret.append(result)
|
|
156
166
|
return ret
|
|
@@ -12,7 +12,7 @@ DOCUMENTATION = r"""
|
|
|
12
12
|
description:
|
|
13
13
|
- The csvfile lookup reads the contents of a file in CSV (comma-separated value) format.
|
|
14
14
|
The lookup looks for the row where the first column matches keyname (which can be multiple words)
|
|
15
|
-
and returns the value in the
|
|
15
|
+
and returns the value in the O(col) column (default 1, which indexed from 0 means the second column in the file).
|
|
16
16
|
options:
|
|
17
17
|
col:
|
|
18
18
|
description: column to return (0 indexed).
|
|
@@ -20,7 +20,7 @@ DOCUMENTATION = r"""
|
|
|
20
20
|
default:
|
|
21
21
|
description: what to return if the value is not found in the file.
|
|
22
22
|
delimiter:
|
|
23
|
-
description: field separator in the file, for a tab you can specify
|
|
23
|
+
description: field separator in the file, for a tab you can specify V(TAB) or V(\\t).
|
|
24
24
|
default: TAB
|
|
25
25
|
file:
|
|
26
26
|
description: name of the CSV/TSV file to open.
|
|
@@ -35,6 +35,9 @@ DOCUMENTATION = r"""
|
|
|
35
35
|
- For historical reasons, in the search keyname, quotes are treated
|
|
36
36
|
literally and cannot be used around the string unless they appear
|
|
37
37
|
(escaped as required) in the first column of the file you are parsing.
|
|
38
|
+
seealso:
|
|
39
|
+
- ref: playbook_task_paths
|
|
40
|
+
description: Search paths used for relative files.
|
|
38
41
|
"""
|
|
39
42
|
|
|
40
43
|
EXAMPLES = """
|
|
@@ -54,7 +57,7 @@ EXAMPLES = """
|
|
|
54
57
|
neighbor_as: "{{ csvline[5] }}"
|
|
55
58
|
neigh_int_ip: "{{ csvline[6] }}"
|
|
56
59
|
vars:
|
|
57
|
-
csvline
|
|
60
|
+
csvline: "{{ lookup('ansible.builtin.csvfile', bgp_neighbor_ip, file='bgp_neighbors.csv', delimiter=',') }}"
|
|
58
61
|
delegate_to: localhost
|
|
59
62
|
"""
|
|
60
63
|
|
|
@@ -75,7 +78,7 @@ from ansible.errors import AnsibleError, AnsibleAssertionError
|
|
|
75
78
|
from ansible.parsing.splitter import parse_kv
|
|
76
79
|
from ansible.plugins.lookup import LookupBase
|
|
77
80
|
from ansible.module_utils.six import PY2
|
|
78
|
-
from ansible.module_utils.
|
|
81
|
+
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
|
|
79
82
|
|
|
80
83
|
|
|
81
84
|
class CSVRecoder:
|
ansible/plugins/lookup/env.py
CHANGED
|
@@ -23,7 +23,7 @@ DOCUMENTATION = """
|
|
|
23
23
|
default: ''
|
|
24
24
|
version_added: '2.13'
|
|
25
25
|
notes:
|
|
26
|
-
- You can pass the C(Undefined) object as
|
|
26
|
+
- You can pass the C(Undefined) object as O(default) to force an undefined error
|
|
27
27
|
"""
|
|
28
28
|
|
|
29
29
|
EXAMPLES = """
|
ansible/plugins/lookup/file.py
CHANGED
|
@@ -28,11 +28,14 @@ DOCUMENTATION = """
|
|
|
28
28
|
notes:
|
|
29
29
|
- if read in variable context, the file can be interpreted as YAML if the content is valid to the parser.
|
|
30
30
|
- this lookup does not understand 'globbing', use the fileglob lookup instead.
|
|
31
|
+
seealso:
|
|
32
|
+
- ref: playbook_task_paths
|
|
33
|
+
description: Search paths used for relative files.
|
|
31
34
|
"""
|
|
32
35
|
|
|
33
36
|
EXAMPLES = """
|
|
34
37
|
- ansible.builtin.debug:
|
|
35
|
-
msg: "the value of foo.txt is {{lookup('ansible.builtin.file', '/etc/foo.txt') }}"
|
|
38
|
+
msg: "the value of foo.txt is {{ lookup('ansible.builtin.file', '/etc/foo.txt') }}"
|
|
36
39
|
|
|
37
40
|
- name: display multiple file contents
|
|
38
41
|
ansible.builtin.debug: var=item
|
|
@@ -52,7 +55,7 @@ RETURN = """
|
|
|
52
55
|
|
|
53
56
|
from ansible.errors import AnsibleError, AnsibleOptionsError, AnsibleLookupError
|
|
54
57
|
from ansible.plugins.lookup import LookupBase
|
|
55
|
-
from ansible.module_utils.
|
|
58
|
+
from ansible.module_utils.common.text.converters import to_text
|
|
56
59
|
from ansible.utils.display import Display
|
|
57
60
|
|
|
58
61
|
display = Display()
|
|
@@ -21,7 +21,10 @@ DOCUMENTATION = """
|
|
|
21
21
|
- See R(Ansible task paths,playbook_task_paths) to understand how file lookup occurs with paths.
|
|
22
22
|
- Matching is against local system files on the Ansible controller.
|
|
23
23
|
To iterate a list of files on a remote node, use the M(ansible.builtin.find) module.
|
|
24
|
-
- Returns a string list of paths joined by commas, or an empty list if no files match. For a 'true list' pass
|
|
24
|
+
- Returns a string list of paths joined by commas, or an empty list if no files match. For a 'true list' pass O(ignore:wantlist=True) to the lookup.
|
|
25
|
+
seealso:
|
|
26
|
+
- ref: playbook_task_paths
|
|
27
|
+
description: Search paths used for relative files.
|
|
25
28
|
"""
|
|
26
29
|
|
|
27
30
|
EXAMPLES = """
|
|
@@ -50,7 +53,7 @@ import os
|
|
|
50
53
|
import glob
|
|
51
54
|
|
|
52
55
|
from ansible.plugins.lookup import LookupBase
|
|
53
|
-
from ansible.module_utils.
|
|
56
|
+
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
|
54
57
|
|
|
55
58
|
|
|
56
59
|
class LookupModule(LookupBase):
|
|
@@ -15,9 +15,9 @@ DOCUMENTATION = """
|
|
|
15
15
|
to the containing locations of role / play / include and so on.
|
|
16
16
|
- The list of files has precedence over the paths searched.
|
|
17
17
|
For example, A task in a role has a 'file1' in the play's relative path, this will be used, 'file2' in role's relative path will not.
|
|
18
|
-
- Either a list of files
|
|
18
|
+
- Either a list of files O(_terms) or a key O(files) with a list of files is required for this plugin to operate.
|
|
19
19
|
notes:
|
|
20
|
-
- This lookup can be used in 'dual mode', either passing a list of file names or a dictionary that has
|
|
20
|
+
- This lookup can be used in 'dual mode', either passing a list of file names or a dictionary that has O(files) and O(paths).
|
|
21
21
|
options:
|
|
22
22
|
_terms:
|
|
23
23
|
description: A list of file names.
|
|
@@ -35,16 +35,19 @@ DOCUMENTATION = """
|
|
|
35
35
|
type: boolean
|
|
36
36
|
default: False
|
|
37
37
|
description:
|
|
38
|
-
- When
|
|
38
|
+
- When V(True), return an empty list when no files are matched.
|
|
39
39
|
- This is useful when used with C(with_first_found), as an empty list return to C(with_) calls
|
|
40
40
|
causes the calling task to be skipped.
|
|
41
|
-
- When used as a template via C(lookup) or C(query), setting
|
|
41
|
+
- When used as a template via C(lookup) or C(query), setting O(skip=True) will *not* cause the task to skip.
|
|
42
42
|
Tasks must handle the empty list return from the template.
|
|
43
|
-
- When
|
|
43
|
+
- When V(False) and C(lookup) or C(query) specifies O(ignore:errors='ignore') all errors (including no file found,
|
|
44
44
|
but potentially others) return an empty string or an empty list respectively.
|
|
45
|
-
- When
|
|
45
|
+
- When V(True) and C(lookup) or C(query) specifies O(ignore:errors='ignore'), no file found will return an empty
|
|
46
46
|
list and other potential errors return an empty string or empty list depending on the template call
|
|
47
|
-
(in other words return values of C(lookup)
|
|
47
|
+
(in other words return values of C(lookup) vs C(query)).
|
|
48
|
+
seealso:
|
|
49
|
+
- ref: playbook_task_paths
|
|
50
|
+
description: Search paths used for relative paths/files.
|
|
48
51
|
"""
|
|
49
52
|
|
|
50
53
|
EXAMPLES = """
|
|
@@ -165,15 +168,13 @@ class LookupModule(LookupBase):
|
|
|
165
168
|
total_search = []
|
|
166
169
|
skip = False
|
|
167
170
|
|
|
168
|
-
if not terms and kwargs:
|
|
169
|
-
terms = ['']
|
|
170
|
-
|
|
171
171
|
# can use a dict instead of list item to pass inline config
|
|
172
172
|
for term in terms:
|
|
173
173
|
if isinstance(term, Mapping):
|
|
174
174
|
self.set_options(var_options=variables, direct=term)
|
|
175
|
+
files = self.get_option('files')
|
|
175
176
|
elif isinstance(term, string_types):
|
|
176
|
-
|
|
177
|
+
files = [term]
|
|
177
178
|
elif isinstance(term, Sequence):
|
|
178
179
|
partial, skip = self._process_terms(term, variables, kwargs)
|
|
179
180
|
total_search.extend(partial)
|
|
@@ -181,7 +182,6 @@ class LookupModule(LookupBase):
|
|
|
181
182
|
else:
|
|
182
183
|
raise AnsibleLookupError("Invalid term supplied, can handle string, mapping or list of strings but got: %s for %s" % (type(term), term))
|
|
183
184
|
|
|
184
|
-
files = self.get_option('files')
|
|
185
185
|
paths = self.get_option('paths')
|
|
186
186
|
|
|
187
187
|
# NOTE: this is used as 'global' but can be set many times?!?!?
|
|
@@ -198,8 +198,8 @@ class LookupModule(LookupBase):
|
|
|
198
198
|
f = os.path.join(path, fn)
|
|
199
199
|
total_search.append(f)
|
|
200
200
|
elif filelist:
|
|
201
|
-
# NOTE: this
|
|
202
|
-
total_search
|
|
201
|
+
# NOTE: this is now 'extend', previouslly it would clobber all options, but we deemed that a bug
|
|
202
|
+
total_search.extend(filelist)
|
|
203
203
|
else:
|
|
204
204
|
total_search.append(term)
|
|
205
205
|
|
|
@@ -207,6 +207,10 @@ class LookupModule(LookupBase):
|
|
|
207
207
|
|
|
208
208
|
def run(self, terms, variables, **kwargs):
|
|
209
209
|
|
|
210
|
+
if not terms:
|
|
211
|
+
self.set_options(var_options=variables, direct=kwargs)
|
|
212
|
+
terms = self.get_option('files')
|
|
213
|
+
|
|
210
214
|
total_search, skip = self._process_terms(terms, variables, kwargs)
|
|
211
215
|
|
|
212
216
|
# NOTE: during refactor noticed that the 'using a dict' as term
|
|
@@ -222,6 +226,8 @@ class LookupModule(LookupBase):
|
|
|
222
226
|
try:
|
|
223
227
|
fn = self._templar.template(fn)
|
|
224
228
|
except (AnsibleUndefinedVariable, UndefinedError):
|
|
229
|
+
# NOTE: backwards compat ff behaviour is to ignore errors when vars are undefined.
|
|
230
|
+
# moved here from task_executor.
|
|
225
231
|
continue
|
|
226
232
|
|
|
227
233
|
# get subdir if set by task executor, default to files otherwise
|