ansible-core 2.17.5rc1__py3-none-any.whl → 2.18.0rc1__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/__main__.py +2 -17
- ansible/cli/__init__.py +3 -15
- ansible/cli/config.py +187 -24
- ansible/cli/console.py +1 -1
- ansible/cli/doc.py +38 -16
- ansible/cli/galaxy.py +3 -49
- ansible/cli/inventory.py +2 -2
- ansible/cli/pull.py +2 -2
- ansible/cli/scripts/ansible_connection_cli_stub.py +1 -10
- ansible/config/base.yml +127 -57
- ansible/config/manager.py +89 -11
- ansible/constants.py +32 -9
- ansible/errors/__init__.py +5 -0
- ansible/executor/interpreter_discovery.py +1 -1
- ansible/executor/play_iterator.py +34 -0
- ansible/executor/playbook_executor.py +1 -4
- ansible/executor/powershell/become_wrapper.ps1 +4 -5
- ansible/executor/powershell/bootstrap_wrapper.ps1 +2 -3
- ansible/executor/powershell/exec_wrapper.ps1 +1 -1
- ansible/executor/powershell/module_manifest.py +2 -2
- ansible/executor/task_executor.py +50 -39
- ansible/executor/task_queue_manager.py +1 -1
- ansible/executor/task_result.py +1 -1
- ansible/galaxy/api.py +3 -4
- ansible/galaxy/collection/__init__.py +21 -10
- ansible/galaxy/collection/concrete_artifact_manager.py +10 -5
- ansible/galaxy/collection/galaxy_api_proxy.py +10 -16
- ansible/galaxy/collection/gpg.py +17 -23
- ansible/galaxy/data/COPYING +7 -0
- ansible/galaxy/data/apb/Dockerfile.j2 +1 -0
- ansible/galaxy/data/apb/Makefile.j2 +1 -0
- ansible/galaxy/data/apb/README.md +7 -3
- ansible/galaxy/data/apb/apb.yml.j2 +1 -0
- ansible/galaxy/data/apb/defaults/main.yml.j2 +1 -0
- ansible/galaxy/data/apb/handlers/main.yml.j2 +1 -0
- ansible/galaxy/data/apb/meta/main.yml.j2 +1 -0
- ansible/galaxy/data/apb/playbooks/deprovision.yml.j2 +1 -0
- ansible/galaxy/data/apb/playbooks/provision.yml.j2 +1 -0
- ansible/galaxy/data/apb/tasks/main.yml.j2 +1 -0
- ansible/galaxy/data/apb/tests/ansible.cfg +1 -0
- ansible/galaxy/data/apb/tests/inventory +1 -0
- ansible/galaxy/data/apb/tests/test.yml.j2 +1 -0
- ansible/galaxy/data/apb/vars/main.yml.j2 +1 -0
- ansible/galaxy/data/collections_galaxy_meta.yml +1 -0
- ansible/galaxy/data/container/defaults/main.yml.j2 +1 -0
- ansible/galaxy/data/container/handlers/main.yml.j2 +1 -0
- ansible/galaxy/data/container/meta/container.yml.j2 +1 -0
- ansible/galaxy/data/container/meta/main.yml.j2 +1 -0
- ansible/galaxy/data/container/tasks/main.yml.j2 +1 -0
- ansible/galaxy/data/container/tests/ansible.cfg +1 -0
- ansible/galaxy/data/container/tests/inventory +1 -0
- ansible/galaxy/data/container/tests/test.yml.j2 +1 -0
- ansible/galaxy/data/container/vars/main.yml.j2 +1 -0
- ansible/galaxy/data/default/collection/README.md.j2 +1 -0
- ansible/galaxy/data/default/collection/galaxy.yml.j2 +1 -0
- ansible/galaxy/data/default/collection/meta/runtime.yml +1 -0
- ansible/galaxy/data/default/collection/plugins/README.md.j2 +1 -0
- ansible/galaxy/data/default/role/defaults/main.yml.j2 +1 -0
- ansible/galaxy/data/default/role/handlers/main.yml.j2 +1 -0
- ansible/galaxy/data/default/role/meta/main.yml.j2 +1 -0
- ansible/galaxy/data/default/role/tasks/main.yml.j2 +1 -0
- ansible/galaxy/data/default/role/tests/inventory +1 -0
- ansible/galaxy/data/default/role/tests/test.yml.j2 +1 -0
- ansible/galaxy/data/default/role/vars/main.yml.j2 +1 -0
- ansible/galaxy/data/network/cliconf_plugins/example.py.j2 +1 -0
- ansible/galaxy/data/network/defaults/main.yml.j2 +1 -0
- ansible/galaxy/data/network/library/example_command.py.j2 +1 -0
- ansible/galaxy/data/network/library/example_config.py.j2 +1 -0
- ansible/galaxy/data/network/library/example_facts.py.j2 +1 -0
- ansible/galaxy/data/network/meta/main.yml.j2 +1 -0
- ansible/galaxy/data/network/module_utils/example.py.j2 +1 -0
- ansible/galaxy/data/network/netconf_plugins/example.py.j2 +1 -0
- ansible/galaxy/data/network/tasks/main.yml.j2 +1 -0
- ansible/galaxy/data/network/terminal_plugins/example.py.j2 +1 -0
- ansible/galaxy/data/network/tests/inventory +1 -0
- ansible/galaxy/data/network/tests/test.yml.j2 +1 -0
- ansible/galaxy/data/network/vars/main.yml.j2 +1 -0
- ansible/galaxy/dependency_resolution/providers.py +3 -3
- ansible/galaxy/role.py +1 -1
- ansible/galaxy/token.py +20 -8
- ansible/keyword_desc.yml +1 -1
- ansible/module_utils/_internal/__init__.py +0 -0
- ansible/module_utils/_internal/_concurrent/__init__.py +0 -0
- ansible/module_utils/_internal/_concurrent/_daemon_threading.py +28 -0
- ansible/module_utils/_internal/_concurrent/_futures.py +21 -0
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/api.py +2 -2
- ansible/module_utils/basic.py +8 -8
- ansible/module_utils/common/collections.py +1 -1
- ansible/module_utils/common/file.py +0 -6
- ansible/module_utils/common/process.py +22 -9
- ansible/module_utils/common/text/converters.py +5 -8
- ansible/module_utils/common/text/formatters.py +20 -4
- ansible/module_utils/common/validation.py +33 -25
- ansible/module_utils/compat/paramiko.py +6 -1
- ansible/module_utils/compat/selinux.py +2 -2
- ansible/module_utils/connection.py +8 -24
- ansible/module_utils/csharp/Ansible.Become.cs +14 -25
- ansible/module_utils/csharp/Ansible.Process.cs +1 -1
- ansible/module_utils/distro/__init__.py +1 -1
- ansible/module_utils/distro/_distro.py +8 -4
- ansible/module_utils/facts/collector.py +2 -0
- ansible/module_utils/facts/default_collectors.py +3 -1
- ansible/module_utils/facts/hardware/aix.py +54 -52
- ansible/module_utils/facts/hardware/darwin.py +37 -34
- ansible/module_utils/facts/hardware/freebsd.py +55 -15
- ansible/module_utils/facts/hardware/hpux.py +3 -0
- ansible/module_utils/facts/hardware/linux.py +101 -57
- ansible/module_utils/facts/hardware/netbsd.py +3 -0
- ansible/module_utils/facts/hardware/openbsd.py +4 -1
- ansible/module_utils/facts/hardware/sunos.py +7 -1
- ansible/module_utils/facts/network/aix.py +16 -17
- ansible/module_utils/facts/network/fc_wwn.py +4 -1
- ansible/module_utils/facts/network/hpux.py +21 -4
- ansible/module_utils/facts/network/iscsi.py +7 -8
- ansible/module_utils/facts/network/linux.py +0 -2
- ansible/module_utils/facts/other/facter.py +9 -4
- ansible/module_utils/facts/other/ohai.py +5 -5
- ansible/module_utils/facts/packages.py +49 -7
- ansible/module_utils/facts/sysctl.py +33 -31
- ansible/module_utils/facts/system/distribution.py +2 -2
- ansible/module_utils/facts/system/local.py +12 -22
- ansible/module_utils/facts/system/service_mgr.py +3 -1
- ansible/module_utils/facts/system/systemd.py +47 -0
- ansible/module_utils/facts/timeout.py +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 +1 -1
- ansible/module_utils/splitter.py +1 -1
- ansible/modules/add_host.py +1 -1
- ansible/modules/apt.py +43 -32
- ansible/modules/apt_key.py +6 -6
- ansible/modules/apt_repository.py +23 -14
- ansible/modules/assemble.py +7 -2
- ansible/modules/assert.py +4 -4
- ansible/modules/blockinfile.py +3 -6
- ansible/modules/command.py +1 -1
- ansible/modules/copy.py +4 -4
- ansible/modules/cron.py +13 -10
- ansible/modules/deb822_repository.py +16 -17
- ansible/modules/debconf.py +25 -22
- ansible/modules/debug.py +1 -1
- ansible/modules/dnf.py +79 -164
- ansible/modules/dnf5.py +54 -29
- ansible/modules/dpkg_selections.py +2 -2
- ansible/modules/expect.py +2 -2
- ansible/modules/fetch.py +2 -2
- ansible/modules/file.py +5 -3
- ansible/modules/find.py +40 -12
- ansible/modules/gather_facts.py +4 -2
- ansible/modules/get_url.py +29 -24
- ansible/modules/git.py +35 -35
- ansible/modules/group.py +71 -1
- ansible/modules/hostname.py +2 -4
- ansible/modules/include_vars.py +5 -5
- ansible/modules/iptables.py +13 -16
- ansible/modules/known_hosts.py +16 -13
- ansible/modules/lineinfile.py +1 -4
- ansible/modules/meta.py +6 -1
- ansible/modules/mount_facts.py +651 -0
- ansible/modules/package_facts.py +63 -80
- ansible/modules/pause.py +4 -3
- ansible/modules/pip.py +14 -14
- ansible/modules/replace.py +1 -4
- ansible/modules/rpm_key.py +31 -11
- ansible/modules/service.py +8 -8
- ansible/modules/service_facts.py +20 -5
- ansible/modules/set_stats.py +1 -1
- ansible/modules/setup.py +3 -3
- ansible/modules/stat.py +3 -3
- ansible/modules/subversion.py +1 -1
- ansible/modules/systemd.py +16 -10
- ansible/modules/systemd_service.py +16 -10
- ansible/modules/sysvinit.py +4 -4
- ansible/modules/unarchive.py +35 -22
- ansible/modules/uri.py +24 -18
- ansible/modules/user.py +148 -13
- ansible/modules/validate_argument_spec.py +3 -3
- ansible/modules/wait_for_connection.py +2 -1
- ansible/modules/yum_repository.py +136 -179
- ansible/parsing/dataloader.py +2 -2
- ansible/parsing/mod_args.py +11 -10
- ansible/parsing/vault/__init__.py +8 -3
- ansible/parsing/yaml/constructor.py +10 -8
- ansible/parsing/yaml/objects.py +1 -1
- ansible/playbook/base.py +12 -23
- ansible/playbook/helpers.py +4 -0
- ansible/playbook/loop_control.py +8 -0
- ansible/playbook/play.py +4 -22
- ansible/playbook/play_context.py +0 -16
- ansible/playbook/playbook_include.py +2 -2
- ansible/playbook/role/__init__.py +2 -2
- ansible/plugins/__init__.py +2 -0
- ansible/plugins/action/__init__.py +7 -9
- ansible/plugins/action/dnf.py +7 -5
- ansible/plugins/action/package.py +5 -4
- ansible/plugins/action/reboot.py +2 -2
- ansible/plugins/become/__init__.py +1 -1
- ansible/plugins/callback/__init__.py +44 -3
- ansible/plugins/callback/default.py +1 -1
- ansible/plugins/cliconf/__init__.py +1 -1
- ansible/plugins/connection/paramiko_ssh.py +2 -80
- ansible/plugins/connection/psrp.py +33 -82
- ansible/plugins/connection/ssh.py +0 -8
- ansible/plugins/connection/winrm.py +46 -1
- ansible/plugins/doc_fragments/connection_pipelining.py +2 -2
- ansible/plugins/doc_fragments/constructed.py +10 -10
- ansible/plugins/doc_fragments/default_callback.py +8 -8
- ansible/plugins/doc_fragments/files.py +5 -5
- ansible/plugins/doc_fragments/inventory_cache.py +2 -2
- ansible/plugins/doc_fragments/result_format_callback.py +6 -6
- ansible/plugins/doc_fragments/return_common.py +1 -1
- ansible/plugins/doc_fragments/shell_common.py +2 -10
- ansible/plugins/doc_fragments/shell_windows.py +0 -9
- ansible/plugins/doc_fragments/url.py +2 -2
- ansible/plugins/doc_fragments/url_windows.py +4 -5
- ansible/plugins/doc_fragments/validate.py +1 -1
- ansible/plugins/filter/core.py +2 -0
- ansible/plugins/filter/human_to_bytes.yml +9 -0
- ansible/plugins/filter/password_hash.yml +1 -1
- ansible/plugins/filter/strftime.yml +1 -1
- ansible/plugins/filter/to_nice_json.yml +7 -3
- ansible/plugins/filter/to_uuid.yml +1 -1
- ansible/plugins/filter/unique.yml +28 -0
- ansible/plugins/inventory/script.py +1 -1
- ansible/plugins/list.py +1 -1
- ansible/plugins/loader.py +0 -11
- ansible/plugins/lookup/config.py +1 -1
- ansible/plugins/lookup/csvfile.py +21 -9
- ansible/plugins/lookup/env.py +8 -9
- ansible/plugins/lookup/ini.py +10 -1
- ansible/plugins/lookup/random_choice.py +2 -2
- ansible/plugins/lookup/url.py +7 -2
- ansible/plugins/shell/__init__.py +15 -20
- ansible/plugins/shell/powershell.py +9 -6
- ansible/plugins/strategy/__init__.py +18 -7
- ansible/plugins/strategy/linear.py +1 -13
- ansible/plugins/test/core.py +23 -1
- ansible/plugins/test/issubset.yml +1 -1
- ansible/plugins/test/subset.yml +1 -1
- ansible/plugins/test/timedout.yml +20 -0
- ansible/plugins/test/vault_encrypted.yml +6 -6
- ansible/plugins/test/vaulted_file.yml +19 -0
- ansible/release.py +2 -2
- ansible/template/__init__.py +3 -8
- ansible/utils/collection_loader/_collection_finder.py +23 -55
- ansible/utils/display.py +44 -31
- ansible/utils/galaxy.py +1 -1
- ansible/utils/jsonrpc.py +1 -1
- ansible/utils/listify.py +1 -5
- ansible/utils/path.py +3 -0
- ansible/utils/vars.py +18 -27
- ansible/vars/manager.py +7 -150
- ansible/vars/plugins.py +1 -1
- ansible_core-2.18.0rc1.dist-info/Apache-License.txt +202 -0
- {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/METADATA +36 -23
- ansible_core-2.18.0rc1.dist-info/MIT-license.txt +14 -0
- ansible_core-2.18.0rc1.dist-info/PSF-license.txt +48 -0
- {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/RECORD +321 -316
- {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/entry_points.txt +1 -1
- ansible_core-2.18.0rc1.dist-info/simplified_bsd.txt +8 -0
- ansible_test/_data/completion/docker.txt +7 -7
- ansible_test/_data/completion/remote.txt +5 -4
- ansible_test/_data/completion/windows.txt +4 -4
- ansible_test/_data/requirements/ansible-test.txt +1 -2
- ansible_test/_data/requirements/constraints.txt +1 -2
- ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
- ansible_test/_data/requirements/sanity.changelog.in +1 -1
- ansible_test/_data/requirements/sanity.changelog.txt +4 -4
- ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
- ansible_test/_data/requirements/sanity.import.txt +1 -1
- ansible_test/_data/requirements/sanity.integration-aliases.txt +1 -1
- ansible_test/_data/requirements/sanity.pep8.txt +1 -1
- ansible_test/_data/requirements/sanity.pylint.txt +6 -8
- ansible_test/_data/requirements/sanity.runtime-metadata.txt +2 -2
- ansible_test/_data/requirements/sanity.validate-modules.txt +3 -3
- ansible_test/_data/requirements/sanity.yamllint.in +1 -0
- ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
- ansible_test/_internal/ansible_util.py +8 -35
- ansible_test/_internal/ci/azp.py +1 -1
- ansible_test/_internal/classification/__init__.py +0 -2
- ansible_test/_internal/cli/parsers/key_value_parsers.py +3 -0
- ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -1
- ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
- ansible_test/_internal/commands/integration/cloud/nios.py +1 -1
- ansible_test/_internal/commands/sanity/__init__.py +96 -19
- ansible_test/_internal/commands/sanity/pylint.py +20 -24
- ansible_test/_internal/completion.py +2 -0
- ansible_test/_internal/constants.py +0 -1
- ansible_test/_internal/coverage_util.py +1 -2
- ansible_test/_internal/docker_util.py +10 -2
- ansible_test/_internal/encoding.py +4 -4
- ansible_test/_internal/host_configs.py +10 -0
- ansible_test/_internal/host_profiles.py +9 -13
- ansible_test/_internal/pypi_proxy.py +1 -1
- ansible_test/_internal/python_requirements.py +5 -14
- ansible_test/_internal/timeout.py +1 -1
- ansible_test/_internal/util.py +56 -8
- ansible_test/_internal/util_common.py +5 -1
- ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.json +3 -1
- ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +6 -3
- ansible_test/_util/controller/sanity/code-smell/empty-init.json +0 -2
- ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +5 -0
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +5 -0
- ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +5 -0
- ansible_test/_util/controller/sanity/pylint/config/collection.cfg +6 -0
- ansible_test/_util/controller/sanity/pylint/config/default.cfg +6 -0
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -19
- ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +3 -4
- ansible_test/_util/controller/sanity/shellcheck/exclude.txt +1 -0
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +67 -2
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +27 -5
- ansible_test/_util/target/cli/ansible_test_cli_stub.py +0 -0
- ansible_test/_util/target/common/constants.py +2 -2
- ansible_test/_util/target/injector/python.py +5 -0
- ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +6 -0
- ansible_test/_util/target/sanity/import/importer.py +1 -1
- ansible_test/_util/target/setup/bootstrap.sh +6 -17
- ansible_test/_util/target/setup/requirements.py +18 -24
- ansible_test/config/config.yml +1 -1
- ansible_core-2.17.5rc1.data/scripts/ansible-test +0 -44
- ansible_test/_data/requirements/sanity.mypy.in +0 -10
- ansible_test/_data/requirements/sanity.mypy.txt +0 -18
- ansible_test/_internal/commands/sanity/mypy.py +0 -274
- ansible_test/_util/controller/sanity/mypy/ansible-core.ini +0 -116
- ansible_test/_util/controller/sanity/mypy/ansible-test.ini +0 -27
- ansible_test/_util/controller/sanity/mypy/modules.ini +0 -92
- ansible_test/_util/controller/sanity/mypy/packaging.ini +0 -20
- {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/COPYING +0 -0
- {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/WHEEL +0 -0
- {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/top_level.txt +0 -0
ansible/template/__init__.py
CHANGED
|
@@ -480,7 +480,7 @@ class JinjaPluginIntercept(MutableMapping):
|
|
|
480
480
|
if self._pluginloader.type == 'filter':
|
|
481
481
|
# filter need wrapping
|
|
482
482
|
if key in C.STRING_TYPE_FILTERS:
|
|
483
|
-
# avoid
|
|
483
|
+
# avoid literal_eval when you WANT strings
|
|
484
484
|
func = _wrap_native_text(func)
|
|
485
485
|
else:
|
|
486
486
|
# conditionally unroll iterators/generators to avoid having to use `|list` after every filter
|
|
@@ -706,7 +706,7 @@ class Templar:
|
|
|
706
706
|
setattr(obj, key, original[key])
|
|
707
707
|
|
|
708
708
|
def template(self, variable, convert_bare=False, preserve_trailing_newlines=True, escape_backslashes=True, fail_on_undefined=None, overrides=None,
|
|
709
|
-
convert_data=True, static_vars=None,
|
|
709
|
+
convert_data=True, static_vars=None, disable_lookups=False):
|
|
710
710
|
'''
|
|
711
711
|
Templates (possibly recursively) any given data as input. If convert_bare is
|
|
712
712
|
set to True, the given data will be wrapped as a jinja2 variable ('{{foo}}')
|
|
@@ -714,9 +714,6 @@ class Templar:
|
|
|
714
714
|
'''
|
|
715
715
|
static_vars = [] if static_vars is None else static_vars
|
|
716
716
|
|
|
717
|
-
if cache is not None:
|
|
718
|
-
display.deprecated("The `cache` option to `Templar.template` is no longer functional, and will be removed in a future release.", version='2.18')
|
|
719
|
-
|
|
720
717
|
# Don't template unsafe variables, just return them.
|
|
721
718
|
if hasattr(variable, '__UNSAFE__'):
|
|
722
719
|
return variable
|
|
@@ -883,11 +880,9 @@ class Templar:
|
|
|
883
880
|
return [] if wantlist else None
|
|
884
881
|
|
|
885
882
|
if not is_sequence(ran):
|
|
886
|
-
|
|
883
|
+
raise AnsibleLookupError(
|
|
887
884
|
f'The lookup plugin \'{name}\' was expected to return a list, got \'{type(ran)}\' instead. '
|
|
888
885
|
f'The lookup plugin \'{name}\' needs to be changed to return a list. '
|
|
889
|
-
'This will be an error in Ansible 2.18',
|
|
890
|
-
version='2.18'
|
|
891
886
|
)
|
|
892
887
|
|
|
893
888
|
if ran and allow_unsafe is False:
|
|
@@ -9,17 +9,14 @@ from __future__ import annotations
|
|
|
9
9
|
import itertools
|
|
10
10
|
import os
|
|
11
11
|
import os.path
|
|
12
|
-
import pkgutil
|
|
13
12
|
import re
|
|
14
13
|
import sys
|
|
15
14
|
from keyword import iskeyword
|
|
16
|
-
from tokenize import Name as _VALID_IDENTIFIER_REGEX
|
|
17
15
|
|
|
18
16
|
|
|
19
17
|
# DO NOT add new non-stdlib import deps here, this loader is used by external tools (eg ansible-test import sanity)
|
|
20
18
|
# that only allow stdlib and module_utils
|
|
21
19
|
from ansible.module_utils.common.text.converters import to_native, to_text, to_bytes
|
|
22
|
-
from ansible.module_utils.six import string_types, PY3
|
|
23
20
|
from ._collection_config import AnsibleCollectionConfig
|
|
24
21
|
|
|
25
22
|
from contextlib import contextmanager
|
|
@@ -32,11 +29,7 @@ except ImportError:
|
|
|
32
29
|
__import__(name)
|
|
33
30
|
return sys.modules[name]
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
from importlib import reload as reload_module
|
|
37
|
-
except ImportError:
|
|
38
|
-
# 2.7 has a global reload function instead...
|
|
39
|
-
reload_module = reload # type: ignore[name-defined] # pylint:disable=undefined-variable
|
|
32
|
+
from importlib import reload as reload_module
|
|
40
33
|
|
|
41
34
|
try:
|
|
42
35
|
try:
|
|
@@ -77,26 +70,7 @@ try:
|
|
|
77
70
|
except ImportError:
|
|
78
71
|
_meta_yml_to_dict = None
|
|
79
72
|
|
|
80
|
-
|
|
81
|
-
if not hasattr(__builtins__, 'ModuleNotFoundError'):
|
|
82
|
-
# this was introduced in Python 3.6
|
|
83
|
-
ModuleNotFoundError = ImportError
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
_VALID_IDENTIFIER_STRING_REGEX = re.compile(
|
|
87
|
-
''.join((_VALID_IDENTIFIER_REGEX, r'\Z')),
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
try: # NOTE: py3/py2 compat
|
|
92
|
-
# py2 mypy can't deal with try/excepts
|
|
93
|
-
is_python_identifier = str.isidentifier # type: ignore[attr-defined]
|
|
94
|
-
except AttributeError: # Python 2
|
|
95
|
-
def is_python_identifier(self): # type: (str) -> bool
|
|
96
|
-
"""Determine whether the given string is a Python identifier."""
|
|
97
|
-
# Ref: https://stackoverflow.com/a/55802320/595220
|
|
98
|
-
return bool(re.match(_VALID_IDENTIFIER_STRING_REGEX, self))
|
|
99
|
-
|
|
73
|
+
is_python_identifier = str.isidentifier # type: ignore[attr-defined]
|
|
100
74
|
|
|
101
75
|
PB_EXTENSIONS = ('.yml', '.yaml')
|
|
102
76
|
SYNTHETIC_PACKAGE_NAME = '<ansible_synthetic_collection_package>'
|
|
@@ -219,7 +193,7 @@ class _AnsibleTraversableResources(TraversableResources):
|
|
|
219
193
|
parts = package.split('.')
|
|
220
194
|
is_ns = parts[0] == 'ansible_collections' and len(parts) < 3
|
|
221
195
|
|
|
222
|
-
if isinstance(package,
|
|
196
|
+
if isinstance(package, str):
|
|
223
197
|
if is_ns:
|
|
224
198
|
# Don't use ``spec_from_loader`` here, because that will point
|
|
225
199
|
# to exactly 1 location for a namespace. Use ``find_spec``
|
|
@@ -241,7 +215,7 @@ class _AnsibleCollectionFinder:
|
|
|
241
215
|
# TODO: accept metadata loader override
|
|
242
216
|
self._ansible_pkg_path = to_native(os.path.dirname(to_bytes(sys.modules['ansible'].__file__)))
|
|
243
217
|
|
|
244
|
-
if isinstance(paths,
|
|
218
|
+
if isinstance(paths, str):
|
|
245
219
|
paths = [paths]
|
|
246
220
|
elif paths is None:
|
|
247
221
|
paths = []
|
|
@@ -326,7 +300,7 @@ class _AnsibleCollectionFinder:
|
|
|
326
300
|
return paths
|
|
327
301
|
|
|
328
302
|
def set_playbook_paths(self, playbook_paths):
|
|
329
|
-
if isinstance(playbook_paths,
|
|
303
|
+
if isinstance(playbook_paths, str):
|
|
330
304
|
playbook_paths = [playbook_paths]
|
|
331
305
|
|
|
332
306
|
# track visited paths; we have to preserve the dir order as-passed in case there are duplicate collections (first one wins)
|
|
@@ -412,19 +386,17 @@ class _AnsiblePathHookFinder:
|
|
|
412
386
|
# when called from a path_hook, find_module doesn't usually get the path arg, so this provides our context
|
|
413
387
|
self._pathctx = to_native(pathctx)
|
|
414
388
|
self._collection_finder = collection_finder
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
self._file_finder = None
|
|
389
|
+
# cache the native FileFinder (take advantage of its filesystem cache for future find/load requests)
|
|
390
|
+
self._file_finder = None
|
|
418
391
|
|
|
419
392
|
# class init is fun- this method has a self arg that won't get used
|
|
420
393
|
def _get_filefinder_path_hook(self=None):
|
|
421
394
|
_file_finder_hook = None
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
_file_finder_hook = _file_finder_hook[0]
|
|
395
|
+
# try to find the FileFinder hook to call for fallback path-based imports in Py3
|
|
396
|
+
_file_finder_hook = [ph for ph in sys.path_hooks if 'FileFinder' in repr(ph)]
|
|
397
|
+
if len(_file_finder_hook) != 1:
|
|
398
|
+
raise Exception('need exactly one FileFinder import hook (found {0})'.format(len(_file_finder_hook)))
|
|
399
|
+
_file_finder_hook = _file_finder_hook[0]
|
|
428
400
|
|
|
429
401
|
return _file_finder_hook
|
|
430
402
|
|
|
@@ -445,20 +417,16 @@ class _AnsiblePathHookFinder:
|
|
|
445
417
|
# out what we *shouldn't* be loading with the limited info it has. So we'll just delegate to the
|
|
446
418
|
# normal path-based loader as best we can to service it. This also allows us to take advantage of Python's
|
|
447
419
|
# built-in FS caching and byte-compilation for most things.
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
return None
|
|
457
|
-
|
|
458
|
-
return self._file_finder
|
|
420
|
+
# create or consult our cached file finder for this path
|
|
421
|
+
if not self._file_finder:
|
|
422
|
+
try:
|
|
423
|
+
self._file_finder = _AnsiblePathHookFinder._filefinder_path_hook(self._pathctx)
|
|
424
|
+
except ImportError:
|
|
425
|
+
# FUTURE: log at a high logging level? This is normal for things like python36.zip on the path, but
|
|
426
|
+
# might not be in some other situation...
|
|
427
|
+
return None
|
|
459
428
|
|
|
460
|
-
|
|
461
|
-
return pkgutil.ImpImporter(self._pathctx)
|
|
429
|
+
return self._file_finder
|
|
462
430
|
|
|
463
431
|
def find_module(self, fullname, path=None):
|
|
464
432
|
# we ignore the passed in path here- use what we got from the path hook init
|
|
@@ -1124,7 +1092,7 @@ class AnsibleCollectionRef:
|
|
|
1124
1092
|
|
|
1125
1093
|
def _get_collection_path(collection_name):
|
|
1126
1094
|
collection_name = to_native(collection_name)
|
|
1127
|
-
if not collection_name or not isinstance(collection_name,
|
|
1095
|
+
if not collection_name or not isinstance(collection_name, str) or len(collection_name.split('.')) != 2:
|
|
1128
1096
|
raise ValueError('collection_name must be a non-empty string of the form namespace.collection')
|
|
1129
1097
|
try:
|
|
1130
1098
|
collection_pkg = import_module('ansible_collections.' + collection_name)
|
|
@@ -1307,7 +1275,7 @@ def _iter_modules_impl(paths, prefix=''):
|
|
|
1307
1275
|
|
|
1308
1276
|
def _get_collection_metadata(collection_name):
|
|
1309
1277
|
collection_name = to_native(collection_name)
|
|
1310
|
-
if not collection_name or not isinstance(collection_name,
|
|
1278
|
+
if not collection_name or not isinstance(collection_name, str) or len(collection_name.split('.')) != 2:
|
|
1311
1279
|
raise ValueError('collection_name must be a non-empty string of the form namespace.collection')
|
|
1312
1280
|
|
|
1313
1281
|
try:
|
ansible/utils/display.py
CHANGED
|
@@ -33,7 +33,7 @@ import getpass
|
|
|
33
33
|
import io
|
|
34
34
|
import logging
|
|
35
35
|
import os
|
|
36
|
-
import
|
|
36
|
+
import secrets
|
|
37
37
|
import subprocess
|
|
38
38
|
import sys
|
|
39
39
|
import termios
|
|
@@ -154,27 +154,31 @@ logger = None
|
|
|
154
154
|
if getattr(C, 'DEFAULT_LOG_PATH'):
|
|
155
155
|
path = C.DEFAULT_LOG_PATH
|
|
156
156
|
if path and (os.path.exists(path) and os.access(path, os.W_OK)) or os.access(os.path.dirname(path), os.W_OK):
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
handler
|
|
164
|
-
|
|
157
|
+
if not os.path.isdir(path):
|
|
158
|
+
# NOTE: level is kept at INFO to avoid security disclosures caused by certain libraries when using DEBUG
|
|
159
|
+
logging.basicConfig(filename=path, level=logging.INFO, # DO NOT set to logging.DEBUG
|
|
160
|
+
format='%(asctime)s p=%(process)d u=%(user)s n=%(name)s %(levelname)s| %(message)s')
|
|
161
|
+
|
|
162
|
+
logger = logging.getLogger('ansible')
|
|
163
|
+
for handler in logging.root.handlers:
|
|
164
|
+
handler.addFilter(FilterBlackList(getattr(C, 'DEFAULT_LOG_FILTER', [])))
|
|
165
|
+
handler.addFilter(FilterUserInjector())
|
|
166
|
+
else:
|
|
167
|
+
print(f"[WARNING]: DEFAULT_LOG_PATH can not be a directory '{path}', aborting", file=sys.stderr)
|
|
165
168
|
else:
|
|
166
|
-
print("[WARNING]: log file at
|
|
169
|
+
print(f"[WARNING]: log file at '{path}' is not writeable and we cannot create it, aborting\n", file=sys.stderr)
|
|
167
170
|
|
|
168
|
-
# map color to log levels
|
|
169
|
-
color_to_log_level = {C.
|
|
170
|
-
C.
|
|
171
|
+
# map color to log levels, in order of priority (low to high)
|
|
172
|
+
color_to_log_level = {C.COLOR_DEBUG: logging.DEBUG,
|
|
173
|
+
C.COLOR_VERBOSE: logging.INFO,
|
|
171
174
|
C.COLOR_OK: logging.INFO,
|
|
172
|
-
C.
|
|
173
|
-
C.COLOR_UNREACHABLE: logging.ERROR,
|
|
174
|
-
C.COLOR_DEBUG: logging.DEBUG,
|
|
175
|
+
C.COLOR_INCLUDED: logging.INFO,
|
|
175
176
|
C.COLOR_CHANGED: logging.INFO,
|
|
177
|
+
C.COLOR_SKIP: logging.WARNING,
|
|
176
178
|
C.COLOR_DEPRECATE: logging.WARNING,
|
|
177
|
-
C.
|
|
179
|
+
C.COLOR_WARN: logging.WARNING,
|
|
180
|
+
C.COLOR_UNREACHABLE: logging.ERROR,
|
|
181
|
+
C.COLOR_ERROR: logging.ERROR}
|
|
178
182
|
|
|
179
183
|
b_COW_PATHS = (
|
|
180
184
|
b"/usr/bin/cowsay",
|
|
@@ -310,8 +314,8 @@ class Display(metaclass=Singleton):
|
|
|
310
314
|
|
|
311
315
|
codecs.register_error('_replacing_warning_handler', self._replacing_warning_handler)
|
|
312
316
|
try:
|
|
313
|
-
sys.stdout.reconfigure(errors='_replacing_warning_handler')
|
|
314
|
-
sys.stderr.reconfigure(errors='_replacing_warning_handler')
|
|
317
|
+
sys.stdout.reconfigure(errors='_replacing_warning_handler') # type: ignore[union-attr]
|
|
318
|
+
sys.stderr.reconfigure(errors='_replacing_warning_handler') # type: ignore[union-attr]
|
|
315
319
|
except Exception as ex:
|
|
316
320
|
self.warning(f"failed to reconfigure stdout/stderr with custom encoding error handler: {ex}")
|
|
317
321
|
|
|
@@ -398,6 +402,7 @@ class Display(metaclass=Singleton):
|
|
|
398
402
|
screen_only: bool = False,
|
|
399
403
|
log_only: bool = False,
|
|
400
404
|
newline: bool = True,
|
|
405
|
+
caplevel: int | None = None,
|
|
401
406
|
) -> None:
|
|
402
407
|
""" Display a message to the user
|
|
403
408
|
|
|
@@ -424,7 +429,7 @@ class Display(metaclass=Singleton):
|
|
|
424
429
|
msg2 = msg2 + u'\n'
|
|
425
430
|
|
|
426
431
|
# Note: After Display() class is refactored need to update the log capture
|
|
427
|
-
# code in '
|
|
432
|
+
# code in 'cli/scripts/ansible_connection_cli_stub.py' (and other relevant places).
|
|
428
433
|
if not stderr:
|
|
429
434
|
fileobj = sys.stdout
|
|
430
435
|
else:
|
|
@@ -447,20 +452,28 @@ class Display(metaclass=Singleton):
|
|
|
447
452
|
# raise
|
|
448
453
|
|
|
449
454
|
if logger and not screen_only:
|
|
450
|
-
self._log(nocolor, color)
|
|
455
|
+
self._log(nocolor, color, caplevel)
|
|
451
456
|
|
|
452
457
|
def _log(self, msg: str, color: str | None = None, caplevel: int | None = None):
|
|
453
458
|
|
|
454
459
|
if logger and (caplevel is None or self.log_verbosity > caplevel):
|
|
455
460
|
msg2 = msg.lstrip('\n')
|
|
456
461
|
|
|
457
|
-
|
|
458
|
-
|
|
462
|
+
if caplevel is None or caplevel > 0:
|
|
463
|
+
lvl = logging.INFO
|
|
464
|
+
elif caplevel == -1:
|
|
465
|
+
lvl = logging.ERROR
|
|
466
|
+
elif caplevel == -2:
|
|
467
|
+
lvl = logging.WARNING
|
|
468
|
+
elif caplevel == -3:
|
|
469
|
+
lvl = logging.DEBUG
|
|
470
|
+
elif color:
|
|
459
471
|
# set logger level based on color (not great)
|
|
472
|
+
# but last resort and backwards compatible
|
|
460
473
|
try:
|
|
461
474
|
lvl = color_to_log_level[color]
|
|
462
475
|
except KeyError:
|
|
463
|
-
# this should not happen, but JIC
|
|
476
|
+
# this should not happen if mapping is updated with new color configs, but JIC
|
|
464
477
|
raise AnsibleAssertionError('Invalid color supplied to display: %s' % color)
|
|
465
478
|
|
|
466
479
|
# actually log
|
|
@@ -509,10 +522,10 @@ class Display(metaclass=Singleton):
|
|
|
509
522
|
@_meets_debug
|
|
510
523
|
@_proxy
|
|
511
524
|
def debug(self, msg: str, host: str | None = None) -> None:
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
525
|
+
prefix = "%6d %0.5f" % (os.getpid(), time.time())
|
|
526
|
+
if host is not None:
|
|
527
|
+
prefix += f" [{host}]"
|
|
528
|
+
self.display(f"{prefix}: {msg}", color=C.COLOR_DEBUG, caplevel=-3)
|
|
516
529
|
|
|
517
530
|
def get_deprecation_message(
|
|
518
531
|
self,
|
|
@@ -591,7 +604,7 @@ class Display(metaclass=Singleton):
|
|
|
591
604
|
new_msg = "\n[WARNING]: \n%s" % msg
|
|
592
605
|
|
|
593
606
|
if new_msg not in self._warns:
|
|
594
|
-
self.display(new_msg, color=C.COLOR_WARN, stderr=True)
|
|
607
|
+
self.display(new_msg, color=C.COLOR_WARN, stderr=True, caplevel=-2)
|
|
595
608
|
self._warns[new_msg] = 1
|
|
596
609
|
|
|
597
610
|
@_proxy
|
|
@@ -633,7 +646,7 @@ class Display(metaclass=Singleton):
|
|
|
633
646
|
if self.noncow:
|
|
634
647
|
thecow = self.noncow
|
|
635
648
|
if thecow == 'random':
|
|
636
|
-
thecow =
|
|
649
|
+
thecow = secrets.choice(list(self.cows_available))
|
|
637
650
|
runcmd.append(b'-f')
|
|
638
651
|
runcmd.append(to_bytes(thecow))
|
|
639
652
|
runcmd.append(to_bytes(msg))
|
|
@@ -650,7 +663,7 @@ class Display(metaclass=Singleton):
|
|
|
650
663
|
else:
|
|
651
664
|
new_msg = u"ERROR! %s" % msg
|
|
652
665
|
if new_msg not in self._errors:
|
|
653
|
-
self.display(new_msg, color=C.COLOR_ERROR, stderr=True)
|
|
666
|
+
self.display(new_msg, color=C.COLOR_ERROR, stderr=True, caplevel=-1)
|
|
654
667
|
self._errors[new_msg] = 1
|
|
655
668
|
|
|
656
669
|
@staticmethod
|
ansible/utils/galaxy.py
CHANGED
|
@@ -64,7 +64,7 @@ def scm_archive_resource(src, scm='git', name=None, version='HEAD', keep_scm_met
|
|
|
64
64
|
clone_cmd = [scm_path, 'clone']
|
|
65
65
|
|
|
66
66
|
# Add specific options for ignoring certificates if requested
|
|
67
|
-
ignore_certs = context.CLIARGS['ignore_certs']
|
|
67
|
+
ignore_certs = context.CLIARGS['ignore_certs'] or C.GALAXY_IGNORE_CERTS
|
|
68
68
|
|
|
69
69
|
if ignore_certs:
|
|
70
70
|
if scm == 'git':
|
ansible/utils/jsonrpc.py
CHANGED
|
@@ -83,7 +83,7 @@ class JsonRpcServer(object):
|
|
|
83
83
|
result = to_text(result)
|
|
84
84
|
if not isinstance(result, text_type):
|
|
85
85
|
response["result_type"] = "pickle"
|
|
86
|
-
result = to_text(pickle.dumps(result,
|
|
86
|
+
result = to_text(pickle.dumps(result), errors='surrogateescape')
|
|
87
87
|
response['result'] = result
|
|
88
88
|
return response
|
|
89
89
|
|
ansible/utils/listify.py
CHANGED
|
@@ -27,11 +27,7 @@ display = Display()
|
|
|
27
27
|
__all__ = ['listify_lookup_plugin_terms']
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def listify_lookup_plugin_terms(terms, templar,
|
|
31
|
-
|
|
32
|
-
if loader is not None:
|
|
33
|
-
display.deprecated('"listify_lookup_plugin_terms" does not use "dataloader" anymore, the ability to pass it in will be removed in future versions.',
|
|
34
|
-
version='2.18')
|
|
30
|
+
def listify_lookup_plugin_terms(terms, templar, fail_on_undefined=True, convert_bare=False):
|
|
35
31
|
|
|
36
32
|
if isinstance(terms, string_types):
|
|
37
33
|
terms = templar.template(terms.strip(), convert_bare=convert_bare, fail_on_undefined=fail_on_undefined)
|
ansible/utils/path.py
CHANGED
|
@@ -33,6 +33,9 @@ def unfrackpath(path, follow=True, basedir=None):
|
|
|
33
33
|
|
|
34
34
|
:arg path: A byte or text string representing a path to be canonicalized
|
|
35
35
|
:arg follow: A boolean to indicate of symlinks should be resolved or not
|
|
36
|
+
:arg basedir: A byte string, text string, PathLike object, or `None`
|
|
37
|
+
representing where a relative path should be resolved from.
|
|
38
|
+
`None` will be substituted for the current working directory.
|
|
36
39
|
:raises UnicodeDecodeError: If the canonicalized version of the path
|
|
37
40
|
contains non-utf8 byte sequences.
|
|
38
41
|
:rtype: A text string (unicode on pyyhon2, str on python3).
|
ansible/utils/vars.py
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
20
|
import keyword
|
|
21
|
-
import
|
|
21
|
+
import secrets
|
|
22
22
|
import uuid
|
|
23
23
|
|
|
24
24
|
from collections.abc import MutableMapping, MutableSequence
|
|
@@ -32,12 +32,10 @@ from ansible.module_utils.common.text.converters import to_native, to_text
|
|
|
32
32
|
from ansible.parsing.splitter import parse_kv
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
ADDITIONAL_PY2_KEYWORDS = frozenset(("True", "False", "None"))
|
|
36
|
-
|
|
37
35
|
_MAXSIZE = 2 ** 32
|
|
38
36
|
cur_id = 0
|
|
39
37
|
node_mac = ("%012x" % uuid.getnode())[:12]
|
|
40
|
-
random_int = ("%08x" %
|
|
38
|
+
random_int = ("%08x" % secrets.randbelow(_MAXSIZE))[:8]
|
|
41
39
|
|
|
42
40
|
|
|
43
41
|
def get_unique_id():
|
|
@@ -237,7 +235,22 @@ def load_options_vars(version):
|
|
|
237
235
|
return load_options_vars.options_vars
|
|
238
236
|
|
|
239
237
|
|
|
240
|
-
def
|
|
238
|
+
def isidentifier(ident):
|
|
239
|
+
"""Determine if string is valid identifier.
|
|
240
|
+
|
|
241
|
+
The purpose of this function is to be used to validate any variables created in
|
|
242
|
+
a play to be valid Python identifiers and to not conflict with Python keywords
|
|
243
|
+
to prevent unexpected behavior. Since Python 2 and Python 3 differ in what
|
|
244
|
+
a valid identifier is, this function unifies the validation so playbooks are
|
|
245
|
+
portable between the two. The following changes were made:
|
|
246
|
+
|
|
247
|
+
* disallow non-ascii characters (Python 3 allows for them as opposed to Python 2)
|
|
248
|
+
|
|
249
|
+
:arg ident: A text string of identifier to check. Note: It is callers
|
|
250
|
+
responsibility to convert ident to text if it is not already.
|
|
251
|
+
|
|
252
|
+
Originally posted at https://stackoverflow.com/a/29586366
|
|
253
|
+
"""
|
|
241
254
|
if not isinstance(ident, string_types):
|
|
242
255
|
return False
|
|
243
256
|
|
|
@@ -251,25 +264,3 @@ def _isidentifier_PY3(ident):
|
|
|
251
264
|
return False
|
|
252
265
|
|
|
253
266
|
return True
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
isidentifier = _isidentifier_PY3
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
isidentifier.__doc__ = """Determine if string is valid identifier.
|
|
260
|
-
|
|
261
|
-
The purpose of this function is to be used to validate any variables created in
|
|
262
|
-
a play to be valid Python identifiers and to not conflict with Python keywords
|
|
263
|
-
to prevent unexpected behavior. Since Python 2 and Python 3 differ in what
|
|
264
|
-
a valid identifier is, this function unifies the validation so playbooks are
|
|
265
|
-
portable between the two. The following changes were made:
|
|
266
|
-
|
|
267
|
-
* disallow non-ascii characters (Python 3 allows for them as opposed to Python 2)
|
|
268
|
-
* True, False and None are reserved keywords (these are reserved keywords
|
|
269
|
-
on Python 3 as opposed to Python 2)
|
|
270
|
-
|
|
271
|
-
:arg ident: A text string of identifier to check. Note: It is callers
|
|
272
|
-
responsibility to convert ident to text if it is not already.
|
|
273
|
-
|
|
274
|
-
Originally posted at http://stackoverflow.com/a/29586366
|
|
275
|
-
"""
|