ansible-core 2.19.0b4__py3-none-any.whl → 2.19.0b6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ansible/_internal/__init__.py +1 -1
- ansible/_internal/_ansiballz/__init__.py +0 -0
- ansible/_internal/_ansiballz/_builder.py +101 -0
- ansible/_internal/{_ansiballz.py → _ansiballz/_wrapper.py} +11 -11
- ansible/_internal/_collection_proxy.py +1 -1
- ansible/_internal/_errors/_alarm_timeout.py +66 -0
- ansible/_internal/_errors/_captured.py +25 -30
- ansible/_internal/_errors/_error_factory.py +89 -0
- ansible/_internal/_errors/_error_utils.py +240 -0
- ansible/_internal/_errors/_task_timeout.py +28 -0
- ansible/_internal/_event_formatting.py +127 -0
- ansible/_internal/_json/__init__.py +5 -5
- ansible/_internal/_json/_profiles/_cache_persistence.py +2 -0
- ansible/_internal/_json/_profiles/_inventory_legacy.py +1 -1
- ansible/_internal/_json/_profiles/_legacy.py +3 -11
- ansible/_internal/_ssh/__init__.py +0 -0
- ansible/_internal/_ssh/_agent_launch.py +91 -0
- ansible/{utils → _internal/_ssh}/_ssh_agent.py +55 -93
- ansible/_internal/_templating/__init__.py +5 -3
- ansible/_internal/_templating/_datatag.py +2 -1
- ansible/_internal/_templating/_engine.py +3 -4
- ansible/_internal/_templating/_jinja_bits.py +28 -20
- ansible/_internal/_templating/_jinja_common.py +18 -27
- ansible/_internal/_templating/_jinja_plugins.py +36 -5
- ansible/_internal/_templating/_lazy_containers.py +5 -5
- ansible/_internal/_templating/_template_vars.py +72 -0
- ansible/_internal/_templating/_transform.py +26 -19
- ansible/_internal/_templating/_utils.py +1 -1
- ansible/_internal/_yaml/_constructor.py +4 -4
- ansible/_internal/_yaml/_dumper.py +26 -18
- ansible/_internal/_yaml/_errors.py +7 -7
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +1 -1
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +1 -1
- ansible/cli/__init__.py +11 -93
- ansible/cli/arguments/option_helpers.py +3 -4
- ansible/cli/console.py +1 -1
- ansible/cli/doc.py +86 -30
- ansible/cli/inventory.py +5 -7
- ansible/compat/importlib_resources.py +9 -12
- ansible/config/base.yml +46 -0
- ansible/errors/__init__.py +98 -50
- ansible/executor/module_common.py +75 -49
- ansible/executor/powershell/async_watchdog.ps1 +2 -2
- ansible/executor/powershell/async_wrapper.ps1 +3 -3
- ansible/executor/powershell/become_wrapper.ps1 +20 -2
- ansible/executor/powershell/bootstrap_wrapper.ps1 +28 -6
- ansible/executor/powershell/coverage_wrapper.ps1 +15 -6
- ansible/executor/powershell/exec_wrapper.ps1 +219 -6
- ansible/executor/powershell/module_manifest.py +52 -0
- ansible/executor/powershell/module_wrapper.ps1 +47 -21
- ansible/executor/powershell/powershell_expand_user.ps1 +20 -0
- ansible/executor/powershell/powershell_mkdtemp.ps1 +17 -0
- ansible/executor/process/worker.py +40 -115
- ansible/executor/task_executor.py +26 -61
- ansible/executor/task_result.py +2 -4
- ansible/galaxy/api.py +1 -4
- ansible/galaxy/collection/__init__.py +2 -10
- ansible/galaxy/collection/concrete_artifact_manager.py +2 -8
- ansible/galaxy/role.py +2 -2
- ansible/inventory/manager.py +1 -1
- ansible/module_utils/_internal/__init__.py +7 -7
- ansible/module_utils/_internal/_ambient_context.py +3 -3
- ansible/module_utils/_internal/_ansiballz/__init__.py +0 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/__init__.py +0 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/_coverage.py +45 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/_pydevd.py +62 -0
- ansible/module_utils/_internal/{_ansiballz.py → _ansiballz/_loader.py} +13 -39
- ansible/module_utils/_internal/_ansiballz/_respawn.py +32 -0
- ansible/module_utils/_internal/_ansiballz/_respawn_wrapper.py +23 -0
- ansible/module_utils/_internal/_datatag/__init__.py +43 -15
- ansible/module_utils/_internal/_datatag/_tags.py +2 -2
- ansible/module_utils/_internal/_deprecator.py +67 -55
- ansible/module_utils/_internal/_errors.py +88 -17
- ansible/module_utils/_internal/_event_utils.py +61 -0
- ansible/module_utils/_internal/_json/_profiles/__init__.py +22 -4
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +2 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +2 -0
- ansible/module_utils/_internal/_json/_profiles/_tagless.py +3 -1
- ansible/module_utils/{common/messages.py → _internal/_messages.py} +54 -49
- ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +1 -3
- ansible/module_utils/_internal/_plugin_info.py +15 -2
- ansible/module_utils/_internal/_stack.py +22 -0
- ansible/module_utils/_internal/_text_utils.py +6 -0
- ansible/module_utils/_internal/_traceback.py +11 -8
- ansible/module_utils/ansible_release.py +1 -1
- ansible/module_utils/basic.py +95 -71
- ansible/module_utils/common/arg_spec.py +2 -2
- ansible/module_utils/common/collections.py +6 -0
- ansible/module_utils/common/json.py +2 -2
- ansible/module_utils/common/respawn.py +4 -41
- ansible/module_utils/common/text/converters.py +3 -3
- ansible/module_utils/common/validation.py +1 -1
- ansible/module_utils/common/warnings.py +80 -23
- ansible/module_utils/common/yaml.py +1 -1
- ansible/module_utils/connection.py +8 -11
- ansible/module_utils/datatag.py +5 -2
- ansible/module_utils/facts/hardware/linux.py +1 -1
- ansible/module_utils/facts/sysctl.py +4 -6
- ansible/module_utils/facts/system/caps.py +2 -2
- ansible/module_utils/facts/system/distribution.py +16 -3
- ansible/module_utils/facts/system/local.py +1 -1
- ansible/module_utils/facts/virtual/linux.py +2 -2
- ansible/module_utils/service.py +3 -10
- ansible/module_utils/urls.py +4 -4
- ansible/modules/apt_repository.py +17 -39
- ansible/modules/assemble.py +2 -2
- ansible/modules/async_status.py +13 -11
- ansible/modules/async_wrapper.py +12 -22
- ansible/modules/command.py +3 -3
- ansible/modules/copy.py +4 -4
- ansible/modules/cron.py +1 -1
- ansible/modules/dnf5.py +14 -22
- ansible/modules/file.py +16 -17
- ansible/modules/find.py +3 -3
- ansible/modules/get_url.py +17 -0
- ansible/modules/git.py +9 -7
- ansible/modules/hostname.py +0 -1
- ansible/modules/known_hosts.py +12 -14
- ansible/modules/package.py +6 -0
- ansible/modules/replace.py +2 -2
- ansible/modules/service.py +3 -9
- ansible/modules/slurp.py +10 -13
- ansible/modules/stat.py +5 -7
- ansible/modules/unarchive.py +6 -6
- ansible/modules/user.py +1 -1
- ansible/modules/wait_for.py +28 -30
- ansible/modules/yum_repository.py +4 -3
- ansible/parsing/ajson.py +3 -5
- ansible/parsing/dataloader.py +6 -6
- ansible/parsing/mod_args.py +1 -1
- ansible/parsing/plugin_docs.py +2 -2
- ansible/parsing/utils/yaml.py +3 -3
- ansible/parsing/vault/__init__.py +10 -14
- ansible/playbook/base.py +7 -2
- ansible/playbook/included_file.py +3 -1
- ansible/playbook/play_context.py +2 -0
- ansible/playbook/playbook_include.py +1 -1
- ansible/playbook/taggable.py +19 -8
- ansible/playbook/task.py +2 -0
- ansible/plugins/__init__.py +0 -25
- ansible/plugins/action/__init__.py +8 -31
- ansible/plugins/action/add_host.py +1 -1
- ansible/plugins/action/assemble.py +8 -16
- ansible/plugins/action/async_status.py +7 -2
- ansible/plugins/action/copy.py +8 -7
- ansible/plugins/action/fetch.py +3 -3
- ansible/plugins/action/gather_facts.py +8 -8
- ansible/plugins/action/package.py +5 -8
- ansible/plugins/action/script.py +8 -15
- ansible/plugins/action/service.py +3 -7
- ansible/plugins/action/template.py +11 -10
- ansible/plugins/action/unarchive.py +5 -15
- ansible/plugins/action/uri.py +9 -20
- ansible/plugins/cache/__init__.py +17 -19
- ansible/plugins/callback/__init__.py +4 -6
- ansible/plugins/callback/junit.py +4 -2
- ansible/plugins/callback/tree.py +5 -5
- ansible/plugins/connection/local.py +6 -6
- ansible/plugins/connection/paramiko_ssh.py +5 -5
- ansible/plugins/connection/ssh.py +25 -15
- ansible/plugins/connection/winrm.py +6 -3
- ansible/plugins/doc_fragments/constructed.py +2 -2
- ansible/plugins/filter/core.py +32 -27
- ansible/plugins/filter/encryption.py +14 -6
- ansible/plugins/inventory/__init__.py +11 -10
- ansible/plugins/inventory/script.py +1 -1
- ansible/plugins/list.py +73 -19
- ansible/plugins/loader.py +7 -7
- ansible/plugins/lookup/csvfile.py +16 -71
- ansible/plugins/lookup/first_found.py +2 -1
- ansible/plugins/lookup/template.py +9 -4
- ansible/plugins/shell/__init__.py +56 -2
- ansible/plugins/shell/powershell.py +67 -9
- ansible/plugins/shell/sh.py +10 -5
- ansible/plugins/strategy/__init__.py +3 -3
- ansible/plugins/test/core.py +22 -16
- ansible/plugins/test/finished.yml +1 -1
- ansible/plugins/test/uri.py +2 -5
- ansible/release.py +1 -1
- ansible/template/__init__.py +38 -54
- ansible/utils/collection_loader/_collection_finder.py +3 -3
- ansible/utils/display.py +124 -138
- ansible/utils/galaxy.py +2 -2
- ansible/utils/hashing.py +6 -8
- ansible/utils/listify.py +6 -4
- ansible/utils/path.py +5 -7
- ansible/utils/py3compat.py +2 -1
- ansible/utils/ssh_functions.py +3 -2
- ansible/utils/unsafe_proxy.py +1 -1
- ansible/vars/hostvars.py +1 -1
- ansible/vars/plugins.py +3 -3
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/METADATA +1 -1
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/RECORD +224 -204
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/WHEEL +1 -1
- ansible_test/_data/completion/docker.txt +3 -3
- ansible_test/_data/completion/remote.txt +1 -0
- ansible_test/_data/requirements/sanity.ansible-doc.txt +1 -1
- ansible_test/_data/requirements/sanity.changelog.txt +2 -2
- ansible_test/_data/requirements/sanity.pep8.txt +1 -1
- ansible_test/_data/requirements/sanity.pylint.txt +4 -4
- ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
- ansible_test/_internal/commands/integration/coverage.py +7 -2
- ansible_test/_internal/host_profiles.py +62 -10
- ansible_test/_internal/provisioning.py +10 -4
- ansible_test/_internal/ssh.py +1 -5
- ansible_test/_internal/thread.py +2 -1
- ansible_test/_internal/timeout.py +1 -1
- ansible_test/_internal/util.py +40 -12
- ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +1 -0
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +1 -0
- ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +1 -0
- ansible_test/_util/controller/sanity/pylint/config/collection.cfg +1 -0
- ansible_test/_util/controller/sanity/pylint/config/default.cfg +1 -0
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +61 -7
- ansible_test/_util/target/setup/bootstrap.sh +31 -0
- ansible_test/_util/target/setup/requirements.py +3 -9
- ansible/_internal/_errors/_utils.py +0 -310
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/top_level.txt +0 -0
@@ -16,10 +16,9 @@ import typing as t
|
|
16
16
|
|
17
17
|
import yaml
|
18
18
|
|
19
|
-
from jinja2 import __version__ as j2_version
|
20
|
-
|
21
19
|
import ansible
|
22
20
|
from ansible import constants as C
|
21
|
+
from ansible._internal import _templating
|
23
22
|
from ansible.module_utils.common.text.converters import to_native
|
24
23
|
from ansible.module_utils.common.yaml import HAS_LIBYAML, yaml_load
|
25
24
|
from ansible.release import __version__
|
@@ -244,7 +243,7 @@ def _git_repo_info(repo_path):
|
|
244
243
|
repo_path = gitdir
|
245
244
|
else:
|
246
245
|
repo_path = os.path.join(repo_path[:-4], gitdir)
|
247
|
-
except (
|
246
|
+
except (OSError, AttributeError):
|
248
247
|
return ''
|
249
248
|
with open(os.path.join(repo_path, "HEAD")) as f:
|
250
249
|
line = f.readline().rstrip("\n")
|
@@ -313,7 +312,7 @@ def version(prog=None):
|
|
313
312
|
result.append(" ansible collection location = %s" % ':'.join(C.COLLECTIONS_PATHS))
|
314
313
|
result.append(" executable location = %s" % sys.argv[0])
|
315
314
|
result.append(" python version = %s (%s)" % (''.join(sys.version.splitlines()), to_native(sys.executable)))
|
316
|
-
result.append(" jinja version =
|
315
|
+
result.append(f" jinja version = {_templating.jinja2_version}")
|
317
316
|
result.append(f" pyyaml version = {yaml.__version__} ({libyaml_fragment})")
|
318
317
|
|
319
318
|
return "\n".join(result)
|
ansible/cli/console.py
CHANGED
@@ -573,7 +573,7 @@ class ConsoleCLI(CLI, cmd.Cmd):
|
|
573
573
|
histfile = os.path.join(os.path.expanduser("~"), ".ansible-console_history")
|
574
574
|
try:
|
575
575
|
readline.read_history_file(histfile)
|
576
|
-
except
|
576
|
+
except OSError:
|
577
577
|
pass
|
578
578
|
|
579
579
|
atexit.register(readline.write_history_file, histfile)
|
ansible/cli/doc.py
CHANGED
@@ -9,12 +9,14 @@ from __future__ import annotations
|
|
9
9
|
# ansible.cli needs to be imported first, to ensure the source bin/* scripts run that code first
|
10
10
|
from ansible.cli import CLI
|
11
11
|
|
12
|
+
import collections.abc
|
12
13
|
import importlib
|
13
14
|
import pkgutil
|
14
15
|
import os
|
15
16
|
import os.path
|
16
17
|
import re
|
17
18
|
import textwrap
|
19
|
+
import typing as t
|
18
20
|
|
19
21
|
import yaml
|
20
22
|
|
@@ -35,7 +37,7 @@ from ansible.parsing.plugin_docs import read_docstub
|
|
35
37
|
from ansible.parsing.yaml.dumper import AnsibleDumper
|
36
38
|
from ansible.parsing.yaml.loader import AnsibleLoader
|
37
39
|
from ansible._internal._yaml._loader import AnsibleInstrumentedLoader
|
38
|
-
from ansible.plugins.list import
|
40
|
+
from ansible.plugins.list import _list_plugins_with_info, _PluginDocMetadata
|
39
41
|
from ansible.plugins.loader import action_loader, fragment_loader
|
40
42
|
from ansible.utils.collection_loader import AnsibleCollectionConfig, AnsibleCollectionRef
|
41
43
|
from ansible.utils.collection_loader._collection_finder import _get_collection_name_from_path
|
@@ -44,6 +46,7 @@ from ansible.utils.display import Display
|
|
44
46
|
from ansible.utils.plugin_docs import get_plugin_docs, get_docstring, get_versioned_doclink
|
45
47
|
from ansible.template import trust_as_template
|
46
48
|
from ansible._internal import _json
|
49
|
+
from ansible._internal._templating import _jinja_plugins
|
47
50
|
|
48
51
|
display = Display()
|
49
52
|
|
@@ -134,8 +137,8 @@ class RoleMixin(object):
|
|
134
137
|
data = yaml.load(trust_as_template(f), Loader=AnsibleLoader)
|
135
138
|
if data is None:
|
136
139
|
data = {}
|
137
|
-
except
|
138
|
-
raise AnsibleParserError(f"Could not read the role {role_name!r}
|
140
|
+
except OSError as ex:
|
141
|
+
raise AnsibleParserError(f"Could not read the role {role_name!r} at {path!r}.") from ex
|
139
142
|
|
140
143
|
return data
|
141
144
|
|
@@ -788,35 +791,47 @@ class DocCLI(CLI, RoleMixin):
|
|
788
791
|
return coll_filter
|
789
792
|
|
790
793
|
def _list_plugins(self, plugin_type, content):
|
791
|
-
|
792
|
-
results = {}
|
793
|
-
self.plugins = {}
|
794
|
-
loader = DocCLI._prep_loader(plugin_type)
|
794
|
+
DocCLI._prep_loader(plugin_type)
|
795
795
|
|
796
796
|
coll_filter = self._get_collection_filter()
|
797
|
-
|
797
|
+
plugins = _list_plugins_with_info(plugin_type, coll_filter)
|
798
|
+
|
799
|
+
# Remove the internal ansible._protomatter plugins if getting all plugins
|
800
|
+
if not coll_filter:
|
801
|
+
plugins = {k: v for k, v in plugins.items() if not k.startswith('ansible._protomatter.')}
|
798
802
|
|
799
803
|
# get appropriate content depending on option
|
800
804
|
if content == 'dir':
|
801
|
-
results = self._get_plugin_list_descriptions(
|
805
|
+
results = self._get_plugin_list_descriptions(plugins)
|
802
806
|
elif content == 'files':
|
803
|
-
results = {k:
|
807
|
+
results = {k: v.path for k, v in plugins.items()}
|
804
808
|
else:
|
805
|
-
results = {k: {} for k in
|
809
|
+
results = {k: {} for k in plugins.keys()}
|
806
810
|
self.plugin_list = set() # reset for next iteration
|
807
811
|
|
808
812
|
return results
|
809
813
|
|
810
|
-
def _get_plugins_docs(self, plugin_type, names, fail_ok=False, fail_on_errors=True):
|
811
|
-
|
814
|
+
def _get_plugins_docs(self, plugin_type: str, names: collections.abc.Iterable[str], fail_ok: bool = False, fail_on_errors: bool = True) -> dict[str, dict]:
|
812
815
|
loader = DocCLI._prep_loader(plugin_type)
|
813
816
|
|
817
|
+
if plugin_type in ('filter', 'test'):
|
818
|
+
jinja2_builtins = _jinja_plugins.get_jinja_builtin_plugin_descriptions(plugin_type)
|
819
|
+
jinja2_builtins.update({name.split('.')[-1]: value for name, value in jinja2_builtins.items()}) # add short-named versions for lookup
|
820
|
+
else:
|
821
|
+
jinja2_builtins = {}
|
822
|
+
|
814
823
|
# get the docs for plugins in the command line list
|
815
824
|
plugin_docs = {}
|
816
825
|
for plugin in names:
|
817
|
-
doc = {}
|
826
|
+
doc: dict[str, t.Any] = {}
|
818
827
|
try:
|
819
|
-
doc, plainexamples, returndocs, metadata =
|
828
|
+
doc, plainexamples, returndocs, metadata = self._get_plugin_docs_with_jinja2_builtins(
|
829
|
+
plugin,
|
830
|
+
plugin_type,
|
831
|
+
loader,
|
832
|
+
fragment_loader,
|
833
|
+
jinja2_builtins,
|
834
|
+
)
|
820
835
|
except AnsiblePluginNotFound as e:
|
821
836
|
display.warning(to_native(e))
|
822
837
|
continue
|
@@ -853,6 +868,39 @@ class DocCLI(CLI, RoleMixin):
|
|
853
868
|
|
854
869
|
return plugin_docs
|
855
870
|
|
871
|
+
def _get_plugin_docs_with_jinja2_builtins(
|
872
|
+
self,
|
873
|
+
plugin_name: str,
|
874
|
+
plugin_type: str,
|
875
|
+
loader: t.Any,
|
876
|
+
fragment_loader: t.Any,
|
877
|
+
jinja_builtins: dict[str, str],
|
878
|
+
) -> tuple[dict, str | None, dict | None, dict | None]:
|
879
|
+
try:
|
880
|
+
return get_plugin_docs(plugin_name, plugin_type, loader, fragment_loader, (context.CLIARGS['verbosity'] > 0))
|
881
|
+
except Exception:
|
882
|
+
if (desc := jinja_builtins.get(plugin_name, ...)) is not ...:
|
883
|
+
short_name = plugin_name.split('.')[-1]
|
884
|
+
long_name = f'ansible.builtin.{short_name}'
|
885
|
+
# Dynamically build a doc stub for any Jinja2 builtin plugin we haven't
|
886
|
+
# explicitly documented.
|
887
|
+
doc = dict(
|
888
|
+
collection='ansible.builtin',
|
889
|
+
plugin_name=long_name,
|
890
|
+
filename='',
|
891
|
+
short_description=desc,
|
892
|
+
description=[
|
893
|
+
desc,
|
894
|
+
'',
|
895
|
+
f"This is the Jinja builtin {plugin_type} plugin {short_name!r}.",
|
896
|
+
f"See: U(https://jinja.palletsprojects.com/en/stable/templates/#jinja-{plugin_type}s.{short_name})",
|
897
|
+
],
|
898
|
+
)
|
899
|
+
|
900
|
+
return doc, None, None, None
|
901
|
+
|
902
|
+
raise
|
903
|
+
|
856
904
|
def _get_roles_path(self):
|
857
905
|
"""
|
858
906
|
Add any 'roles' subdir in playbook dir to the roles search path.
|
@@ -1001,10 +1049,10 @@ class DocCLI(CLI, RoleMixin):
|
|
1001
1049
|
def get_all_plugins_of_type(plugin_type):
|
1002
1050
|
loader = getattr(plugin_loader, '%s_loader' % plugin_type)
|
1003
1051
|
paths = loader._get_paths_with_context()
|
1004
|
-
plugins =
|
1052
|
+
plugins = []
|
1005
1053
|
for path_context in paths:
|
1006
|
-
plugins
|
1007
|
-
return sorted(plugins
|
1054
|
+
plugins += _list_plugins_with_info(plugin_type).keys()
|
1055
|
+
return sorted(plugins)
|
1008
1056
|
|
1009
1057
|
@staticmethod
|
1010
1058
|
def get_plugin_metadata(plugin_type, plugin_name):
|
@@ -1101,18 +1149,20 @@ class DocCLI(CLI, RoleMixin):
|
|
1101
1149
|
|
1102
1150
|
return text
|
1103
1151
|
|
1104
|
-
def _get_plugin_list_descriptions(self,
|
1152
|
+
def _get_plugin_list_descriptions(self, plugins: dict[str, _PluginDocMetadata]) -> dict[str, str]:
|
1105
1153
|
|
1106
1154
|
descs = {}
|
1107
|
-
for plugin in
|
1155
|
+
for plugin, plugin_info in plugins.items():
|
1108
1156
|
# TODO: move to plugin itself i.e: plugin.get_desc()
|
1109
1157
|
doc = None
|
1110
|
-
|
1158
|
+
|
1111
1159
|
docerror = None
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1160
|
+
if plugin_info.path:
|
1161
|
+
filename = Path(to_native(plugin_info.path))
|
1162
|
+
try:
|
1163
|
+
doc = read_docstub(filename)
|
1164
|
+
except Exception as e:
|
1165
|
+
docerror = e
|
1116
1166
|
|
1117
1167
|
# plugin file was empty or had error, lets try other options
|
1118
1168
|
if doc is None:
|
@@ -1127,9 +1177,15 @@ class DocCLI(CLI, RoleMixin):
|
|
1127
1177
|
except Exception as e:
|
1128
1178
|
docerror = e
|
1129
1179
|
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1180
|
+
# Do a final fallback to see if the plugin is a shadowed Jinja2 plugin
|
1181
|
+
# without any explicit documentation.
|
1182
|
+
if doc is None and plugin_info.jinja_builtin_short_description:
|
1183
|
+
descs[plugin] = plugin_info.jinja_builtin_short_description
|
1184
|
+
continue
|
1185
|
+
|
1186
|
+
if docerror:
|
1187
|
+
display.error_as_warning(f"{plugin} has a documentation formatting error.", exception=docerror)
|
1188
|
+
continue
|
1133
1189
|
|
1134
1190
|
if not doc or not isinstance(doc, dict):
|
1135
1191
|
desc = 'UNDOCUMENTED'
|
@@ -1368,7 +1424,7 @@ class DocCLI(CLI, RoleMixin):
|
|
1368
1424
|
try:
|
1369
1425
|
text.append(yaml_dump(doc.pop('examples'), indent=2, default_flow_style=False))
|
1370
1426
|
except Exception as e:
|
1371
|
-
raise AnsibleParserError("Unable to parse examples section"
|
1427
|
+
raise AnsibleParserError("Unable to parse examples section.") from e
|
1372
1428
|
|
1373
1429
|
return text
|
1374
1430
|
|
@@ -1406,7 +1462,7 @@ class DocCLI(CLI, RoleMixin):
|
|
1406
1462
|
try:
|
1407
1463
|
text.append('\t' + C.config.get_deprecated_msg_from_config(doc['deprecated'], True, collection_name=collection_name))
|
1408
1464
|
except KeyError as e:
|
1409
|
-
raise AnsibleError("Invalid deprecation documentation structure"
|
1465
|
+
raise AnsibleError("Invalid deprecation documentation structure.") from e
|
1410
1466
|
else:
|
1411
1467
|
text.append("%s" % doc['deprecated'])
|
1412
1468
|
del doc['deprecated']
|
ansible/cli/inventory.py
CHANGED
@@ -14,13 +14,12 @@ import sys
|
|
14
14
|
import typing as t
|
15
15
|
|
16
16
|
import argparse
|
17
|
-
import functools
|
18
17
|
|
19
18
|
from ansible import constants as C
|
20
19
|
from ansible import context
|
21
20
|
from ansible.cli.arguments import option_helpers as opt_help
|
22
21
|
from ansible.errors import AnsibleError, AnsibleOptionsError, AnsibleRuntimeError
|
23
|
-
from ansible.module_utils.common.text.converters import to_bytes,
|
22
|
+
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
24
23
|
from ansible._internal._json._profiles import _inventory_legacy
|
25
24
|
from ansible.utils.vars import combine_vars
|
26
25
|
from ansible.utils.display import Display
|
@@ -152,8 +151,8 @@ class InventoryCLI(CLI):
|
|
152
151
|
try:
|
153
152
|
with open(to_bytes(outfile), 'wb') as f:
|
154
153
|
f.write(to_bytes(results))
|
155
|
-
except
|
156
|
-
raise AnsibleError('Unable to write to destination file
|
154
|
+
except OSError as ex:
|
155
|
+
raise AnsibleError(f'Unable to write to destination file {outfile!r}.') from ex
|
157
156
|
sys.exit(0)
|
158
157
|
|
159
158
|
sys.exit(1)
|
@@ -162,11 +161,10 @@ class InventoryCLI(CLI):
|
|
162
161
|
def dump(stuff):
|
163
162
|
if context.CLIARGS['yaml']:
|
164
163
|
import yaml
|
164
|
+
|
165
165
|
from ansible.parsing.yaml.dumper import AnsibleDumper
|
166
166
|
|
167
|
-
|
168
|
-
dumper = functools.partial(AnsibleDumper, dump_vault_tags=True)
|
169
|
-
results = to_text(yaml.dump(stuff, Dumper=dumper, default_flow_style=False, allow_unicode=True))
|
167
|
+
results = to_text(yaml.dump(stuff, Dumper=AnsibleDumper, default_flow_style=False, allow_unicode=True))
|
170
168
|
elif context.CLIARGS['toml']:
|
171
169
|
results = toml_dumps(stuff)
|
172
170
|
else:
|
@@ -3,17 +3,14 @@
|
|
3
3
|
|
4
4
|
from __future__ import annotations
|
5
5
|
|
6
|
-
import
|
6
|
+
from ansible.utils.display import Display as _Display
|
7
7
|
|
8
|
-
|
8
|
+
from importlib.resources import files # pylint: disable=unused-import
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
else:
|
18
|
-
from importlib.resources import files
|
19
|
-
HAS_IMPORTLIB_RESOURCES = True
|
10
|
+
HAS_IMPORTLIB_RESOURCES = True
|
11
|
+
|
12
|
+
_Display().deprecated(
|
13
|
+
msg="The `ansible.compat.importlib_resources` module is deprecated.",
|
14
|
+
help_text="Use `importlib.resources` from the Python standard library instead.",
|
15
|
+
version="2.23",
|
16
|
+
)
|
ansible/config/base.yml
CHANGED
@@ -1,6 +1,26 @@
|
|
1
1
|
# Copyright (c) 2017 Ansible Project
|
2
2
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
3
3
|
---
|
4
|
+
_ANSIBALLZ_COVERAGE_CONFIG:
|
5
|
+
name: Configure the AnsiballZ code coverage extension
|
6
|
+
description:
|
7
|
+
- Enables and configures the AnsiballZ code coverage extension.
|
8
|
+
- This is for internal use only.
|
9
|
+
env:
|
10
|
+
- {name: _ANSIBLE_ANSIBALLZ_COVERAGE_CONFIG}
|
11
|
+
vars:
|
12
|
+
- {name: _ansible_ansiballz_coverage_config}
|
13
|
+
version_added: '2.19'
|
14
|
+
_ANSIBALLZ_DEBUGGER_CONFIG:
|
15
|
+
name: Configure the AnsiballZ remote debugging extension
|
16
|
+
description:
|
17
|
+
- Enables and configures the AnsiballZ remote debugging extension.
|
18
|
+
- This is for internal use only.
|
19
|
+
env:
|
20
|
+
- {name: _ANSIBLE_ANSIBALLZ_DEBUGGER_CONFIG}
|
21
|
+
vars:
|
22
|
+
- {name: _ansible_ansiballz_debugger_config}
|
23
|
+
version_added: '2.19'
|
4
24
|
_ANSIBLE_CONNECTION_PATH:
|
5
25
|
env:
|
6
26
|
- name: _ANSIBLE_CONNECTION_PATH
|
@@ -906,6 +926,10 @@ DEFAULT_MANAGED_STR:
|
|
906
926
|
ini:
|
907
927
|
- {key: ansible_managed, section: defaults}
|
908
928
|
yaml: {key: defaults.ansible_managed}
|
929
|
+
deprecated:
|
930
|
+
why: The `ansible_managed` variable can be set just like any other variable, or a different variable can be used.
|
931
|
+
version: "2.23"
|
932
|
+
alternatives: Set the `ansible_managed` variable, or use any custom variable in templates.
|
909
933
|
DEFAULT_MODULE_ARGS:
|
910
934
|
name: Adhoc default arguments
|
911
935
|
default: ~
|
@@ -1335,6 +1359,7 @@ DISPLAY_TRACEBACK:
|
|
1335
1359
|
- error
|
1336
1360
|
- warning
|
1337
1361
|
- deprecated
|
1362
|
+
- deprecated_value
|
1338
1363
|
- always
|
1339
1364
|
- never
|
1340
1365
|
version_added: "2.19"
|
@@ -1961,6 +1986,14 @@ SSH_AGENT:
|
|
1961
1986
|
env: [{name: ANSIBLE_SSH_AGENT}]
|
1962
1987
|
ini: [{key: ssh_agent, section: connection}]
|
1963
1988
|
version_added: '2.19'
|
1989
|
+
SSH_AGENT_EXECUTABLE:
|
1990
|
+
name: Executable to start for the ansible-managed SSH agent
|
1991
|
+
description: When ``SSH_AGENT`` is ``auto``, the path or name of the ssh agent executable to start.
|
1992
|
+
default: ssh-agent
|
1993
|
+
type: str
|
1994
|
+
env: [ { name: ANSIBLE_SSH_AGENT_EXECUTABLE } ]
|
1995
|
+
ini: [ { key: ssh_agent_executable, section: connection } ]
|
1996
|
+
version_added: '2.19'
|
1964
1997
|
SSH_AGENT_KEY_LIFETIME:
|
1965
1998
|
name: Set a maximum lifetime when adding identities to an agent
|
1966
1999
|
description: For keys inserted into an agent defined by ``SSH_AGENT``, define a lifetime, in seconds, that the key may remain
|
@@ -2035,6 +2068,19 @@ TASK_TIMEOUT:
|
|
2035
2068
|
- {key: task_timeout, section: defaults}
|
2036
2069
|
type: integer
|
2037
2070
|
version_added: '2.10'
|
2071
|
+
_TEMPLAR_SANDBOX_MODE:
|
2072
|
+
name: Control Jinja template sandbox behavior
|
2073
|
+
default: default
|
2074
|
+
description:
|
2075
|
+
- The default Jinja sandbox behavior blocks template access to all `_` prefixed object attributes and known collection mutation methods (e.g., `dict.clear()`, `list.append()`).
|
2076
|
+
type: choices
|
2077
|
+
choices:
|
2078
|
+
- default
|
2079
|
+
- allow_unsafe_attributes
|
2080
|
+
env: [{name: _ANSIBLE_TEMPLAR_SANDBOX_MODE}]
|
2081
|
+
deprecated:
|
2082
|
+
why: controlling sandbox behavior is a temporary workaround
|
2083
|
+
version: '2.23'
|
2038
2084
|
_TEMPLAR_UNKNOWN_TYPE_CONVERSION:
|
2039
2085
|
name: Templar unknown type conversion behavior
|
2040
2086
|
default: warning
|
ansible/errors/__init__.py
CHANGED
@@ -3,20 +3,18 @@
|
|
3
3
|
|
4
4
|
from __future__ import annotations
|
5
5
|
|
6
|
+
import collections.abc as _c
|
6
7
|
import enum
|
7
|
-
import traceback
|
8
|
-
import sys
|
9
8
|
import types
|
10
9
|
import typing as t
|
11
10
|
|
12
|
-
from collections.abc import Sequence
|
13
|
-
|
14
11
|
from json import JSONDecodeError
|
15
12
|
|
16
13
|
from ansible.module_utils.common.text.converters import to_text
|
17
14
|
from ..module_utils.datatag import native_type_name
|
18
15
|
from ansible._internal._datatag import _tags
|
19
|
-
from .._internal._errors import
|
16
|
+
from .._internal._errors import _error_utils
|
17
|
+
from ansible.module_utils._internal import _text_utils
|
20
18
|
|
21
19
|
if t.TYPE_CHECKING:
|
22
20
|
from ansible.plugins import loader as _t_loader
|
@@ -73,7 +71,7 @@ class AnsibleError(Exception):
|
|
73
71
|
message = str(message)
|
74
72
|
|
75
73
|
if self._default_message and message:
|
76
|
-
message =
|
74
|
+
message = _text_utils.concat_message(self._default_message, message)
|
77
75
|
elif self._default_message:
|
78
76
|
message = self._default_message
|
79
77
|
elif not message:
|
@@ -97,8 +95,9 @@ class AnsibleError(Exception):
|
|
97
95
|
self._show_content = False
|
98
96
|
|
99
97
|
Display().deprecated(
|
100
|
-
msg=f"The `suppress_extended_error` argument to `{type(self).__name__}` is deprecated.
|
98
|
+
msg=f"The `suppress_extended_error` argument to `{type(self).__name__}` is deprecated.",
|
101
99
|
version="2.23",
|
100
|
+
help_text="Use `show_content=False` instead.",
|
102
101
|
)
|
103
102
|
|
104
103
|
@property
|
@@ -108,12 +107,10 @@ class AnsibleError(Exception):
|
|
108
107
|
@property
|
109
108
|
def message(self) -> str:
|
110
109
|
"""
|
111
|
-
|
112
|
-
|
113
|
-
The recursion is due to `AnsibleError.__str__` calling this method, which uses `str` on child exceptions to create the cause message.
|
114
|
-
Recursion stops on the first non-AnsibleError since those exceptions do not implement the custom `__str__` behavior.
|
110
|
+
Return the original message with cause message(s) appended.
|
111
|
+
The cause will not be followed on any `AnsibleError` with `_include_cause_message=False`.
|
115
112
|
"""
|
116
|
-
return
|
113
|
+
return _error_utils.format_exception_message(self)
|
117
114
|
|
118
115
|
@message.setter
|
119
116
|
def message(self, val) -> None:
|
@@ -121,8 +118,8 @@ class AnsibleError(Exception):
|
|
121
118
|
|
122
119
|
@property
|
123
120
|
def _formatted_source_context(self) -> str | None:
|
124
|
-
with
|
125
|
-
if source_context :=
|
121
|
+
with _error_utils.RedactAnnotatedSourceContext.when(not self._show_content):
|
122
|
+
if source_context := _error_utils.SourceContext.from_value(self.obj):
|
126
123
|
return str(source_context)
|
127
124
|
|
128
125
|
return None
|
@@ -238,8 +235,20 @@ class AnsibleModuleError(AnsibleRuntimeError):
|
|
238
235
|
"""A module failed somehow."""
|
239
236
|
|
240
237
|
|
241
|
-
class AnsibleConnectionFailure(AnsibleRuntimeError):
|
242
|
-
"""
|
238
|
+
class AnsibleConnectionFailure(AnsibleRuntimeError, _error_utils.ContributesToTaskResult):
|
239
|
+
"""
|
240
|
+
The transport / connection_plugin had a fatal error.
|
241
|
+
|
242
|
+
This exception provides a result dictionary via the ContributesToTaskResult mixin.
|
243
|
+
"""
|
244
|
+
|
245
|
+
@property
|
246
|
+
def result_contribution(self) -> t.Mapping[str, object]:
|
247
|
+
return dict(unreachable=True)
|
248
|
+
|
249
|
+
@property
|
250
|
+
def omit_failed_key(self) -> bool:
|
251
|
+
return True
|
243
252
|
|
244
253
|
|
245
254
|
class AnsibleAuthenticationFailure(AnsibleConnectionFailure):
|
@@ -319,7 +328,7 @@ class AnsibleFileNotFound(AnsibleRuntimeError):
|
|
319
328
|
else:
|
320
329
|
message += "Could not find file"
|
321
330
|
|
322
|
-
if self.paths and isinstance(self.paths, Sequence):
|
331
|
+
if self.paths and isinstance(self.paths, _c.Sequence):
|
323
332
|
searched = to_text('\n\t'.join(self.paths))
|
324
333
|
if message:
|
325
334
|
message += "\n"
|
@@ -331,47 +340,76 @@ class AnsibleFileNotFound(AnsibleRuntimeError):
|
|
331
340
|
suppress_extended_error=suppress_extended_error, orig_exc=orig_exc)
|
332
341
|
|
333
342
|
|
334
|
-
|
335
|
-
# DO NOT USE as they will probably be removed soon.
|
336
|
-
# We will port the action modules in our tree to use a context manager instead.
|
337
|
-
class AnsibleAction(AnsibleRuntimeError):
|
343
|
+
class AnsibleAction(AnsibleRuntimeError, _error_utils.ContributesToTaskResult):
|
338
344
|
"""Base Exception for Action plugin flow control."""
|
339
345
|
|
340
346
|
def __init__(self, message="", obj=None, show_content=True, suppress_extended_error=..., orig_exc=None, result=None):
|
341
|
-
super(
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
+
super().__init__(message=message, obj=obj, show_content=show_content, suppress_extended_error=suppress_extended_error, orig_exc=orig_exc)
|
348
|
+
|
349
|
+
self._result = result or {}
|
350
|
+
|
351
|
+
@property
|
352
|
+
def result_contribution(self) -> _c.Mapping[str, object]:
|
353
|
+
return self._result
|
354
|
+
|
355
|
+
@property
|
356
|
+
def result(self) -> dict[str, object]:
|
357
|
+
"""Backward compatibility property returning a mutable dictionary."""
|
358
|
+
return dict(self.result_contribution)
|
347
359
|
|
348
360
|
|
349
361
|
class AnsibleActionSkip(AnsibleAction):
|
350
|
-
"""
|
362
|
+
"""
|
363
|
+
An action runtime skip.
|
351
364
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
365
|
+
This exception provides a result dictionary via the ContributesToTaskResult mixin.
|
366
|
+
"""
|
367
|
+
|
368
|
+
@property
|
369
|
+
def result_contribution(self) -> _c.Mapping[str, object]:
|
370
|
+
return self._result | dict(
|
371
|
+
skipped=True,
|
372
|
+
msg=self.message,
|
373
|
+
)
|
374
|
+
|
375
|
+
@property
|
376
|
+
def omit_failed_key(self) -> bool:
|
377
|
+
return True
|
378
|
+
|
379
|
+
@property
|
380
|
+
def omit_exception_key(self) -> bool:
|
381
|
+
return True
|
356
382
|
|
357
383
|
|
358
384
|
class AnsibleActionFail(AnsibleAction):
|
359
|
-
"""
|
385
|
+
"""
|
386
|
+
An action runtime failure.
|
360
387
|
|
361
|
-
|
362
|
-
|
363
|
-
|
388
|
+
This exception provides a result dictionary via the ContributesToTaskResult mixin.
|
389
|
+
"""
|
390
|
+
|
391
|
+
@property
|
392
|
+
def result_contribution(self) -> _c.Mapping[str, object]:
|
393
|
+
return self._result | dict(
|
394
|
+
failed=True,
|
395
|
+
msg=self.message,
|
396
|
+
)
|
364
397
|
|
365
|
-
result_overrides = {'failed': True, 'msg': message}
|
366
|
-
# deprecated: description='use sys.exception()' python_version='3.11'
|
367
|
-
if sys.exc_info()[1]: # DTFIX-RELEASE: remove this hack once TaskExecutor is no longer shucking AnsibleActionFail and returning its result
|
368
|
-
result_overrides['exception'] = traceback.format_exc()
|
369
398
|
|
370
|
-
|
399
|
+
class _ActionDone(AnsibleAction):
|
400
|
+
"""
|
401
|
+
Imports as `_AnsibleActionDone` are deprecated. An action runtime early exit.
|
402
|
+
|
403
|
+
This exception provides a result dictionary via the ContributesToTaskResult mixin.
|
404
|
+
"""
|
371
405
|
|
406
|
+
@property
|
407
|
+
def omit_failed_key(self) -> bool:
|
408
|
+
return not self._result.get('failed')
|
372
409
|
|
373
|
-
|
374
|
-
|
410
|
+
@property
|
411
|
+
def omit_exception_key(self) -> bool:
|
412
|
+
return not self._result.get('failed')
|
375
413
|
|
376
414
|
|
377
415
|
class AnsiblePluginError(AnsibleError):
|
@@ -422,13 +460,23 @@ def __getattr__(name: str) -> t.Any:
|
|
422
460
|
"""Inject import-time deprecation warnings."""
|
423
461
|
from ..utils.display import Display
|
424
462
|
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
463
|
+
match name:
|
464
|
+
case 'AnsibleFilterTypeError':
|
465
|
+
Display().deprecated(
|
466
|
+
msg=f"Importing {name!r} is deprecated.",
|
467
|
+
help_text=f"Import {AnsibleTypeError.__name__!r} instead.",
|
468
|
+
version="2.23",
|
469
|
+
)
|
470
|
+
|
471
|
+
return AnsibleTypeError
|
472
|
+
|
473
|
+
case '_AnsibleActionDone':
|
474
|
+
Display().deprecated(
|
475
|
+
msg=f"Importing {name!r} is deprecated.",
|
476
|
+
help_text="Return directly from action plugins instead.",
|
477
|
+
version="2.23",
|
478
|
+
)
|
431
479
|
|
432
|
-
|
480
|
+
return _ActionDone
|
433
481
|
|
434
482
|
raise AttributeError(f'module {__name__!r} has no attribute {name!r}')
|