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
ansible/parsing/dataloader.py
CHANGED
|
@@ -11,15 +11,16 @@ import os
|
|
|
11
11
|
import os.path
|
|
12
12
|
import re
|
|
13
13
|
import tempfile
|
|
14
|
+
import typing as t
|
|
14
15
|
|
|
15
16
|
from ansible import constants as C
|
|
16
17
|
from ansible.errors import AnsibleFileNotFound, AnsibleParserError
|
|
17
18
|
from ansible.module_utils.basic import is_executable
|
|
18
19
|
from ansible.module_utils.six import binary_type, text_type
|
|
19
|
-
from ansible.module_utils.
|
|
20
|
+
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
|
|
20
21
|
from ansible.parsing.quoting import unquote
|
|
21
22
|
from ansible.parsing.utils.yaml import from_yaml
|
|
22
|
-
from ansible.parsing.vault import VaultLib, b_HEADER, is_encrypted, is_encrypted_file, parse_vaulttext_envelope
|
|
23
|
+
from ansible.parsing.vault import VaultLib, b_HEADER, is_encrypted, is_encrypted_file, parse_vaulttext_envelope, PromptVaultSecret
|
|
23
24
|
from ansible.utils.path import unfrackpath
|
|
24
25
|
from ansible.utils.display import Display
|
|
25
26
|
|
|
@@ -45,7 +46,7 @@ class DataLoader:
|
|
|
45
46
|
Usage:
|
|
46
47
|
|
|
47
48
|
dl = DataLoader()
|
|
48
|
-
# optionally: dl.
|
|
49
|
+
# optionally: dl.set_vault_secrets([('default', ansible.parsing.vault.PrompVaultSecret(...),)])
|
|
49
50
|
ds = dl.load('...')
|
|
50
51
|
ds = dl.load_from_file('/path/to/file')
|
|
51
52
|
'''
|
|
@@ -66,20 +67,19 @@ class DataLoader:
|
|
|
66
67
|
# initialize the vault stuff with an empty password
|
|
67
68
|
# TODO: replace with a ref to something that can get the password
|
|
68
69
|
# a creds/auth provider
|
|
69
|
-
# self.set_vault_password(None)
|
|
70
70
|
self._vaults = {}
|
|
71
71
|
self._vault = VaultLib()
|
|
72
72
|
self.set_vault_secrets(None)
|
|
73
73
|
|
|
74
74
|
# TODO: since we can query vault_secrets late, we could provide this to DataLoader init
|
|
75
|
-
def set_vault_secrets(self, vault_secrets):
|
|
75
|
+
def set_vault_secrets(self, vault_secrets: list[tuple[str, PromptVaultSecret]] | None) -> None:
|
|
76
76
|
self._vault.secrets = vault_secrets
|
|
77
77
|
|
|
78
|
-
def load(self, data, file_name='<string>', show_content=True, json_only=False):
|
|
78
|
+
def load(self, data: str, file_name: str = '<string>', show_content: bool = True, json_only: bool = False) -> t.Any:
|
|
79
79
|
'''Backwards compat for now'''
|
|
80
80
|
return from_yaml(data, file_name, show_content, self._vault.secrets, json_only=json_only)
|
|
81
81
|
|
|
82
|
-
def load_from_file(self, file_name, cache=True, unsafe=False, json_only=False):
|
|
82
|
+
def load_from_file(self, file_name: str, cache: bool = True, unsafe: bool = False, json_only: bool = False) -> t.Any:
|
|
83
83
|
''' Loads data from a file, which can contain either JSON or YAML. '''
|
|
84
84
|
|
|
85
85
|
file_name = self.path_dwim(file_name)
|
|
@@ -105,28 +105,28 @@ class DataLoader:
|
|
|
105
105
|
# return a deep copy here, so the cache is not affected
|
|
106
106
|
return copy.deepcopy(parsed_data)
|
|
107
107
|
|
|
108
|
-
def path_exists(self, path):
|
|
108
|
+
def path_exists(self, path: str) -> bool:
|
|
109
109
|
path = self.path_dwim(path)
|
|
110
110
|
return os.path.exists(to_bytes(path, errors='surrogate_or_strict'))
|
|
111
111
|
|
|
112
|
-
def is_file(self, path):
|
|
112
|
+
def is_file(self, path: str) -> bool:
|
|
113
113
|
path = self.path_dwim(path)
|
|
114
114
|
return os.path.isfile(to_bytes(path, errors='surrogate_or_strict')) or path == os.devnull
|
|
115
115
|
|
|
116
|
-
def is_directory(self, path):
|
|
116
|
+
def is_directory(self, path: str) -> bool:
|
|
117
117
|
path = self.path_dwim(path)
|
|
118
118
|
return os.path.isdir(to_bytes(path, errors='surrogate_or_strict'))
|
|
119
119
|
|
|
120
|
-
def list_directory(self, path):
|
|
120
|
+
def list_directory(self, path: str) -> list[str]:
|
|
121
121
|
path = self.path_dwim(path)
|
|
122
122
|
return os.listdir(path)
|
|
123
123
|
|
|
124
|
-
def is_executable(self, path):
|
|
124
|
+
def is_executable(self, path: str) -> bool:
|
|
125
125
|
'''is the given path executable?'''
|
|
126
126
|
path = self.path_dwim(path)
|
|
127
127
|
return is_executable(path)
|
|
128
128
|
|
|
129
|
-
def _decrypt_if_vault_data(self, b_vault_data, b_file_name=None):
|
|
129
|
+
def _decrypt_if_vault_data(self, b_vault_data: bytes, b_file_name: bytes | None = None) -> tuple[bytes, bool]:
|
|
130
130
|
'''Decrypt b_vault_data if encrypted and return b_data and the show_content flag'''
|
|
131
131
|
|
|
132
132
|
if not is_encrypted(b_vault_data):
|
|
@@ -139,7 +139,7 @@ class DataLoader:
|
|
|
139
139
|
show_content = False
|
|
140
140
|
return b_data, show_content
|
|
141
141
|
|
|
142
|
-
def _get_file_contents(self, file_name):
|
|
142
|
+
def _get_file_contents(self, file_name: str) -> tuple[bytes, bool]:
|
|
143
143
|
'''
|
|
144
144
|
Reads the file contents from the given file name
|
|
145
145
|
|
|
@@ -168,17 +168,17 @@ class DataLoader:
|
|
|
168
168
|
except (IOError, OSError) as e:
|
|
169
169
|
raise AnsibleParserError("an error occurred while trying to read the file '%s': %s" % (file_name, to_native(e)), orig_exc=e)
|
|
170
170
|
|
|
171
|
-
def get_basedir(self):
|
|
171
|
+
def get_basedir(self) -> str:
|
|
172
172
|
''' returns the current basedir '''
|
|
173
173
|
return self._basedir
|
|
174
174
|
|
|
175
|
-
def set_basedir(self, basedir):
|
|
175
|
+
def set_basedir(self, basedir: str) -> None:
|
|
176
176
|
''' sets the base directory, used to find files when a relative path is given '''
|
|
177
177
|
|
|
178
178
|
if basedir is not None:
|
|
179
179
|
self._basedir = to_text(basedir)
|
|
180
180
|
|
|
181
|
-
def path_dwim(self, given):
|
|
181
|
+
def path_dwim(self, given: str) -> str:
|
|
182
182
|
'''
|
|
183
183
|
make relative paths work like folks expect.
|
|
184
184
|
'''
|
|
@@ -194,7 +194,7 @@ class DataLoader:
|
|
|
194
194
|
|
|
195
195
|
return unfrackpath(path, follow=False)
|
|
196
196
|
|
|
197
|
-
def _is_role(self, path):
|
|
197
|
+
def _is_role(self, path: str) -> bool:
|
|
198
198
|
''' imperfect role detection, roles are still valid w/o tasks|meta/main.yml|yaml|etc '''
|
|
199
199
|
|
|
200
200
|
b_path = to_bytes(path, errors='surrogate_or_strict')
|
|
@@ -228,7 +228,7 @@ class DataLoader:
|
|
|
228
228
|
|
|
229
229
|
return False
|
|
230
230
|
|
|
231
|
-
def path_dwim_relative(self, path, dirname, source, is_role=False):
|
|
231
|
+
def path_dwim_relative(self, path: str, dirname: str, source: str, is_role: bool = False) -> str:
|
|
232
232
|
'''
|
|
233
233
|
find one file in either a role or playbook dir with or without
|
|
234
234
|
explicitly named dirname subdirs
|
|
@@ -283,7 +283,7 @@ class DataLoader:
|
|
|
283
283
|
|
|
284
284
|
return candidate
|
|
285
285
|
|
|
286
|
-
def path_dwim_relative_stack(self, paths, dirname, source, is_role=False):
|
|
286
|
+
def path_dwim_relative_stack(self, paths: list[str], dirname: str, source: str, is_role: bool = False) -> str:
|
|
287
287
|
'''
|
|
288
288
|
find one file in first path in stack taking roles into account and adding play basedir as fallback
|
|
289
289
|
|
|
@@ -342,7 +342,7 @@ class DataLoader:
|
|
|
342
342
|
|
|
343
343
|
return result
|
|
344
344
|
|
|
345
|
-
def _create_content_tempfile(self, content):
|
|
345
|
+
def _create_content_tempfile(self, content: str | bytes) -> str:
|
|
346
346
|
''' Create a tempfile containing defined content '''
|
|
347
347
|
fd, content_tempfile = tempfile.mkstemp(dir=C.DEFAULT_LOCAL_TMP)
|
|
348
348
|
f = os.fdopen(fd, 'wb')
|
|
@@ -356,7 +356,7 @@ class DataLoader:
|
|
|
356
356
|
f.close()
|
|
357
357
|
return content_tempfile
|
|
358
358
|
|
|
359
|
-
def get_real_file(self, file_path, decrypt=True):
|
|
359
|
+
def get_real_file(self, file_path: str, decrypt: bool = True) -> str:
|
|
360
360
|
"""
|
|
361
361
|
If the file is vault encrypted return a path to a temporary decrypted file
|
|
362
362
|
If the file is not encrypted then the path is returned
|
|
@@ -396,7 +396,7 @@ class DataLoader:
|
|
|
396
396
|
except (IOError, OSError) as e:
|
|
397
397
|
raise AnsibleParserError("an error occurred while trying to read the file '%s': %s" % (to_native(real_path), to_native(e)), orig_exc=e)
|
|
398
398
|
|
|
399
|
-
def cleanup_tmp_file(self, file_path):
|
|
399
|
+
def cleanup_tmp_file(self, file_path: str) -> None:
|
|
400
400
|
"""
|
|
401
401
|
Removes any temporary files created from a previous call to
|
|
402
402
|
get_real_file. file_path must be the path returned from a
|
|
@@ -406,7 +406,7 @@ class DataLoader:
|
|
|
406
406
|
os.unlink(file_path)
|
|
407
407
|
self._tempfiles.remove(file_path)
|
|
408
408
|
|
|
409
|
-
def cleanup_all_tmp_files(self):
|
|
409
|
+
def cleanup_all_tmp_files(self) -> None:
|
|
410
410
|
"""
|
|
411
411
|
Removes all temporary files that DataLoader has created
|
|
412
412
|
NOTE: not thread safe, forks also need special handling see __init__ for details.
|
|
@@ -417,7 +417,7 @@ class DataLoader:
|
|
|
417
417
|
except Exception as e:
|
|
418
418
|
display.warning("Unable to cleanup temp files: %s" % to_text(e))
|
|
419
419
|
|
|
420
|
-
def find_vars_files(self, path, name, extensions=None, allow_dir=True):
|
|
420
|
+
def find_vars_files(self, path: str, name: str, extensions: list[str] | None = None, allow_dir: bool = True) -> list[str]:
|
|
421
421
|
"""
|
|
422
422
|
Find vars files in a given path with specified name. This will find
|
|
423
423
|
files in a dir named <name>/ or a file called <name> ending in known
|
|
@@ -447,11 +447,11 @@ class DataLoader:
|
|
|
447
447
|
else:
|
|
448
448
|
continue
|
|
449
449
|
else:
|
|
450
|
-
found.append(full_path)
|
|
450
|
+
found.append(to_text(full_path))
|
|
451
451
|
break
|
|
452
452
|
return found
|
|
453
453
|
|
|
454
|
-
def _get_dir_vars_files(self, path, extensions):
|
|
454
|
+
def _get_dir_vars_files(self, path: str, extensions: list[str]) -> list[str]:
|
|
455
455
|
found = []
|
|
456
456
|
for spath in sorted(self.list_directory(path)):
|
|
457
457
|
if not spath.startswith(u'.') and not spath.endswith(u'~'): # skip hidden and backups
|
ansible/parsing/mod_args.py
CHANGED
|
@@ -22,7 +22,7 @@ __metaclass__ = type
|
|
|
22
22
|
import ansible.constants as C
|
|
23
23
|
from ansible.errors import AnsibleParserError, AnsibleError, AnsibleAssertionError
|
|
24
24
|
from ansible.module_utils.six import string_types
|
|
25
|
-
from ansible.module_utils.
|
|
25
|
+
from ansible.module_utils.common.text.converters import to_text
|
|
26
26
|
from ansible.parsing.splitter import parse_kv, split_args
|
|
27
27
|
from ansible.plugins.loader import module_loader, action_loader
|
|
28
28
|
from ansible.template import Templar
|
ansible/parsing/plugin_docs.py
CHANGED
|
@@ -9,7 +9,7 @@ import tokenize
|
|
|
9
9
|
|
|
10
10
|
from ansible import constants as C
|
|
11
11
|
from ansible.errors import AnsibleError, AnsibleParserError
|
|
12
|
-
from ansible.module_utils.
|
|
12
|
+
from ansible.module_utils.common.text.converters import to_text, to_native
|
|
13
13
|
from ansible.parsing.yaml.loader import AnsibleLoader
|
|
14
14
|
from ansible.utils.display import Display
|
|
15
15
|
|
|
@@ -151,10 +151,10 @@ def read_docstring_from_python_file(filename, verbose=True, ignore_errors=True):
|
|
|
151
151
|
if theid == 'EXAMPLES':
|
|
152
152
|
# examples 'can' be yaml, but even if so, we dont want to parse as such here
|
|
153
153
|
# as it can create undesired 'objects' that don't display well as docs.
|
|
154
|
-
data[varkey] = to_text(child.value.
|
|
154
|
+
data[varkey] = to_text(child.value.value)
|
|
155
155
|
else:
|
|
156
156
|
# string should be yaml if already not a dict
|
|
157
|
-
data[varkey] = AnsibleLoader(child.value.
|
|
157
|
+
data[varkey] = AnsibleLoader(child.value.value, file_name=filename).get_single_data()
|
|
158
158
|
|
|
159
159
|
display.debug('Documentation assigned: %s' % varkey)
|
|
160
160
|
|
ansible/parsing/splitter.py
CHANGED
|
@@ -23,7 +23,7 @@ import codecs
|
|
|
23
23
|
import re
|
|
24
24
|
|
|
25
25
|
from ansible.errors import AnsibleParserError
|
|
26
|
-
from ansible.module_utils.
|
|
26
|
+
from ansible.module_utils.common.text.converters import to_text
|
|
27
27
|
from ansible.parsing.quoting import unquote
|
|
28
28
|
|
|
29
29
|
|
|
@@ -58,15 +58,7 @@ def parse_kv(args, check_raw=False):
|
|
|
58
58
|
|
|
59
59
|
options = {}
|
|
60
60
|
if args is not None:
|
|
61
|
-
|
|
62
|
-
vargs = split_args(args)
|
|
63
|
-
except IndexError as e:
|
|
64
|
-
raise AnsibleParserError("Unable to parse argument string", orig_exc=e)
|
|
65
|
-
except ValueError as ve:
|
|
66
|
-
if 'no closing quotation' in str(ve).lower():
|
|
67
|
-
raise AnsibleParserError("error parsing argument string, try quoting the entire line.", orig_exc=ve)
|
|
68
|
-
else:
|
|
69
|
-
raise
|
|
61
|
+
vargs = split_args(args)
|
|
70
62
|
|
|
71
63
|
raw_params = []
|
|
72
64
|
for orig_x in vargs:
|
|
@@ -168,6 +160,9 @@ def split_args(args):
|
|
|
168
160
|
how Ansible needs to use it.
|
|
169
161
|
'''
|
|
170
162
|
|
|
163
|
+
if not args:
|
|
164
|
+
return []
|
|
165
|
+
|
|
171
166
|
# the list of params parsed out of the arg string
|
|
172
167
|
# this is going to be the result value when we are done
|
|
173
168
|
params = []
|
|
@@ -204,6 +199,10 @@ def split_args(args):
|
|
|
204
199
|
# Empty entries means we have subsequent spaces
|
|
205
200
|
# We want to hold onto them so we can reconstruct them later
|
|
206
201
|
if len(token) == 0 and idx != 0:
|
|
202
|
+
# Make sure there is a params item to store result in.
|
|
203
|
+
if not params:
|
|
204
|
+
params.append('')
|
|
205
|
+
|
|
207
206
|
params[-1] += ' '
|
|
208
207
|
continue
|
|
209
208
|
|
|
@@ -235,13 +234,11 @@ def split_args(args):
|
|
|
235
234
|
elif print_depth or block_depth or comment_depth or inside_quotes or was_inside_quotes:
|
|
236
235
|
if idx == 0 and was_inside_quotes:
|
|
237
236
|
params[-1] = "%s%s" % (params[-1], token)
|
|
238
|
-
|
|
237
|
+
else:
|
|
239
238
|
spacer = ''
|
|
240
239
|
if idx > 0:
|
|
241
240
|
spacer = ' '
|
|
242
241
|
params[-1] = "%s%s%s" % (params[-1], spacer, token)
|
|
243
|
-
else:
|
|
244
|
-
params[-1] = "%s\n%s" % (params[-1], token)
|
|
245
242
|
appended = True
|
|
246
243
|
|
|
247
244
|
# if the number of paired block tags is not the same, the depth has changed, so we calculate that here
|
|
@@ -273,10 +270,11 @@ def split_args(args):
|
|
|
273
270
|
# one item (meaning we split on newlines), add a newline back here
|
|
274
271
|
# to preserve the original structure
|
|
275
272
|
if len(items) > 1 and itemidx != len(items) - 1 and not line_continuation:
|
|
276
|
-
params
|
|
273
|
+
# Make sure there is a params item to store result in.
|
|
274
|
+
if not params:
|
|
275
|
+
params.append('')
|
|
277
276
|
|
|
278
|
-
|
|
279
|
-
line_continuation = False
|
|
277
|
+
params[-1] += '\n'
|
|
280
278
|
|
|
281
279
|
# If we're done and things are not at zero depth or we're still inside quotes,
|
|
282
280
|
# raise an error to indicate that the args were unbalanced
|
ansible/parsing/utils/yaml.py
CHANGED
|
@@ -13,7 +13,7 @@ from yaml import YAMLError
|
|
|
13
13
|
|
|
14
14
|
from ansible.errors import AnsibleParserError
|
|
15
15
|
from ansible.errors.yaml_strings import YAML_SYNTAX_ERROR
|
|
16
|
-
from ansible.module_utils.
|
|
16
|
+
from ansible.module_utils.common.text.converters import to_native
|
|
17
17
|
from ansible.parsing.yaml.loader import AnsibleLoader
|
|
18
18
|
from ansible.parsing.yaml.objects import AnsibleBaseYAMLObject
|
|
19
19
|
from ansible.parsing.ajson import AnsibleJSONDecoder
|
|
@@ -55,7 +55,7 @@ except ImportError:
|
|
|
55
55
|
from ansible.errors import AnsibleError, AnsibleAssertionError
|
|
56
56
|
from ansible import constants as C
|
|
57
57
|
from ansible.module_utils.six import binary_type
|
|
58
|
-
from ansible.module_utils.
|
|
58
|
+
from ansible.module_utils.common.text.converters import to_bytes, to_text, to_native
|
|
59
59
|
from ansible.utils.display import Display
|
|
60
60
|
from ansible.utils.path import makedirs_safe, unfrackpath
|
|
61
61
|
|
|
@@ -787,13 +787,13 @@ class VaultEditor:
|
|
|
787
787
|
|
|
788
788
|
passes = 3
|
|
789
789
|
with open(tmp_path, "wb") as fh:
|
|
790
|
-
for
|
|
790
|
+
for dummy in range(passes):
|
|
791
791
|
fh.seek(0, 0)
|
|
792
792
|
# get a random chunk of data, each pass with other length
|
|
793
793
|
chunk_len = random.randint(max_chunk_len // 2, max_chunk_len)
|
|
794
794
|
data = os.urandom(chunk_len)
|
|
795
795
|
|
|
796
|
-
for
|
|
796
|
+
for dummy in range(0, file_len // chunk_len):
|
|
797
797
|
fh.write(data)
|
|
798
798
|
fh.write(data[:file_len % chunk_len])
|
|
799
799
|
|
|
@@ -1044,10 +1044,10 @@ class VaultEditor:
|
|
|
1044
1044
|
since in the plaintext case, the original contents can be of any text encoding
|
|
1045
1045
|
or arbitrary binary data.
|
|
1046
1046
|
|
|
1047
|
-
When used to write the result of vault encryption, the
|
|
1048
|
-
should be a utf-8 encoded byte string and not a text
|
|
1047
|
+
When used to write the result of vault encryption, the value of the 'data' arg
|
|
1048
|
+
should be a utf-8 encoded byte string and not a text type.
|
|
1049
1049
|
|
|
1050
|
-
When used to write the result of vault decryption, the
|
|
1050
|
+
When used to write the result of vault decryption, the value of the 'data' arg
|
|
1051
1051
|
should be a byte string and not a text type.
|
|
1052
1052
|
|
|
1053
1053
|
:arg data: the byte string (bytes) data
|
|
@@ -1077,6 +1077,8 @@ class VaultEditor:
|
|
|
1077
1077
|
output = getattr(sys.stdout, 'buffer', sys.stdout)
|
|
1078
1078
|
output.write(b_file_data)
|
|
1079
1079
|
else:
|
|
1080
|
+
if not os.access(os.path.dirname(thefile), os.W_OK):
|
|
1081
|
+
raise AnsibleError("Destination '%s' not writable" % (os.path.dirname(thefile)))
|
|
1080
1082
|
# file names are insecure and prone to race conditions, so remove and create securely
|
|
1081
1083
|
if os.path.isfile(thefile):
|
|
1082
1084
|
if shred:
|
|
@@ -23,7 +23,7 @@ from yaml.constructor import SafeConstructor, ConstructorError
|
|
|
23
23
|
from yaml.nodes import MappingNode
|
|
24
24
|
|
|
25
25
|
from ansible import constants as C
|
|
26
|
-
from ansible.module_utils.
|
|
26
|
+
from ansible.module_utils.common.text.converters import to_bytes, to_native
|
|
27
27
|
from ansible.parsing.yaml.objects import AnsibleMapping, AnsibleSequence, AnsibleUnicode, AnsibleVaultEncryptedUnicode
|
|
28
28
|
from ansible.parsing.vault import VaultLib
|
|
29
29
|
from ansible.utils.display import Display
|
ansible/parsing/yaml/objects.py
CHANGED
|
@@ -24,7 +24,7 @@ import sys as _sys
|
|
|
24
24
|
from collections.abc import Sequence
|
|
25
25
|
|
|
26
26
|
from ansible.module_utils.six import text_type
|
|
27
|
-
from ansible.module_utils.
|
|
27
|
+
from ansible.module_utils.common.text.converters import to_bytes, to_text, to_native
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
class AnsibleBaseYAMLObject(object):
|
ansible/playbook/__init__.py
CHANGED
|
@@ -23,7 +23,7 @@ import os
|
|
|
23
23
|
|
|
24
24
|
from ansible import constants as C
|
|
25
25
|
from ansible.errors import AnsibleParserError
|
|
26
|
-
from ansible.module_utils.
|
|
26
|
+
from ansible.module_utils.common.text.converters import to_text, to_native
|
|
27
27
|
from ansible.playbook.play import Play
|
|
28
28
|
from ansible.playbook.playbook_include import PlaybookInclude
|
|
29
29
|
from ansible.plugins.loader import add_all_plugin_dirs
|
ansible/playbook/base.py
CHANGED
|
@@ -19,7 +19,7 @@ from ansible import context
|
|
|
19
19
|
from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleAssertionError
|
|
20
20
|
from ansible.module_utils.six import string_types
|
|
21
21
|
from ansible.module_utils.parsing.convert_bool import boolean
|
|
22
|
-
from ansible.module_utils.
|
|
22
|
+
from ansible.module_utils.common.text.converters import to_text, to_native
|
|
23
23
|
from ansible.parsing.dataloader import DataLoader
|
|
24
24
|
from ansible.playbook.attribute import Attribute, FieldAttribute, ConnectionFieldAttribute, NonInheritableFieldAttribute
|
|
25
25
|
from ansible.plugins.loader import module_loader, action_loader
|
|
@@ -637,7 +637,7 @@ class FieldAttributeBase:
|
|
|
637
637
|
else:
|
|
638
638
|
combined = value + new_value
|
|
639
639
|
|
|
640
|
-
return [i for i,
|
|
640
|
+
return [i for i, dummy in itertools.groupby(combined) if i is not None]
|
|
641
641
|
|
|
642
642
|
def dump_attrs(self):
|
|
643
643
|
'''
|
ansible/playbook/block.py
CHANGED
|
@@ -377,7 +377,6 @@ class Block(Base, Conditional, CollectionSearch, Taggable, Notifiable, Delegatab
|
|
|
377
377
|
if filtered_block.has_tasks():
|
|
378
378
|
tmp_list.append(filtered_block)
|
|
379
379
|
elif ((task.action in C._ACTION_META and task.implicit) or
|
|
380
|
-
(task.action in C._ACTION_INCLUDE and task.evaluate_tags([], self._play.skip_tags, all_vars=all_vars)) or
|
|
381
380
|
task.evaluate_tags(self._play.only_tags, self._play.skip_tags, all_vars=all_vars)):
|
|
382
381
|
tmp_list.append(task)
|
|
383
382
|
return tmp_list
|
ansible/playbook/conditional.py
CHANGED
|
@@ -19,15 +19,10 @@
|
|
|
19
19
|
from __future__ import (absolute_import, division, print_function)
|
|
20
20
|
__metaclass__ = type
|
|
21
21
|
|
|
22
|
-
import ast
|
|
23
22
|
import typing as t
|
|
24
23
|
|
|
25
|
-
from jinja2.compiler import generate
|
|
26
|
-
from jinja2.exceptions import UndefinedError
|
|
27
|
-
|
|
28
24
|
from ansible.errors import AnsibleError, AnsibleUndefinedVariable
|
|
29
|
-
from ansible.module_utils.
|
|
30
|
-
from ansible.module_utils._text import to_native
|
|
25
|
+
from ansible.module_utils.common.text.converters import to_native
|
|
31
26
|
from ansible.playbook.attribute import FieldAttribute
|
|
32
27
|
from ansible.template import Templar
|
|
33
28
|
from ansible.utils.display import Display
|
|
@@ -36,7 +31,6 @@ display = Display()
|
|
|
36
31
|
|
|
37
32
|
|
|
38
33
|
class Conditional:
|
|
39
|
-
|
|
40
34
|
'''
|
|
41
35
|
This is a mix-in class, to be used with Base to allow the object
|
|
42
36
|
to be run conditionally when a condition is met or skipped.
|
|
@@ -53,7 +47,7 @@ class Conditional:
|
|
|
53
47
|
raise AnsibleError("a loader must be specified when using Conditional() directly")
|
|
54
48
|
else:
|
|
55
49
|
self._loader = loader
|
|
56
|
-
super(
|
|
50
|
+
super().__init__()
|
|
57
51
|
|
|
58
52
|
def _validate_when(self, attr, name, value):
|
|
59
53
|
if not isinstance(value, list):
|
|
@@ -67,123 +61,55 @@ class Conditional:
|
|
|
67
61
|
return self.evaluate_conditional_with_result(templar, all_vars)[0]
|
|
68
62
|
|
|
69
63
|
def evaluate_conditional_with_result(self, templar: Templar, all_vars: dict[str, t.Any]) -> tuple[bool, t.Optional[str]]:
|
|
70
|
-
"""
|
|
71
|
-
Loops through the conditionals set on this object, returning
|
|
64
|
+
"""Loops through the conditionals set on this object, returning
|
|
72
65
|
False if any of them evaluate as such as well as the condition
|
|
73
66
|
that was false.
|
|
74
67
|
"""
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
result = True
|
|
84
|
-
false_condition: t.Optional[str] = None
|
|
85
|
-
try:
|
|
86
|
-
for conditional in self.when:
|
|
87
|
-
|
|
88
|
-
# do evaluation
|
|
89
|
-
if conditional is None or conditional == '':
|
|
90
|
-
res = True
|
|
91
|
-
elif isinstance(conditional, bool):
|
|
92
|
-
res = conditional
|
|
93
|
-
else:
|
|
68
|
+
for conditional in self.when:
|
|
69
|
+
if conditional is None or conditional == "":
|
|
70
|
+
res = True
|
|
71
|
+
elif isinstance(conditional, bool):
|
|
72
|
+
res = conditional
|
|
73
|
+
else:
|
|
74
|
+
try:
|
|
94
75
|
res = self._check_conditional(conditional, templar, all_vars)
|
|
76
|
+
except AnsibleError as e:
|
|
77
|
+
raise AnsibleError(
|
|
78
|
+
"The conditional check '%s' failed. The error was: %s" % (to_native(conditional), to_native(e)),
|
|
79
|
+
obj=getattr(self, '_ds', None)
|
|
80
|
+
)
|
|
95
81
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
display.debug("Evaluated conditional (%s): %s" % (conditional, res))
|
|
101
|
-
if not result:
|
|
102
|
-
false_condition = conditional
|
|
103
|
-
break
|
|
82
|
+
display.debug("Evaluated conditional (%s): %s" % (conditional, res))
|
|
83
|
+
if not res:
|
|
84
|
+
return res, conditional
|
|
104
85
|
|
|
105
|
-
|
|
106
|
-
raise AnsibleError("The conditional check '%s' failed. The error was: %s" % (to_native(conditional), to_native(e)), obj=ds)
|
|
107
|
-
|
|
108
|
-
return result, false_condition
|
|
109
|
-
|
|
110
|
-
def _check_conditional(self, conditional, templar, all_vars):
|
|
111
|
-
'''
|
|
112
|
-
This method does the low-level evaluation of each conditional
|
|
113
|
-
set on this object, using jinja2 to wrap the conditionals for
|
|
114
|
-
evaluation.
|
|
115
|
-
'''
|
|
86
|
+
return True, None
|
|
116
87
|
|
|
88
|
+
def _check_conditional(self, conditional: str, templar: Templar, all_vars: dict[str, t.Any]) -> bool:
|
|
117
89
|
original = conditional
|
|
118
|
-
|
|
119
|
-
if templar.is_template(conditional):
|
|
120
|
-
display.warning('conditional statements should not include jinja2 '
|
|
121
|
-
'templating delimiters such as {{ }} or {%% %%}. '
|
|
122
|
-
'Found: %s' % conditional)
|
|
123
|
-
|
|
124
|
-
# make sure the templar is using the variables specified with this method
|
|
125
90
|
templar.available_variables = all_vars
|
|
126
|
-
|
|
127
91
|
try:
|
|
128
|
-
|
|
92
|
+
if templar.is_template(conditional):
|
|
93
|
+
display.warning(
|
|
94
|
+
"conditional statements should not include jinja2 "
|
|
95
|
+
"templating delimiters such as {{ }} or {%% %%}. "
|
|
96
|
+
"Found: %s" % conditional
|
|
97
|
+
)
|
|
98
|
+
conditional = templar.template(conditional)
|
|
99
|
+
if isinstance(conditional, bool):
|
|
100
|
+
return conditional
|
|
101
|
+
elif conditional == "":
|
|
102
|
+
return False
|
|
103
|
+
|
|
104
|
+
# If the result of the first-pass template render (to resolve inline templates) is marked unsafe,
|
|
105
|
+
# explicitly disable lookups on the final pass to prevent evaluation of untrusted content in the
|
|
106
|
+
# constructed template.
|
|
129
107
|
disable_lookups = hasattr(conditional, '__UNSAFE__')
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if not isinstance(conditional, text_type) or conditional == "":
|
|
133
|
-
return conditional
|
|
134
|
-
|
|
135
|
-
# update the lookups flag, as the string returned above may now be unsafe
|
|
136
|
-
# and we don't want future templating calls to do unsafe things
|
|
137
|
-
disable_lookups |= hasattr(conditional, '__UNSAFE__')
|
|
138
|
-
|
|
139
|
-
# First, we do some low-level jinja2 parsing involving the AST format of the
|
|
140
|
-
# statement to ensure we don't do anything unsafe (using the disable_lookup flag above)
|
|
141
|
-
class CleansingNodeVisitor(ast.NodeVisitor):
|
|
142
|
-
def generic_visit(self, node, inside_call=False, inside_yield=False):
|
|
143
|
-
if isinstance(node, ast.Call):
|
|
144
|
-
inside_call = True
|
|
145
|
-
elif isinstance(node, ast.Yield):
|
|
146
|
-
inside_yield = True
|
|
147
|
-
elif isinstance(node, ast.Str):
|
|
148
|
-
if disable_lookups:
|
|
149
|
-
if inside_call and node.s.startswith("__"):
|
|
150
|
-
# calling things with a dunder is generally bad at this point...
|
|
151
|
-
raise AnsibleError(
|
|
152
|
-
"Invalid access found in the conditional: '%s'" % conditional
|
|
153
|
-
)
|
|
154
|
-
elif inside_yield:
|
|
155
|
-
# we're inside a yield, so recursively parse and traverse the AST
|
|
156
|
-
# of the result to catch forbidden syntax from executing
|
|
157
|
-
parsed = ast.parse(node.s, mode='exec')
|
|
158
|
-
cnv = CleansingNodeVisitor()
|
|
159
|
-
cnv.visit(parsed)
|
|
160
|
-
# iterate over all child nodes
|
|
161
|
-
for child_node in ast.iter_child_nodes(node):
|
|
162
|
-
self.generic_visit(
|
|
163
|
-
child_node,
|
|
164
|
-
inside_call=inside_call,
|
|
165
|
-
inside_yield=inside_yield
|
|
166
|
-
)
|
|
167
|
-
try:
|
|
168
|
-
res = templar.environment.parse(conditional, None, None)
|
|
169
|
-
res = generate(res, templar.environment, None, None)
|
|
170
|
-
parsed = ast.parse(res, mode='exec')
|
|
171
|
-
|
|
172
|
-
cnv = CleansingNodeVisitor()
|
|
173
|
-
cnv.visit(parsed)
|
|
174
|
-
except Exception as e:
|
|
175
|
-
raise AnsibleError("Invalid conditional detected: %s" % to_native(e))
|
|
176
|
-
|
|
177
|
-
# and finally we generate and template the presented string and look at the resulting string
|
|
108
|
+
|
|
178
109
|
# NOTE The spaces around True and False are intentional to short-circuit literal_eval for
|
|
179
110
|
# jinja2_native=False and avoid its expensive calls.
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
elif val == "False":
|
|
185
|
-
return False
|
|
186
|
-
else:
|
|
187
|
-
raise AnsibleError("unable to evaluate conditional: %s" % original)
|
|
188
|
-
except (AnsibleUndefinedVariable, UndefinedError) as e:
|
|
111
|
+
return templar.template(
|
|
112
|
+
"{%% if %s %%} True {%% else %%} False {%% endif %%}" % conditional,
|
|
113
|
+
disable_lookups=disable_lookups).strip() == "True"
|
|
114
|
+
except AnsibleUndefinedVariable as e:
|
|
189
115
|
raise AnsibleUndefinedVariable("error while evaluating conditional (%s): %s" % (original, e))
|